Pinging Faster with Test-Connection

Pinging in PowerShell is easy, but it always seems to be slow. As an example, here’s a command to ping 254 addresses:


Six minutes! Part of the issue here is that we’re pinging these hosts one by one in serial, meaning that we have to wait for the previous command to finish before we can begin the next one.

Luckily Test-Connection has a parameter AsJob that allows us to run each test more or less at the same time. The script here is a bit more complicated as we now have to deal with the management of the jobs1 (a new job is created for each IP we’re testing). We’re also using Select-Object here because there seems to be some odd performance hit when Test-Connection is allowed to output normally. Consequently we’re also using Where-Object to return only those hosts which we were able to ping successfully (for more information on ping status codes, check out the StatusCode section in the Win32_PingStatus2 documentation):

1..254 | ForEach-Object {
    Test-Connection -ComputerName "192.168.1.$_" -Count 1 -ErrorAction:SilentlyContinue -AsJob
} | Get-Job | Receive-Job -Wait -AutoRemoveJob | Where-Object {$_.StatusCode -eq 0} | Select-Object -Property Address

And the results…


Two seconds! That’s more like it! Kudos to Anders Wahlqvist3 over on StackExchange for providing the code neccessary to accomplish this.


Hunting Down Rogue Static IPs

I recently ran into an issue at work where someone had set static IPs on a handful of nodes as a temporary fix, but then forgot to exclude the IPs on our DHCP server. This was in turn causing issues with some other nodes that were getting their IPs from the DHCP server dynamically, and were then receiving a DHCP NAK on startup when their assigned address was already in use. With the problem identified, I decided to hunt down these misconfigurations by determining which IPs on our DHCP server should not be in use, and then simply ping them. Determing the IPs that shouldn’t be in use is bit complicated though, as you have to take the IP range you want to query and then remove all leases, reservations, and manual exclusions from it. Thankfully Microsoft provides a powershell cmdlet that does all that work for us, Get-DhcpServerv4FreeIPAddress (phew!). With that cmdlet at hand, we can now take those IPs1 and pipe them out to Test-Connection. Any results that are returned are IPs that the DHCP server believes to be free, but are actually in use as an undocumented static IP.

$dhcpserver = ""
Get-DhcpServerv4Scope -ComputerName $dhcpserver | Get-DhcpServerv4FreeIPAddress -ComputerName $dhcpserver -NumAddress 1024 |
ForEach-Object {
    Test-Connection -ComputerName $_ -Count 1 -ErrorAction:SilentlyContinue

By default the script will query all scopes, but if you want to get more granular and only target one scope, in the Get-DhcpServerv4Scope command add on the -ScopeID parameter followed by the ID of the scope you want to target.

If you have alot of IPs that you want to query, or just want to monitor the script’s progress, I have a fancier version of this script too.

$dhcpserver = ""
$ips = Get-DhcpServerv4Scope -ComputerName $dhcpserver | Get-DhcpServerv4FreeIPAddress -ComputerName $dhcpserver -NumAddress 1024 -WarningAction:SilentlyContinue
$percent = ( 100 / $ips.Count )
$i = $percent
foreach($ip in $ips){
    Write-Progress -Activity "Testing Connections" -Status "Pinging $ip" -PercentComplete $i
    Test-Connection -ComputerName $ip -Count 1 -ErrorAction:SilentlyContinue
    $i = $i + $percent


  1. Get-DhcpServerv4FreeIPAddress can only return a maximum of 1024 addresses per scope. If any scope on your DHCP server has more than 1024 possible addresses in it, be aware that this script may not be able to test them all.

MDTApplicationTools PowerShell Module

Earlier in the year I took charge of my work’s Windows 7 to Windows 10 Migration. I work at a college, and a good part of the machines we manage are computer labs, for which we have to manage about 130 different software packages (I should probably mention at this point that we use the Microsoft Deployment Toolkit to manage all of our images, drivers, and packages). As part of the migration, I wanted to mark all packages in the labs as supporting Windows 7 Only in MDT, and then gradually bring in each package, testing to make sure their installation, settings configuration, and user experience didn’t break in Windows 10, and afterwards removing the OS restriction once I had verified the app was OK. I also wanted a way to query a package that is dependency of a bunch of other packages, so I could then test all those dependent applications to make sure my updating their shared dependency didn’t in turn break those packages themselves(I had one package in mind here for the shared dependency issue. It’s name rhymes with lava)

Through having the Microsoft Deployment Toolkit installed on my computer I had access to all the MDT PowerShell Cmdlets, and could mount my MDT shares as a drive in PowerShell (cool stuff), but I didn’t really have the fine grain control I wanted in order query and manipulate the MDT applications in this manner. So what would be the shortest, easiest, most efficient way to get around these problems? Spend hours upon hours creating a PowerShell module of course! Here’s an excerpt from the README file to give you an idea of what it does:

  • Get-MDTApplication
    • Retrieves MDT applications, either by name/guid, or just all of them.
  • Get-MDTApplicationDependency
    • Retrieves either the parent or child dependencies of an MDT application. Can either return one depth, or can recurse the entire depth of the dependency tree
  • Get-MDTApplicationSupportedPlatform
    • Queries MDT applications to see if they have the SupportedPlatform attribute set.
  • Set-MDTApplicationSupportedPlatform
    • Sets the SupportedPlatform attribute on MDT applications
  • Find-MDTApplicationContent
    • Searches through either the installcmd attribute or the install scripts themselves of all the MDT applications in a share for the specified string(i.e “pause”, “powershell.exe”, “C:\Program Files (x86)”, etc.)

It took me a while to make, but I learned a ton in the process, and in the end I have a tool that helps me out a great deal when updating or changing applications. If you’d like to learn more, check out the project’s page below. The README file on that page should have all the info you need to get it up and running on your computer.