Use PowerShell Workflow to Ping Computers in Parallel

Use PowerShell Workflow to Ping Computers in Parallel

  • Comments 20
  • Likes

Summary: Guest blogger and Microsoft MVP Niklas Goude talks about using Windows PowerShell workflow to ping computers in parallel and save time.

Microsoft Scripting Guy, Ed Wilson, is here. Yesterday was an awesome time spent in Stockholm and the User group there. The Scripting wife and I had a great time with Niklas Goude and friends. So, it seems like a good day to host a guest blog written by none other than MVP Niklas Goude. Read more about Niklas and his other guest blog posts.

Here’s the keyboard, Niklas.

The Test-Connection cmdlet is used to send ICMP echo request packets ("ping") to one or more remote computers.

It's a quick and easy way of finding out if computers are up and running.

To ping a single computer, you can simply type:

Test-Connection -ComputerName localhost

The Test-Connection cmdlet sends 4 echo requests by default. You can change this value to 1, telling the cmdlet to only perform 1 echo request.

Test-Connection -ComputerName localhost -Count 1

Pinging a computer that's not on the network results in an error:

Test-Connection -ComputerName blablabla -Count 1

Test-Connection : Testing connection to computer 'blablabla' failed: No such ho

st is known

At line:1 char:1

+ Test-Connection -ComputerName blablabla -Count 1

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ResourceUnavailable: (blablabla:String) [Test-Co

   nnection], PingException

    + FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Com

   mands.TestConnectionCommand

If you don't want to display the error message, you can set the cmdlets ErrorAction to SilentlyContinue (or use a Try/Catch block and handle the error):

Test-Connection -ComputerName blablabla -Count 1 -ErrorAction SilentlyContinue

The error still occurs—it's just not visible on the screen. (You can still access the error by typing $error[0].)

Now for some fun, let's say that you want to test the connection to all computers in a domain. First, you get a list of all computers by using the Get-ADComputer cmdlet.

$computers = Get-ADComputer -Filter * | Select -ExpandProperty DNSHostName

Next, let's see how many computers are in the domain:

$computers.Count

162

If you want to perform a ping test on each computer in the domain, you could type:

foreach ($computer in $computers) {

  Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue

}

The command returns information from the computers that can be contacted. The only problem with this command is that it takes a lot of time because it pings one computer, and then waits for it to reply before pinging the next one.

Let's find out how much time the command takes by using Measure-Command:

Measure-Command -Expression {

  foreach ($computer in $computers) {

    Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue

  }

}

 

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 39

Milliseconds      : 679

Ticks             : 396797893

TotalDays         : 0,000459256820601852

TotalHours        : 0,0110221636944444

TotalMinutes      : 0,661329821666667

TotalSeconds      : 39,6797893

TotalMilliseconds : 39679,7893

Notice how it takes 39 seconds to ping each computer on the network.

To speed things up, you can place the code in a Windows PowerShell workflow and benefit from the foreach -parallel language construct. Foreach -parallel allows you to process the computers in parallel.

workflow Test-WFConnection {

  param(

    [string[]]$Computers

  )

  foreach -parallel ($computer in $computers) {

    Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue

  }

}

 

Let's see how long the workflow takes to execute:

Measure-Command -Expression { Test-WFConnection -Computers $computers }

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 7

Milliseconds      : 808

Ticks             : 78082448

TotalDays         : 9,03732037037037E-05

TotalHours        : 0,00216895688888889

TotalMinutes      : 0,130137413333333

TotalSeconds      : 7,8082448

TotalMilliseconds : 7808,2448

And we are down at 7 seconds. Isn't that cool!

~Niklas

Thank you, Niklas, for a great post that introduces the capability of Windows PowerShell workflow!

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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Great example of using a workflow...thanks for the idea!

  • @LA Richards yes, I was really impressed when Niklas sent the article. It is a great idea.

  • Playing around with this example and I noticed two things.  First, I don't get any data back with either              Test-Connection or Get-Wmiobject.  And second, inside a workflow statement get-wmiobject wants me to use PSComputerName for remote connectivity.  Is there something that discusses the why to both observations?  

  • Ok, I found out what I did wrong.  I wasn't calling the workflow anywhere in the script....oops.  But, is there anyword on why workflow changes parameter names like -computername to -pscomputername?

  • @LA Richards Great question. PSComputername is a common workflow parameter. You can find more information in the PowerShell help topic about_WorkflowCommonParameters:

    technet.microsoft.com/.../jj129719.aspx

  • Hi Niclas,

    this is cool! Thanks for sharing it.

    I had an approvement from 96.3 to 17.7 seconds (98 computers) which is a factor of 5.4 quite similar to your factor: 5!

    I checked it again against 1000 computers:  The parallel workflow solution took 196.5 seconds ( ~ 3 and a half minutes ) to run, which is quite acceptable and a time I could "actively wait" ( :=  go an get a coffee ) for results :-)

    Executing the sequential approach gave me the results after a returned from lunch: 1016,1 seconds or 16,93 minutes

    which is another factor 5,x

    This is great and really easy to use, at least in this case!

    Thanks, Klaus

  • Great Script, thanks everyone.

  • @K_Schulte wow ... thanks for the statistics ... pinging 1000 computers in 3 1/2 minutes is impressive indeed. Niklas hit a home run with this article.

  • This is perfect timing, I'm working on a script right now that this would be perfect for thanks!

  • A workflow consists of a sequence of concatenated (connected) steps. Emphasis is on the flow paradigm, where each step follows the precedent without delay or gap and ends just before the subsequent step may begin. This concept is related to non overlapping tasks of single resources.

    bworkflow is a intuitive <a href=" http://www.bworkflow.com/> process improvement software </a>      management software which help to increase <a href=" http://www.bworkflow.com/> business process improvement  </a> operational improvement, site audit and operating compliance with business safety legislation

  • Great information and i like the way you write - thumbs up! networks360.net/.../it-support.html

  • You should also put "-ErrorAction SilentlyContinue" on the "Select" incase you have a computer object that does not have the DNSHostName populated like I did in my case.

    $computers = Get-ADComputer -Filter * | Select -ExpandProperty DNSHostName -ErrorAction SilentlyContinue

    sorry if this gets double posted

  • The facor of five seems to be a limit with workflow:

    jeffwouters.nl/.../powershell-workflow-foreach-parallel-limited-to-5-parallel-threads

  • Great post. I am experiencing an issue that might be a bit out of scope. I am multi-threading a powershell script to manipulate Citrix applications against a list of servers. Problem I am seeing is that the Test-Connection when run from the same server against the same remote server it returns false.

    For example, I fire up 5 threads, each from the same source server. They iterate through the list of servers testing for availability, 1 of the five requests comes back true, the others false. Is there anyway around this in your experience?

  • I might add my multi-threading occurs in Python, not powershell due to the need for some other processing.