PowerShell with a Purpose Blog

Guest Article: I just wanna go home, so I use PowerShell Remoting!

It's guest Friday, and I've asked another Arizonian PowerShell fan to write up a column for you today. - Don

As an IT Admin or Engineer in a large enterprise, every second counts. As good ol' Ben Franklin once said “a penny saved, is a penny earned”. I’m all about saving time at every opportunity so I can spend that time with my family, or the more serious business of playing games with PowerShell.

One game with PowerShell I began playing was to determine how I could squeeze a little more free-time out of my workload. PowerShell Remoting is clearly one of the most impressive features of PowerShell v2.0, however it's not just a feature, but a life/management style. Once you begin implementing Remoting into your environment, a new world and style of systems management evolves. Let me take a moment to demonstrate how Remoting can save precious time, then I'll demonstrate a management style change.

First, I wanted to create a simple test to represent the power of PowerShell Remoting. Let me be honest, this is a simple test and your results will vary, but it represents my point. I'll start by describing my lab environment for this test.


The purpose of the test is to compare using the -computername parameter in WMI, versus the -computername with Invoke-Command. Also, I wanted to test Invoke-Command using a pre-built session (Fan-out) to each test computer and compare the results. To achieve this, I would construct a PowerShell one-liner to pass commands remotely to several computers.

Expectations? It's never good to have a predetermined result in mind when testing, but my understanding of non-remoting -computername (such as in WMI) would result in passing the commands to one computer at a time sequentially. Using Remoting and the -computername or a pre-built session should pass the commands to each computer simultaneously, decreasing overall execution time.

Framework of the lab

My lab environment consists of 10 test computers, plus one domain controller and one management station. All are Windows 2008 R2 servers connected to a Cisco 2960 switch. Nothing was virtualized.
Test commands should be a PowerShell one-liner and not a script (just because I like one-liners).
Tests should be averaged over multiple runs.

Testing Cmdlets

The primary "work" cmdlet that will be executed on each of the computers is a WMI query of the application log. I didn't want to perform get-process or get-service to avoid some of the caching issues.

Get-WmiObject win32_ntlogevent -filter 'logfile="application"'

I wanted to measure the time that it takes the command to complete, I wrapped the expression in the Measure-Command cmdlet

measure-command {Get-WmiObject win32_ntlogevent -filter 'logfile="application"'}

I needed an average time of the command running for several cycles. Measure-Command sums the results, so I had to use the dreaded Foreach-Object.(yes Don, I'm going to hell!) In this way, the following Measure-Object could give me the average execution time for a per command that I so desired.

1..5 | Foreach-Object{measure-command {Get-WmiObject win32_ntlogevent -filter 'logfile="application"'}}

Lastly, I wanted to trim out only the information I was interested in, which was the average of the total seconds the command took to execute. So I piped the results to the following:

| Measure-object -Property TotalSeconds -Average | 
Format-list -Property Property, Count, Average 

5. I created a server list (Xserver.txt) that held the number of test servers I desired. i.e. 2Server.txt, 4Server.txt, etc.

Tests and Results

1. The first test is using the -computername with WMI. No PowerShell Remoting involved. 

1..5 | 
Foreach-Object{Measure-Command{Get-WmiObject Win32_NTLogEvent -Filter 'logfile="application"' -Computername (Get-Content -Path c:\Xserver.txt)}} | 
Measure-Object -Property TotalSeconds -Average | 
Format-List -Property Property, Count, Average

1 Server -  3.00s
2 Servers -  8.08s
4 Servers - 12.95s
6 Servers - 19.83s
8 Servers - 27.87s
10 Servers - 35.62s

2. Now, let's use PowerShell Remoting. Here I‚Äôm going to use Invoke-Command with the -ComputerName. Unlike WMI, the servers will be contacted simultaneously. This should improve performance greatly, however the drawback is that each time Invoke-Command -computername is executed, it has a start-up and tear-down time for the connection.  

1..5 | Foreach-Object{Measure-Command{Invoke-Command -Computername (Get-Content -Path c:\1server.txt) {Get-WmiObject Win32_NTLogEvent -Filter 'LogFile="Application"'}}} | Measure-Object -Property TotalSeconds -Average | Format-List Property, Count, Average

1 Server -  7.30s
2 Servers - 8.80s
4 Servers - 11.15s
6 Servers - 12.37s
8 Servers - 14.27s
10 Servers - 17.13s

Wow! The difference in time is really dramatic! Ok, not so dramatic, but imagine scaling out to several hundred or thousands of servers. Initially, the startup cost was more for fewer servers, but it really ripped as I scaled out. Let's push the limits and this time pre-build the sessions (fan-out). This should remove the session startup and tear-down cost with Invoke-command -computername.

$s=New-PSSession (Get-Content -Path c:\Xserver.txt)
1..5 | 
Foreach-Object{Measure-Command{Invoke-Command -Session $s {Get-WmiObject Win32_NTLogEvent -Filter 'LogFile="Application"'}}} | 
Measure-Object -Property TotalSeconds -Average | 
Format-List Property, Count, Average

1 Server -  6.44s
2 Servers - 6.64s
4 Servers - 7.38s
6 Servers - 10.34s
8 Servers - 13.55s
10 Servers - 16.03s

Real World

Well, the last test isn't so great, but I suspect that something is going on with the cost of using WMI. More on that in a minute.  

Now, you might be saying, this is interesting but how does it affect me in the real-world. Well, it doesn’t unless you're working with a large amount of computers, however look at Remoting performance from a different management style. Let me give you an example. As an enterprise engineer, I don't think about "How do I check processor performance on a couple of servers?" I think "How do I monitor my network?" See the difference? This is where Remoting really shines in its performance.

Instead of doing something one server at a time, Remoting effects several at once. When I need to deploy a web farm, I could perform this one server at a time, with RDP, or a CD (if I’m crazy), or I could "deploy a web farm."

$s=New-PSSession (Get-Content -Path c:\Xserver.txt)
invoke-command -Session $s {Import-Module ServerManager}
Measure-Command{Invoke-Command -Session $s {Add-WindowsFeature Web-server}}

1 Server -  1.91 minutes
2 Servers - 1.39 minutes
4 Servers - 2.41 minutes
6 Servers - 3.54 minutes
8 Servers - 4.78 minutes
10 Servers - 5.82 minutes

The results speak for themselves. I deployed 10 web servers in 5 minutes, all ready for an xcopy deploy of my web app. 5 Minutes! Wonder what I'll do with the rest of my day? I could go home and spend it with my family, or play with PowerShell some more!

As a closing note, the above tests were run using WMI, and I suspect that WMI might be throwing off some of my numbers. I wonder what my performance would be like if I used a cmdlet such as Get-EventLog? I wonder what stunning results that would produce? Do you want to try?

Knowledge is PowerShell,

Jason Helmick is an instructor at Interface Technical Training specializing in PowerShell.  He is also the co-leader of the Arizona PowerShell User Group AZPOSH.

Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.