Wednesday, April 24, 2013

Learn to Use Remoting in PowerShell


One of the best features PowerShell offers is the ability to remotely manage your Servers. It even lets you manage a bunch of them at once as well.

What is Remoting?

Bulk management of your servers can be tedious, and if you have had to make an IIS configuration change on 50 webservers before, you will know what I mean. These are the kinds of situations when PowerShell Remoting and the language’s scripting abilities can come to the rescue. Using HTTP or the more secure HTTPS, PowerShell Remoting allows you to send commands to a remote machine on you network. The machine then runs the commands and sends the output back to you, which is in turn displayed on your screen.

Let’s Get Technical

At the core of PowerShell Remoting lies a single Windows Service, the Windows Remote Management, or WinRM service, as it has come to be known. Using WinRM, you can set up one or more session configurations (also known as endpoints), which are basically files that contain information about the experience you want to provide to the person connecting to your remote PowerShell instance. More specifically, you can use session configuration files to define who can and who can’t connect to the instance, what cmdlets and scripts they can run, as well as what security context the session must be run under. Using the WinRM Service, you also set up “listeners”, which listen for incoming PowerShell requests. These “listeners” can either be HTTP or HTTPS and can be bound to a single IP address on your machine. When you open a PowerShell connection to another machine (technically this is done using the WS-MAN protocol, which is based on HTTP), the connection binds to one of these “listeners”. The “listeners” are then in charge of sending the traffic to the application associated with the appropriate session configuration file; the application (normally PowerShell but you can have other hosting applications if you want) then runs the command and feeds the results back through the “listener” across the network and back onto your machine.

Show Me How

The first thing you will need to do is enable Remoting on the Machine you want to connect to. This can be done by running the following:
Enable-PSRemoting

You will need to then answer yes to all the prompts. When you run Enable-PSRemoting, a few changes are made to your PC:
  • The WinRM Service starts up.
  • The WinRM Service changes from Manual startup mode to Automatic.
  • It creates an HTTP listener that is bound to all your network cards.
  • It also creates a inbound firewall exception for the WS-MAN protocol.
  • Some default session configurations are created
If you are running Windows 7 and your network card’s location is set to Public, enabling PowerShell Remoting will fail. To fix it, simply switch to the Home or Work network location. Alternatively, you can skip the network check using the following:
Enable-PSRemoting –SkipNetworkProfileCheck

However, we recommend you rather change your network location.
There are two ways of connecting to another machine using PowerShell. There’s the one to one method, which is very similar to using SSH, and then there’s the one to many method.

Using a PowerShell Session

The first way of connecting to a remote machine using PowerShell is using something called a PowerShell Session. Simply put a session allows you to run commands on the remote machine in an interactive fashion much the same you would on your own machine. To open a session simply type the following:
Enter-PSSession –ComputerName “Darlah”

The prompt will gain a prefix which signifies the machine that you are running the cmdlets against.

From here you can really treat the prompt as if you were sitting at the remote machine. For example, if you want to see all the files on the C:\ drive you can do a simple:
Get-ChildItem –Path C:\

If you come from a Linux background, you can think of using this one to one method of remoting as the PowerShell alternative to SSH.

Using Invoke-Command

The second way you can use PowerShell on a remote machine is by using Invoke-Command. The advantage to using Invoke-Command comes from the fact that you can execute the same command on multiple machines simultaneously. As you can imagine, this is particularly useful when you want to do something like gather event logs from your servers. Invoke-Command follows the following syntax:
Invoke-Command -ComputerName Darlah,localhost -ScriptBlock {Get-EventLog Application -Newest 2}

Since the command is executed in parallel across all machines, you will need some way to see which PC a given result came from. You can do this by looking at the PSComputerName property.

When you use Invoke-Command, you no longer have the objects that you might expect in the Pipeline. You see, in order for PowerShell to get the information from the remote machine back to your machine, they need some way of representing the objects that the command you ran on the remote machine outputs. These days it seems the chosen way to represent a hierarchical data structure is to use XML, which means when you issue a command using Invoke-Command, the results are first serialized into XML before being sent back to your machine. Once they get back to your machine, they are deserialized back into an object; the gotcha here is that when they are deserialized, all methods, except the ToString() method, that the object had are stripped away from it.

Note: There are some exceptions to this rule, for example most primitive types like integers can be deserialized with its methods included. There is also a process called Rehydration where some methods can be added back to deserialized objects. So just be careful and remember Get-Member is your friend.

No comments:

Post a Comment