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.


Microsoft Remote Assistance UAC

We recently ran into an issue at my work when using Microsoft Remote Assistance. We’d be able to remote into a user’s PC using Remote Assistance just fine, but then when we ran something that needed admin rights, We’d go from a normal screen to this:

MSRA with UAC Secure Desktop prompt

Well that’s not good. The user would be presented with a normal UAC dialog box with a prompt to put credentials in, but the tech helping them just saw a big black box. This was happening because UAC prompts don’t quite go to the user’s desktop, but rather to something called Secure Desktop. To quote Microsoft:

The Secure Desktop’s primary difference from the User Desktop is that only trusted processes running as SYSTEM are allowed to run here (i.e. nothing running as the User’s privilege level) and the path to get to the Secure Desktop from the User Desktop must also be trusted through the entire chain.”

What this means for those using Remote Assistance to help out a user, is that the UAC prompts can be viewed and interacted with on the user’s console, but not via the Remote Assistance session.

The way to “fix” this issue would be to simply disable Secure Desktop, which would keep UAC on, but now present the UAC dialog box on the user’s desktop (and also on the Remote Assistance session). After reading more about Secure Desktop though I decided the need was too small to justify disabling it, as it significantly weakens UAC’s protections, and most especially since we were able to workaround this issue by simply RDPing in as an administrator. With that warning in mind, here’s how to disable Secure Desktop if you decide that’s what’s needed in your environment:

In Group Policy, go to “Computer Configuration\Windows Settings\Security Settings\Local Policies\Security Options”, and from there go to the policy “User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop”. From there check off “define this policy setting”, and make sure “enabled” is selected.

GP setting to disable Secure Desktop