It looks like you've hit a bug in Windows PowerShell - see bottom section for details.
The bug is unlikely to get fixed, given that Windows PowerShell will only see critical fixes going forward.
You are already aware of the workaround: pass the array of computer names as an argument to -ComputerName
instead of via the pipeline.
# Windows PowerShell only.
Get-Process dwm -ComputerName $a.computername
From a broader perspective, consider switching to using PowerShell's remoting, where only the general-purpose Invoke-Command
cmdlet facilitates execution of arbitrary commands remotely, using a modern, firewall-friendly transport. Similarly, the CIM cmdlets (e.g. Get-CimInstance
), which use the same transport, should be preferred over the obsolete WMI cmdlets they supersede (e.g., Get-WmiObject
).
# Works in both PowerShell editions, assuming the target computers
# are set up for PowerShell remoting.
# Note: Invoke-Command does NOT support passing computer names via the pipeline.
Invoke-Command -ComputerName $a.computername { Get-Process dwm -ComputerName }
- Note that the
-ComputerName
parameters on purpose-specific cmdlets such as Get-Process
and Restart-Computer
aren't available in PowerShell (Core) 7+ anymore, and neither are the WMI cmdlets, because they are based on .NET Remoting, a form of remoting unrelated to PowerShell that has been declared obsolete and is therefore not part of .NET Core / .NET 5+. By definition, the bug at hand therefore doesn't affect PowerShell (Core).
Bug details:
The bug is specific to the combination of:
providing objects that have a .ComputerName
property via the pipeline in order to bind the property values to the -ComputerName
parameter
targeting processes by name(s), via the (possibly positionally implied) -Name
parameter, or targeting all processes (by neither passing a -Name
nor an -Id
argument)
In other words: targeting processes by PID (process ID), via the -Id
parameter is not affected - but using -Id
remotely is only useful if you've previously obtained a PID from a given computer and if you're targeting only one computer.
In Windows PowerShell, Get-Process
's -ComputerName
parameter is designed to bind objects supplied via the pipeline that have a .ComputerName
property to the -ComputerName
parameter:
WinPS> Get-Help Get-Process -Parameter ComputerName
-ComputerName <System.String[]>
# ...
Accept pipeline input? True (ByPropertyName)
# ...
However, as you've observed, only the first computer name bound this way is honored by Get-Process
in combination with -Name
- any remaining ones are quietly ignored:
# Target the local machine (.) and a NON-EXISTENT machine ('NOSUCH')
WinPS> [pscustomobject] @{ ComputerName='.' },
[pscustomobject] @{ ComputerName='NOSUCH' } |
Get-Process -Name powershell
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
970 48 170860 29120 56.41 4656 1 powershell
That is, the local machine's PowerShell process(es) are reported, and the non-existent computer name was quietly ignored.
Note: Any subsequent computer names are ignored, whether they refer to existing computers or not. Using a non-existent one should conspicuously surface as an error.
If you replace -Name powershell
with -Id $PID
, you will indeed see the error.
The problem is not one of parameter binding, as output from a Trace-Command
call shows:
WinPS> Trace-Command -pshost -name ParameterBinding {
[pscustomobject] @{ ComputerName='.' },
[pscustomobject] @{ ComputerName='NOSUCH' } | Get-Process -Name powershell
}
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Process]
# ...
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-Process]
# ...
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Get-Process]
DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
# ...
DEBUG: ParameterBinding Information: 0 : Parameter [ComputerName] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [.] to parameter [ComputerName]
# ...
DEBUG: ParameterBinding Information: 0 : BIND arg [System.String[]] to param [ComputerName] SUCCESSFUL
# ...
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Get-Process]
DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
DEBUG: ParameterBinding Information: 0 : BIND arg [NOSUCH] to parameter [ComputerName]
# ...
DEBUG: ParameterBinding Information: 0 : BIND arg [System.String[]] to param [ComputerName] SUCCESSFUL
# ...
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
BIND arg [.]
and BIND arg [NOSUCH]
, followed by a SUCCESSFUL
status, indicate that both computer names were properly bound.
In other words: the bug must be in the code that subsequently uses the correctly bound parameters.