Im trying to get list of all computers and logged on user for each computer.
I get the list of computers, and when I query for each string returned, I can get the logged in user.
However, when I use the computer name variable to get all users - I get an error saying that my variable is unknown. I tried casting the computer name to string but that didn't help.
By the way it's the same error that comes up when I type in a wrong computer name, so it has something to do with the type of variable #item, When I print the variable out it's correct, but cannot be used inside the loop.
$obj = Get-ADComputer -Filter 'Name -like "L*"' -Properties * | Select -ExpandProperty Name
foreach ( $item in $obj ) {
$itemString = $item.ToString()
$user = Get-WmiObject –ComputerName $itemString –Class Win32_ComputerSystem | Select-Object UserName | select -expandproperty UserName -first 1
$user = $user.SubString(8)
write-output "Computer: $itemString Username: $user"
}
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At N:\Foreach.ps1:4 char:13
+ $user = Get-WmiObject –ComputerName $itemString –Class Win32_Comp ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Your symptom suggests that the offending target computer is simply not available, e.g., due to being disconnected from the network or being powered off.
Your code doesn't deal with this scenario, but is otherwise correct in terms of data types (though given that the .Name
property is [string]
-typed and you've used Select-Object -ExpandProperty
, $obj
is an array of strings already, and therefore $item
is a single string in the foreach
loop, there is no need for a separate $itemString
variable obtained with .ToString()
).
Note: I'm assuming that the .Name
property value is sufficient to identify a computer in the Get-WmiObject
call; if it isn't, use Select-Object -ExpandProperty DNSHostName
.
Generally, note that Get-WmiObject
's -ComputerName
parameter is [string[]]
-typed, so you can directly pass an array of hostnames to it.
However, regrettably, the [System.Management.Automation.ErrorRecord]
instances created by Get-WmiObject
when a target computer is unavailable don't contain the offending computer name, so using a single command with later inspection of error output isn't an option (though see the Get-CimInstance
alternative at the bottom).
With that in mind, here's a PSv3+ loop-based solution that handles unavailable computers gracefully:
foreach ($computer in (Get-ADComputer -Filter 'Name -like "L*"' -Properties *).Name) {
$computerInfo = Get-WmiObject -ErrorAction SilentlyContinue -ComputerName $computer -Class Win32_ComputerSystem
if (-not $?) { # Call failed, analyze the reason.
if ($Error[0].Exception.HResult -eq 0x800706BA) { # unavailable
# Merely issue a *warning*.
# Alternatively, collect the unavailable names in an array for later use.
Write-Warning "Computer is unavailable: $computer"
} else { # unexpected error, pass it through
Write-Error $Error[0]
}
} else { # success
"Computer: $($computerInfo.Name) Username: $(($computerInfo.UserName -split '\\')[-1])"
}
}
By contrast, Get-CimInstance
- recommended instead of Get-WmiObject
since its introduction in PSv3 - does add origin information to error records, so a single invocation of Get-CimInstance
is sufficient - do note that the results are not guaranteed to arrive in the same order in which the computers were specified, but you do benefit from parallel execution.
# Use a single Get-CimInstance call to target all computers and
# quietly collect errors for later analysis.
$computerNames = (Get-ADComputer -Filter 'Name -like "L*"' -Properties *).Name
Get-CimInstance -ErrorAction SilentlyContinue -ErrorVariable errs `
-ComputerName $computerNames -Class Win32_ComputerSystem | #`
ForEach-Object {
"Computer: $($_.Name) Username: $(($_.UserName -split '\\')[-1])"
}
# Analyze the errors that occurred, if any.
$errs | ForEach-Object {
if ($_.Exception -is [Microsoft.Management.Infrastructure.CimException] -and $_.CategoryInfo.Category -eq 'ConnectionError') {
Write-Warning "Computer is unavailable: $($_.OriginInfo.PSComputerName)"
} else { # unexpected error, pass it through
Write-Error $_
}
}
User contributions licensed under CC BY-SA 3.0