Reputation: 2098
I've hacked together a script that lists all AD computer objects and enriches with some other information: Namely, is the machine pingable and what are the members of its local admin group. Each of these data elements are retrieved in an independent pipeline function.
For reasons unknown, the array of objects I'm pipelining is being truncated. Instead of the 883 computers returned from the GetAdComputer cmdlet, I'm left with only ~230 computers in the final CSV.
I've narrowed down the problem to the command that retrieves local admins via PS remoting. I'm sure there are machines for which this command fails so it's likely an exception is being thrown at some point. I assume such an exception may terminate the loop and lop off array items? I tried wrapping the Invoke-Command in a try/catch but that didn't resolve the issue. Still missing array items.
I'm sure this is a noob oversight. I don't use PS often enough to keep the language semantics straight. Any help is appreciated.
Import-Module active*
$now=(Get-Date).ToString("yyyyMMddTHHmmss")
Get-ADComputer -Filter 'Name -like "prod-idfi*"' -Properties LastLogonDate, Description |select LastLogonDate,DNSHostName,DistinguishedName,Description |foreach{
$alive = Test-Connection -CN $_.DNSHostName -Count 1 -BufferSize 16 -Quiet
return [PSCustomObject]@{
PSTypeName = "Computer"
Id=$null
Name = $_.DNSHostName
IsAlive = If($alive) {1} Else {0}
DistinguishedName = $_.DistinguishedName
Description = $_.Description
LastLogonDate = $_.LastLogonDate
LocalAdmins=''
}
}|foreach{
$computer = $_
if ($computer.IsAlive){
try{
$localAdmins = Invoke-Command -ComputerName $_.Name {([ADSI]"WinNT://./Administrators").psbase.Invoke('Members') | % { ([ADSI]$_).InvokeGet('AdsPath')}}
$computer.LocalAdmins= "$($localAdmins -join ",")"
}
catch {
Write-Host ("something bad happened")
}
}
$computer
} |Export-Csv ".\ComputerInventory_$now.csv" -NoTypeInformation
Upvotes: 1
Views: 150
Reputation: 61013
You do not need to pipe to a second ForEach-Object, since all can be done inside the first loop. Also, the Select-Object
can be left out.
In order to enter the catch
block also on non-terminating errors, you need to add parameter -ErrorAction Stop
to the Invoke-Command.
Your code rewritten
Import-Module Active*
$now = (Get-Date).ToString("yyyyMMddTHHmmss")
$localGroup = 'Administrators'
Get-ADComputer -Filter "Name -like 'prod-idfi*'" -Properties LastLogonDate, Description |
ForEach-Object {
$alive = Test-Connection -ComputerName $_.DNSHostName -Count 1 -BufferSize 16 -Quiet
$localAdmins = if ($alive) {
try {
Invoke-Command -ScriptBlock {
([ADSI]"WinNT://./$localGroup").psbase.Invoke('Members') |
ForEach-Object { ([ADSI]$_).InvokeGet('AdsPath') -join ', '}
} -ErrorAction Stop
}
catch {
Write-Warning "Could not retrieve members of the local '$localGroup' group"
}
}
else { '' }
[PSCustomObject]@{
PSTypeName = "Computer"
Id = $null
Name = $_.DNSHostName
IsAlive = [int]$alive
DistinguishedName = $_.DistinguishedName
Description = $_.Description
LastLogonDate = $_.LastLogonDate
LocalAdmins = $localAdmins
}
} | Export-Csv -Path ".\ComputerInventory_$now.csv" -NoTypeInformation
Upvotes: 1