'Get-Process -computername pipeline input works only with the first name
Get-Process accepts -computername parameter by pipeline (ByPropertyName). The file I import looks like:
computername
sql01
sql02
sql03
When I pipe it, I'll get the processes only from the first computer in the list (sql01)?
$a = Import-Csv C:\temp\computers.txt
$a | get-process -name dwm # output only from the first computer in the list
get-process dwm -ComputerName $a.computername # here correct output from 3 computers
Solution 1:[1]
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
-ComputerNameinstead of via the pipeline.# Windows PowerShell only. Get-Process dwm -ComputerName $a.computernameFrom a broader perspective, consider switching to using PowerShell's remoting, where only the general-purpose
Invoke-Commandcmdlet 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
-ComputerNameparameters on purpose-specific cmdlets such asGet-ProcessandRestart-Computeraren'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).
- Note that the
Bug details:
The bug is specific to the combination of:
providing objects that have a
.ComputerNameproperty via the pipeline in order to bind the property values to the-ComputerNameparametertargeting processes by name(s), via the (possibly positionally implied)
-Nameparameter, or targeting all processes (by neither passing a-Namenor an-Idargument)
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
