One of the things that I urge, if not plead, in my PowerShell classes is to read the help files. I’ve been working with PowerShell since it was called Monad. I honestly cannot work with PowerShell unless I use the help system. One of the reasons why I want IT Pros to read the help files is so they do not “assume” something. Take this code that I looked at on PowerShell.Com’s forums.
get-content -path c:\temp\servers.txt |
foreach {Get-WmiObject win32_service} |
select pscomputername, displayname, startname
The problem that the IT Pro was having is that the PSComputerName property was always his local client, not the remote computer. The help file for Get-WMIObject says this about the ComputerName parameter:
-ComputerName [<String[]>]
Specifies the target computer for the management operation. Enter a fully
qualified domain name, a NetBIOS name, or an IP address. When the remote
computer is in a different domain than the local computer, the fully
qualified domain name is required.
The default is the local computer. To specify the local computer, such as
in a list of computer names, use "localhost", the local computer name, or
a dot (.).
This parameter does not rely on Windows PowerShell remoting, which uses
WS-Management. You can use the ComputerName parameter of Get-WmiObject
even if your computer is not configured to run WS-Management remote
commands.
Required? false
Position? named
Default value none
Accept pipeline input? false
Accept wildcard characters? false
The assumption here is that ComputerName would be populated by the name of the computer in the Pipeline. Two things are wrong here. The first is that ComputerName parameter is Name, not positional. It also cannot accept anything from the pipeline. That means that if you do not type –ComputerName, it will not be used. Get-WMIObject will execute against the local client. The other problem is that inside of ForEach-Object, you need to make a reference to the current object in the PowerShell Pipeline. You do this with $_ or $PSItem
The site user CMartin16 provided the correct answer to this problem:
get-content -path c:\temp\servers.txt |
foreach {Get-WmiObject win32_service -ComputerName $_} |
select pscomputername, displayname, startname
As an update to this, take a look at Get-CIMInstance and using a CIMSession. You could also use Invoke-Command and take advantage of PowerShell remoting to contact the remote clients.
Get-Content -Path c:\temp\servers.txt |
ForEach-Object {Get-CimInstance -ClassName Win32_Service -ComputerName $_} |
Select-Object -Property pscomputername, displayname, startname
The ComputerName parameter of Get-CIMInstance creates an ad-hoc Session to each client. Here is another example.
Get-CimInstance -ClassName Win32_Service -ComputerName (Get-Content -Path c:\temp\servers.txt)|
Select-Object -Property pscomputername, displayname, startname
An example using PowerShell remoting.
Invoke-Command -ComputerName (Get-Content -Path c:\temp\servers.txt) -ScriptBlock {
Get-CimInstance -ClassName Win32_Service
}| Select-Object -Property pscomputername, displayname, startname
Comments