New Remoting Features in PowerShell 2.0

Comments 0

Share to social media

PowerShell 1.0 was a fantastic leap forward for Windows-based administrators, enabling them to manage Microsoft products from the command line in a consistent and powerful way. However, one area which could possibly be considered weak, and which had many calls for improvement, was in the ability to remotely manage computers. Although the Get-WMIObject cmdlet had remote functionality and there were other ways to get round running commands and scripts on remote computers, PowerShell 2.0 goes a long way to improve the experience. There are many more cmdlets that have built-in remoting functionality, and PowerShell 2.0 also adds full remoting capabilities with other servers.

In the course of this article, I’m going to introduce you to some of this fantastic new functionality, point out why it’s such a huge leap forward from PowerShell 1.0, and take you on a whirlwind tour of some newfound powers at your fingertips. By the time we’re finished, I hope you’ll agree with me that PowerShell 2.0 remoting is a great piece of technology, and definitely something you should investigate more.

New cmdlets with remoting functionality

In PowerShell 1.0, only the Get-WMIObject cmdlet had the ComputerName parameter available, enabling administrators to execute that cmdlet against remote machines. In PowerShell 2.0, this list has been extended to thirty five cmdlets with the ComputerName parameter, including two of the most popular, Get-Process and Get-Service.

Tip: to quickly find which cmdlets have a ComputerName parameter available, you can run the below command:

It is important to note that the remoting functionality used with the ComputerName parameter is not consistent across all cmdlets, and is determined by the creator of the cmdlet. Most likely it will not be using the technology which ‘full’ PowerShell remoting takes advantage of, and will typically be using something like RPC instead.

Great examples of this enhanced functionality are the Get-Service  and Set-Service cmdlets, which now make it possible to query services on a remote computer and then manipulate them. To demonstrate: the following command queries the Print Spooler service on the remote machine Test01:

We observe that this service currently has a status of Stopped. By running the same command again, and this time piping it through to the Set-Service cmdlet and using the Status parameter to apply a status of Running, we observe that this service has now started:

1007-JM1.JPG

Fig 1. – A successful start of the Print Spool service using PowerShell 2.0

Previously, in PowerShell 1.0, we could have done this through WMI using the Get-WMIObject cmdlet and its ComputerName parameter:

  • First of all store the results of a WMI query into the $Service variable.

  • Then execute the StartService method to start the Print Spooler service on Test01.

The ReturnValue of 0 indicates that this was successful.

1007-JM2.JPG

Fig. 2  – A successful start of the Print Spool service through WMI, using PowerShell 1.0

Clearly it still only took two lines of code in PowerShell 1.0 to achieve this task, but in PowerShell 2.0 we were able to take advantage of the pipeline with the Get-Service  and Set-Service cmdlets,  and we didn’t need to investigate which WMI classes and methods we might have needed to achieve the same outcome.

WinRM 2.0 and the Windows Management Framework

Aside from these cmdlets with enhanced capabilities, PowerShell 2.0 also ships with full remoting functionality. By that I mean that it is possible to connect your local PowerShell session to a remote computer and execute commands just as if you were sitting in front of the server console. The technology to make this happen relies on WinRM 2.0, which is Microsoft’s latest implementation of the WS-Management Protocol, a SOAP-based protocol used to manage a variety of hardware devices. The theory behind this is that it will provide a shared way for differing systems to communicate with each other.

WinRM 2.0 communicates via HTTP, and so is likely to be firewall-friendly; it also listens on ports 5985 (default) and 5986 (encrypted), avoiding issues with locally installed IIS. Even though it uses HTTP for communication, security has still been considered; either NTLM or Kerberos are used for authentication, and if you wish to configure WinRM 2.0 to use SSL, that is possible too. A lot of the configuration can be carried out via new PowerShell cmdlets shipped with version 2.0, but more on that later.

