Eager to quell misinformation, Jonathan Medd points why PowerShell 2.0 is so much more than just super-charged SSH. He describes some new commands with full remoting functionality, and then explains persistent sessions, and how they give you that much sought-after power: administration automation.
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:
Get-Command
|
Where-Object {$_.definition
-match
'computername'}
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:
Get-Service
Spooler
-ComputerName
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:
Get-Service
Spooler
-ComputerName
Test01 |
Set-Service
-Status
Running

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.
$Service
=
Get-WmiObject
-ComputerName
Test01
win32_service
-filter
"name='Spooler'"
- Then execute the StartService method to start the Print
Spooler service on Test01.
The ReturnValue of 0 indicates that this was
successful.

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:
Set-Item
WSMan:localhost\Client\TrustedHosts
-value
ServerName
Note: You will need to run
the Enable-PSRemoting cmdlet from a PowerShell session with elevated
privileges, i.e. Run as administrator.

Fig. 3 – running the PowerShell cmdlet with elevated
privileges

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:
-
Start or restart (as necessary) the WinRM service
- Set the WinRM service startup type to be Automatic
- Create a listener to accept requests on any IP address
- Enable a firewall exception for WS-Management traffic (known as
Windows Remote Management)

Fig. 5 – The Firewall exception for WS-Management traffic
You will receive confirmation of what has been carried out
in each step.

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:
-
Registered the Microsoft.PowerShell session configuration, if it
is not already registered.
- Registered the Microsoft.PowerShell32 session configuration on
64-bit computers, if it is not already registered.
- Removed the “Deny Everyone” setting from the security descriptor for all
the registered session configurations.
- 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.

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:
Enter-PSSession
-ComputerName
Test01
You will see that your prompt is now preceded by the name
of the server you have connected to:

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

Fig. 6 – Querying the C:\ drive contents on a remote
machine
Or examine the currently running processes which are from
Microsoft products...
Get-Process
|
Where-Object {$_.Company
-like
'Microsoft
Corporation'} |
Format-Table
Name,Company
-AutoSize

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.

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:
$sessions
=
New-PSSession
-ComputerName
Test01

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.

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:
Enter-PSSession
-Session
$sessions
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:
Invoke-Command -Session $sessions –ScriptBlock {Get-Culture}
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.

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:
Invoke-Command -Session $sessions -FilePath C:\Scripts\QueryServer.ps1
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:
$sessions = New-PSSession -ComputerName (Get-Content C:\Scripts\Servers.csv) 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.
Invoke-Command -Session $sessions –ScriptBlock {Get-Culture}
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:
Remove-PSSession -Session $sessions
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:
$SessionOptions = New-PSSessionOption -IdleTimeout 1200000 -NoCompression -MaximumReceivedObjectSize 104857676

Fig. 11 – Setting the advanced options for persistent
sessions
...and then picked up for use by the New-PSSession cmdlet with the SessionOption parameter:
New-PSSession -ComputerName Test01 -SessionOption $SessionOptions 
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:

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:
Register-PSSessionConfiguration -name WriteLogfile -StartupScript C:\Scripts\StartupScript.ps1
They will first be prompted for confirmation of the action:
Fig. 14 – Setting up the Write-Logfile functionality – part
1
...and then confirmation for restarting the WinRM service to
pick up the new PSSessionConfiguration.
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:
New-PSSession -ConfigurationName WriteLogfile -ComputerName Test01
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:
Get-Command Write-Logfile
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.