Don’t Learn PowerShell: Reaching Out


Summary: Microsoft Scripting Guy, Ed Wilson, talks about running commands on remote servers.

Hey, Scripting Guy! Question Hey, Scripting Guy! One of the things I really don’t understand is why Windows PowerShell is broken. I look at commands like you suggest, but they don’t work. Specifically, I wanted to see the status of services on my servers, but the commands just don’t work. What’s up with that?

—BB

Hey, Scripting Guy! Answer Hello BB,

Microsoft Scripting Guy, Ed Wilson, is here. This morning it is cold and raining, which would not be unusual winter weather for Charlotte, North Carolina—except the weather app on Bing said it was going to be sunny all day. It seems that Punxsutawney Phil is more accurate—and he is just a gopher. I wonder, at times, why the weather forecast remains a mystery and isn't updated. I can look outside and see that it is raining, and yet the app says sunshine. Hmmm…

BB, one thing that is not a mystery is why Windows PowerShell won’t work. There is always a reason, and in your case, there are a few likely suspects:

  1. Rights.
    The account you are using to make your remote command may not have rights on the destination server.
  2. Firewall.
    The port used by the command you are attempting to run may be blocked at the firewall.
  3. Services.
    Some commands rely on services, such as the Remote Registry Service or others that may not be running by default.

Because of these issues, I have pretty much quit using commands such as Get-Service –ComputerName MyRemoteServer. The command will fail by default unless you have made configuration changes on your servers—and I would not recommend making such changes due to the fact that you would be widening the attack surface on your servers.

A simple change

The solution is simple: change your command…just a little bit.

I add the command Invoke-Command. When I use Invoke-Command, the command uses WinRM (which is enabled by default on Windows Server 2012 R2. Windows PowerShell uses WinRM for remoting commands. The great thing about this is that it is already enabled on servers, and I do not need to do anything.

Note  If WinRm is not enabled, I use the Enable-PSRemoting command. I can test if WinRM is enabled and configured properly by using the Test-WsMan command.

The command to check the status of the BITS service on a remote server named S1, so the command would therefore be:

Invoke-Command -ComputerName S1 { Get-Service bits }

If I need to check the status of the BITS service on several remote servers, I can separate the computer names with a comma. The following command checks the status of the BITS service on the servers named S1, S2, and SGW.

Invoke-Command -ComputerName S1, S2, SGW { Get-Service bits }

The cool thing is that Windows PowerShell automatically adds a column named PSComputerName to the output. This is shown in the following image:

Image of command output

If I need to add different credentials, I use the –Credential parameter. This causes a dialog box to appear that prompts me to type my password. Here is the command:

Invoke-Command -ComputerName S1, S2, SGW  -Credential nwtraders\administrator { Get-Service bits }

The dialog box is shown here:

Image of dialog box

BB, that is all there is to using Windows PowerShell against remote servers. Don’t Learn Windows PowerShell Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (2)

  1. tommymaynard says:

    My first thought was to build the object on the local computer (not the remote computer), once the results of Invoke-Command were written to $AA: that didn’t work so well. While $AA contained two objects: the deserialized Service object and a System.String
    object, the string didn’t include a property that held the value of $env:ComSpec.

    So I tried your suggesting and built a custom object on the remote computer, and set that as the value of $AA. Here’s an example of doing just that. I hope this helps answer you question!

    $AA = Invoke-Command -ComputerName dc01,dc02 -ScriptBlock {
    $a = Get-Service -Name BITS
    $b = $env:ComSpec

    $Object = [pscustomobject]@{
    Service = $a.Name;
    ServiceStatus = $a.Status;
    ComSpec = $b
    }
    Write-Output -Verbose $Object
    }
    Write-Output -Verbose $AA

  2. Stacey says:

    What is the best way of manipulating the data when it comes back if you have more than one piece of data for example $AA = Invoke-Command -ComputerName server1,server2{ Get-Service bits; $env:ComSpec }

    Do you put everything into an object on the remote computer and somehow get that object to come back?

    Thank you,

    Stacey

Skip to main content