Since PowerShell 2.0 and WinRM 2.0 go hand in hand, Microsoft has bundled them up together along with a new version of BITS (Background Intelligent Transfer Service) 4.0, making a single package known as the Windows Management Framework. Although this collection makes some sense if you know the background, there can be some confusion if an administrator is searching for the download of PowerShell 2.0, ends up at the homepage for the Windows Management Framework (http://support.microsoft.com/kb/968929) and wonders what the heck that is. Well, now you know!

The components of the Windows Management Framework are already installed with both Windows Server 2008 R2 and Windows 7, althoughWinRM 2.0 is not enabled by default on Windows 7. The components have also been made available for older OS  versions, and you can download all of those from the homepage of the Windows Management Framework. Essentially, it is available for the various flavours of Windows Server 2008 and 2003, as well as the Windows Vista and XP client operating systems – although BITS 4.0 is not available for Windows Server 2003 or XP. This might sound like a muddle, but in short, it is possible to run remote PowerShell 2.0 sessions both to and from all these different operating systems.

At this point, Unix / Linux administrators might be sitting back and chuckling to themselves, saying that they’ve had this since the beginning of time with Telnet / SSH, and wondering what all the fuss is about; and to a certain extent, that is a very fair point. However, the great news for Windows administrators is that you now have a scalable, consistent command line interface which you can use against remote machines – you no longer have anything standing in the way of efficiently managing and automating your systems! Even if this was just an equivalent of SSH, that would be a decent start, but I’m hopefully about to show you that PowerShell remoting is significantly more than that.

Getting Started

First of all, you obviously need to make sure you’ve got a server which meets the requirements for PowerShell 2.0 remoting; either Windows Server 2008 R2 with everything already built-in, or Windows Server 2008 or 2003 with the Windows Management Framework downloaded and installed. Once you’ve got that, configuration for PowerShell 2.0 remoting, if the computer is a member of a domain, is as simple as running this cmdlet…

Enable-PSRemoting

…which will make all the necessary changes for you. However, if you are operating within a workgroup then you need to make some additional changes. Specifically, if the Operating System is Windows XP then you will need to adjust the Local Security Policy setting (Network Access: Sharing and Security Model for local accounts) to Classic.

Then, for any Windows Operating System, including Windows XP, you will need to add the names of the remote computer(s) into the TrustedHosts setting of WinRM. You can do this using the PowerShell command below:

Note: You will need to run the Enable-PSRemoting cmdlet from a PowerShell session with elevated privileges, i.e. Run as administrator.

1007-JM3.JPG

Fig. 3 – running the PowerShell cmdlet with elevated privileges

1007-JM4.JPG

Fig. 4 – Enable-PSRemoting initially runs Set-WSManQuickConfig

You can see from the screenshot above that the Enable-PSRemoting cmdlet actually initially runs the Set-WSManQuickConfig cmdlet, which in turn is one of the new cmdlets I mentioned previously that have been included as part of PowerShell 2.0 for working with WS-Management. Set-WSManQuickConfig will carry out four steps:

  1. Start or restart (as necessary) the WinRM service
  2. Set the WinRM service startup type to be Automatic
  3. Create a listener to accept requests on any IP address
  4. Enable a firewall exception for WS-Management traffic (known as Windows Remote Management)

1007-JM5.JPG

Fig. 5 – The Firewall exception for WS-Management traffic

You will receive confirmation of what has been carried out in each step.

1007-JM6.JPG

If you are running on a 64bit machine, then you will be prompted to additionally create a 32bit session configuration – accept this, and then your configuration will be complete. In addition to the WS-Management configuration, to ensure that all registered Windows PowerShell session configurations will have been enabled to receive instructions from a remote computer, the following steps will have also been taken:

  1. Registered the Microsoft.PowerShell session configuration, if it is not already registered.
  2. Registered the Microsoft.PowerShell32 session configuration on 64-bit computers, if it is not already registered.
  3. Removed the “Deny Everyone” setting from the security descriptor for all the registered session configurations.
  4. Restarted the WinRM service to make the preceding changes effective.

So quite a lot has been configured, but it’s all been made nice and easy for the administrator in one short command.

Note: In an Enterprise environment you will obviously not want to run Enable-PSRemoting on every machine you wish to configure for remoting. Fortunately, it is possible to make these changes via the Group Policy setting Computer Configuration\Policies\Administrative Templates\Windows Components\Windows Remote Management\WinRM Service\Allow automatic configuration of listeners. Group Policy could also be used to configure the necessary firewall change and ensure that the WinRM service was set to start automatically.

1007-JM7.JPG

Interactive Sessions

Now that you are ready to begin using PowerShell remote sessions, we will  start off with a look at running an interactive session. Say, for instance, that you wish to quickly connect to a remote computer to run a few interactive commands and you don’t need to save the session for later use – a fairly typical situation for a Unix / Linux administrator wishing to quickly SSH into a remote server.

To do this, you will need to use the Enter-PSSession and Exit-PSSession cmdlets, and connect to a remote computer where Enable-PSRemoting has previously been run. To begin the session, use Enter-PSSession and specify which computer you wish to connect to:

You will see that your prompt is now preceded by the name of the server you have connected to:

1007-JM8.JPG

From classhere, you can now run any commands just as if you were sat in front of the console at Test01; for example, you could look at the contents of the C:\ drive…

dir

1007-JM9.JPG

Fig. 6 – Querying the C:\ drive contents on a remote machine

Or examine the currently running processes which are from Microsoft products…

1007-JM10.JPG

Fig. 7 – Finding all the currently-running process which originate from Microsoft products

Once you are finished with the session, you can quickly tear it down without any parameters using Exit-PSSession:

Once you’ve done this, you will notice that your prompt changes back to normal now that you are back on the local computer.

1007-JM11.JPG

Persistent Sessions

If the story ended there, then you might say to yourself “Terrific, Windows now has a solution similar to SSH. I can manage Windows Servers remotely from the command line.” However, the PowerShell story is all about automation, and not just for one remote server, but for as many as you can handle. To that end, there are a number of other cmdlets in PowerShell 2.0 for working with remoting and, starting with New-PSSession, I will show you how to advantage of these and very simply use some of the very powerful tools now at your disposal.

The New-PSSession cmdlet creates persistent remote PowerShell sessions to one or multiple computers. The difference between this and  Enter-PSSession is that these sessions are maintained for later use, either for ad hoc connections or, more typically, to run commands or scripts against. You can also store these sessions as objects in a variable for ease of reference. For instance, the command below will create a persistent remote PowerShell session to the computer Test01, and store it in the $sessions variable:

1007-JM12.JPG

Fig. 8 – Creating and storing a persistent session

The stored session is an object of type System.Management.Automation.Runspaces.PSSession, and has methods and properties just like any other object.

1007-JM13.JPG

Fig. 9 – The methods and properties of System.Management.Automation.Runspace.PSSession object

If you wanted to, you could now use that session with the Enter-PSSession cmdlet and remotely connect to the server Test01 with minimum hassle:

Remote Commands, Local Results

What would actually be far more interesting (not to mention useful) would be to submit some commands to that remote server via this persistent session, and return the results to your local session. To do that, we can use another new PowerShell 2.0 cmdlet: Invoke-Command.

Let’s say we wanted to run another new PowerShell 2.0 cmdlet Get-Culture , which doesn’t have a built-in ComputerName parameter, on the remote Test01 server in order to retrieve information about the current culture settings. The command below will make use of the already established remote PowerShell session with Test01, run the command contained within the scriptblock on Test01, and then return the results to the local session:

You will notice that the results are returned to your local session and contain a column named PSComputerName, which indicates which remote computer the results were returned from.

1007-JM100.JPG

Fig. 10 – The Culture settings from Test01, returned to the local session

Another useful parameter included with Invoke-Command is the FilePath parameter. So instead of having all their commands inside a chunky scriptblock, an administrator can instead specify the path to a local PowerShell script, have that script run locally on the desired server, and return the results back to the local session.

For example, the command below would execute the local PowerShell script QueryServer.ps1 on the remote server Test01 and return the results:

The possibilities for using these techniques with remote sessions are potentially limitless, and a really powerful and efficient leap can be made with just one minor amendment when creating the remote session with New-PSSession (which I’ll tell you about in just a moment). It doesn’t take great imagination to extend the ideas we’ve been looking at, potentially saving the administrator hours of work.

Envisage a scenario where, instead of needing to determine the culture settings on just one server (Test01), this time we need to find the same settings on 100, or even 1000 servers. If you have the names of the servers stored somewhere easily accessible, say in a CSV file or a SQL database, an administrator could very easily first query that datasource for the names, and then create persistent remote PowerShell 2.0 sessions to all of those servers from one command.

Note: by default, PowerShell will only process 32 sessions created by New-PSSession at one time, and any others will be queued. Depending on system resources and network bandwidth, it is possible to increase this value via the ThrottleLimit parameter.

Let’s say the administrator has these server names stored in the file C:\Scripts\Servers.csv. Creating these 100 or 1000 sessions is now as simple as running New-PSSession and using another PowerShell cmdlet, Get-Content, to read in those names for New-PSSession to use:

All those sessions would then be created and, once again, stored in the $sessions variable. Next, the administrator would just need to re-run exactly the same code for Invoke-Command , and they would receive the culture settings for all 100 or 1000 servers in their local session.

Sessions stored within the $sessions variable will remain there until either the client PowerShell session itself is closed, they have been removed with the Remove-PSSession cmdlet, or they have timed out. Each remote server maintains a heartbeat connection with the client by default for four minutes, and if there is no network communication between them during this period then the session will break. To manually close the sessions, use the command below:

Advanced Session Options

There are a number of other cmdlets which ship with PowerShell 2.0 for the advanced configuration of remote PowerShell sessions. The first and most obvious of these is the New-PSSessionOption cmdlet, which enables an administrator to configure advanced options for use with the New-PSSession cmdlet. For instance, they might want to fine tune the connection by changing the default timeout period from four minutes, turn off compression or set some restrictions on the maximum size of an object that the local machine can receive from the remote computer (in bytes). These options can be stored in a variable:

1007-JM15.JPG

Fig. 11 – Setting the advanced options for persistent sessions

…and then picked up for use by the New-PSSession cmdlet with the SessionOption parameter:

1007-JM16.JPG

Fig. 12 – A persistent session employing the Administrator’s customized advanced settings

Alternatively, an administrator can set session options directly on the machine which will be connected to, either so that particular functionality can be offered to the administrator connecting remotely or so that session settings can be enforced. To achieve this, we can use the Register-PSSessionConfiguration cmdlet.

A good example for this cmdlet is to use the StartupScript parameter; when a remote administrator connects in and specifies this specific session configuration, they will receive the functionality specified in the startup script. So, say an administrator creates a startup script containing the function Write-Logfile seen below:

1007-JM17.JPG

Fig. 13 – A startup script containing a Write-Logfile script, ready to be activated remotely

Now they can register a new PSSessionConfiguration called WriteLogfile with the above file specified as a startup script, which will in turn create a dynamic module using the scriptblock containing the Write-Logfile function:

They will first be prompted for confirmation of the action:

1007-JM18.JPG

Fig. 14 – Setting up the Write-Logfile functionality – part 1

…and then confirmation for restarting the WinRM service to pick up the new PSSessionConfiguration.

1007-JM19.JPG

Fig. 15 – Confirming the WinRM service restart

For the remote administrator to make use of this new PSSessionConfiguration, they should use the ConfigurationName property of the New-PSSession cmdlet:

1007-JM20.JPG

Fig. 16 – Setting the ConfigurationName property in New-PSSession

They can then connect to that session with:

…and test that the Write-Logfile function is available:

1007-JM21.JPG

Fig. 17 – testing the new Write-Logfile functionality

Summary

Missing from the original 1.0 release of Windows PowerShell was the ability to work remotely against Windows Servers. Although some functionality was available with the Get-WMIObject cmdlet, this has been greatly enhanced in version 2.0 with the addition of many more cmdlets which have the ability to function against remote computers, and full remoting capabilities that work either interactively or with persistent sessions. Administrators can and should take advantage of these new possibilities to work more efficiently with the servers they manage, and increase the levels of automation within their environment.

I’ve taken you on a very brief tour of some of the highlights of this new and enhanced functionality, and I invite you to find out more and start experimenting.

This article was commissioned by Red Gate Software, engineers of ingeniously simple tools for optimizing your Exchange email environment.
Learn more about Exchange Server Archiver and PST Importer.

About the author

Jonathan Medd

See Profile

Jonathan Medd has been working with Windows Infrastructure products since 1997 and, more recently, virtualisation technologies from VMware. In 2007, he discovered Windows PowerShell and now spends a lot of time encouraging the IT pros he meets to use PowerShell by talking with them, giving presentations to User Groups, and via posts on his blog. He also co-hosts the Get-Scripting PowerShell podcast, which contains info on how to learn PowerShell and what's going on in the PowerShell world. In April 2010, he was awarded status as a Microsoft Most Valuable Professional (MVP) for PowerShell, and you can follow him on Twitter at @jonathanmedd

Jonathan Medd's contributions