Use PowerShell to Audit and Install Windows Patches

Summary: Learn how to use a free Windows PowerShell module to audit and install patches on Windows systems.


Microsoft Scripting Guy Ed Wilson here. Today, I am proud to present a guest blog post written by Boe Prox. Boe has written a really cool module to audit and install software patches on Windows systems.

Boe is currently a senior systems administrator with BAE Systems. He has been in the IT industry since 2003 and has spent the past three years working with VBScript and Windows PowerShell. He looks to script whatever he can, whenever he can. He is also a moderator on the Hey, Scripting Guy! Forum. You can check out his blog and his projects: PoshWSUS and PoshPAIG.


<BoeProxDisclaimer>This post does not contain any code in it. It does, however, show examples of what I have been able to put together using Windows PowerShell to create an application to manage the patching of servers in an enterprise environment. Tomorrow’s post will contain more code in it as I discuss some issues I ran into and how I resolved them.</BoeProxDisclamer>

Something that I have been working on for a little while as a work project is a way for other users in my shop to be able to patch our servers during a downtime without actually having to log into each server remotely to install the patches that have been downloaded from the local WSUS server. 

Initially, I wrote two sets of Windows PowerShell scripts: one to audit for patches that were downloaded to each server and waiting to be installed, and another that would install those patches on the server remotely. Though this is a great solution for a couple other folks and me who are familiar with Windows PowerShell, it is not the “complete solution” that we were looking to use with everyone else in my shop. We needed something that would make it easy for anyone to use (a GUI) and still perform the same tasks as the original scripts I wrote.

Enter the PowerShell Patch Audit/Installation GUI (PoshPAIG).

Image of PoshPAIG interface

Rather than go into a lot about how I built PoshPAIG and why I made it the way I did, I am going to go more into some of the new features that I implemented for the latest version, 1.6. If you wish to learn more about what I did to initially build this utility, go to this blog post. My next post tomorrow will also go into some issues I ran into during the build and what I was able to do to resolve them.

Running the utility

First download PoshPAIG. From there, unzip the file to wherever you wish. You can then open a Windows PowerShell console, navigate to the directory structure, and run the Start-PoshPAIG.ps1 script to start the utility.

No more double-clicking a system to run an operation

One of the first changes I made was the removal of double-clicking on a system in the server list to perform the specified operation. Instead of doing that, you can now right-click a system and bring up a shortcut menu to select a few different items, such as removing a server, viewing the WindowsUpdatelog.log, viewing installed updates and performing other operations against the remote system. Clicking Run in the shortcut menu will perform the specified operation that is designated below the server list (Audit, Install, Test Network Connection, or Reboot).

Image of shortcut menu that appears when right-clicking a system

Adding multiple computers using the Add Server menu

Originally, the Add Server menu only let you add one system at a time. While this is okay, I felt that it needed the ability to add more than one system at a time. So with that, I’ve made it so you can add more than one computer by separating the names with a comma. Simply right-click the server list window, click Add Server, type each system name, and then click OK.

The following figure shows the UI before clicking OK.

Image of UI before clicking OK

After clicking OK, the servers are then added to the server list, as shown in the following figure.

Image of UI after clicking OK

Support for operations against multiple systems at a time

One of my most requested features was the ability to perform the operations (audit, install, etc.) against multiple systems at a time instead of against only one system at a time. Doing this allows for a much quicker process of completing whichever operation that you decide to do; otherwise, the operation could take a much longer time than you would expect.

As you can see from another new feature—the Notes column—all the systems are being audited for patches that have been downloaded from the WSUS server. As each system is finished, it will be updated accordingly on the server list with the number of patches found. Depending on the operation you choose, the Notes column and other columns will be affected as well based on the decision. During these operations, if the system is not reachable on the network, the Notes column will report it as being offline.

Image of Notes column with Completed and Offline statuses

By default, the number of systems that will be run against at a time is 20. You can adjust this in the Start-PoshPAIG.ps1 script by modifying the $maxconcurrentjobs variable on line 37 to whatever you feel is an appropriate value.

Sort columns when clicked

Something that should have been in the first version but unfortunately was not as easy to implement as I would have thought (more on this in tomorrow’s post) was the ability to sort a column when clicked. So in this latest version, you can now sort a column by clicking it. The following figure shows sorting the Audited column so that the system with the most patches required is first.

Image of Audited column sorted by systems needing most patches at top


Tracked reboot of systems

Another option I added was the ability to send a reboot command to the remote systems; it will continue to monitor the system until it is back online. To avoid having too many systems being rebooted at one time, I have hard-coded a limit of five systems at a time to be rebooted. If a machine has not been reported as being back online within five minutes, it will be registered as being offline and will need more investigation into the system to see why it has not came back online.

To do this, first select the Reboot option below the server list, and you can choose to run the command against every system by clicking Run. Or you can run the command against a specific computer or computers by selecting them from the server list, right-clicking the server list, and then clicking Run.

Image of running command against specific computer

A warning is first presented advising the user that the computer will be rebooted if the user chooses to continue.

Image of reboot warning

Clicking Yes will continue the reboot process. When completed, you will see the Completed note in the Notes column or the Offline note.

Ping sweep

Another option implemented in version 1.6 is performing a “ping sweep” of all the systems in the server list. This is done by selecting the Test Network Connection check box, clicking Run or selecting the systems, and clicking Run from the menu when right-clicking the server list.

Image of testing network connection

The Notes column shows that the network check is occurring.

Image of results of network connection check

As you can see, two systems are online and the rest are offline. Note that the total time to perform this was just less than 13 seconds.

View WindowsUpdate.log for troubleshooting

I thought that this would be a nice and obvious addition to this utility. One big caveat is that this can only be run against one system at a time. Parsing and using Out-GridView to display the output against a file that could possibly contain several thousand lines of information would slow things down quite a bit. Just right-click a system, click WindowsUpdateLog in the shortcut menu, and then click one of the four options (Last 25, Last 50, Last 100, and Entire Log) to have the utility grab the remote log and display it.

Image of options for viewing WindowsUpdateLog

In this instance, I selected the last 50 lines from the WindowsUpdatelog.log to view.

Show currently installed updates

While not necessarily needed, I figured I would add an option to view the currently installed updates on one or more remote systems. Just select the systems, right-click Installed Updates, and then click View Installed Updates in the shortcut menu.

Image of View Installed Updates option

After all of the updates have been gathered, you can then view the installed updates on each system.

Image of viewing installed updates on each system


I hope everyone enjoyed this post displaying some of the new features of my latest project. This is a work in progress and will have more releases in the future. If you have any feature requests or any bugs that you find, be sure to log them in the Issue Tracker on CodePlex.

Tomorrow, I will address some issues I ran into while creating this utility and the steps I took to resolve them. I promise you will see some code in that post.


I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy



Comments (44)

  1. Boe Prox says:

    @aWp Thanks for the input and suggestion! I can certainly look into adding that into the UI.

    @John Currently PoshPAIG does not support the downloading of updates for a specific OS. I believe that feature was requested on the codeplex site, but if not, you can certainly use the issue tracker to request that feature and I will look into adding it.

    @jrv I appreciate the kind words regarding PoshPAIG. There was a lot of sweat, blood and tears spent working on this. But I am very happy with the results thus far.

    I'll keep my eyes open for your comments on codeplex, especially regarding the issue running the utility.

    I see what you are saying now regarding the updates. I would also recommend using WMI to install a patch if not coming from WSUS or another location.  Something I should have mentioned in this article and will be sure to update on the codeplex page is that the optimal environment for using this utility is that the systems should have their WU settings set to "download but do not install" either through Group Policy or Local Policy and have an internal WSUS server to approve specific patches for their environment. It will fine outside this environment, but this way a sys admin has complete control over what is being installed on their network.

  2. Oops.  Forgot to include the computername from listview.

    (gwmi win32_service -computername ($listview.selecteditems | %{$}) | ?{$ -match 'wuauserv'}).Restart()

  3. Boe Prox says:

    What version are you currently running? I know at one point there was a bug in the Audit code that listed updates which were available but had not yet downloaded which would give inaccurate numbers.

  4. Boe Prox says:

    The tool is still being supported. Can you provide more information on this? Do you see all of the patches during the audit but only one is installed? Any errors showing up?

  5. Boe Prox says:

    @arposh Absolutely! That is something that should have been in PoshPAIG already! 🙂 Thanks for the feature request!

  6. Boe Prox says:

    @Jose: Delete the options.xml file prior to running the utility. This will create a fresh file and you will no longer have the errors.

    @cchien_nguyen: What version of PoshPAIG are you running? I have made several UI changes to the utility since this article was published. I no longer use radio buttons and instead use combo boxes at the top of the utility along with a run button to perform the operations.

  7. jrv says:

    I understand the not installing a patch remotely. However, if you specify it to be downloaded and installed from WU/MU or WSUS you can trigger it remotely I believe.  It’s been a while since I did this but I seem to remember that that was the trick.

    Yes – you cannot just point at a package and install it. It has to be downloaded into the patch distribution folder and registered.  Only WU can do this.  If you do not have WSUS or the patch is not distributed by WU/MU then you would have to use either PsExec or WMI. I prefer WMI.

    I had some issues running the code but need to look at it more closely. I will post to Codeplex.

    It’s an amazing piece of scripting. You must have sweat bullets.  You also introduce a bunch of interesting techniques for coding Forms and complex programs. I will spend more time looking through you code. Thanks again.

  8. Boe Prox says:

    Thanks, JRV! Glad you like the utility I wrote. It’s been a fun learning process to work on something like this.

    The code you posted is actually very similar to what I use on the back-end to perform the queries for updates. I have just a couple of small changes as I want to be able to query for updates on remote systems.

    $c = "remoteserver"

    $updatesession =  [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$c))

    $updatesearcher = $updatesession.CreateUpdateSearcher()

    $searchresult = $updatesearcher.Search("IsInstalled=0")

    Your last statement has my attention:

    "Microsoft.Update does not require PsExec to install patches or to execute remotely."

    I’ve spent a bit of time researching this and some trial and error to make the installation work remotely with the COM object, but it is stated on the msdn site that remote execution of patch installations via the COM object is not allowed.…/aa386863%28v=VS.85%29.aspx

    I’ve tried using PowerShell remoting, creating a process remotely using WMI and a couple other ways that all ended in failure as the COM object can still see that a remote attempt is being used to try and install updates. I would be very interested if you
    found a way to utilize the COM object remotely without the need of an outside dependency to remotely install the updates.


  9. Anonymous says:

    Most Excellent!

  10. jrv says:

    That really nice Ed.  It is sort of a manual version of WSUS. There are a lot of admin out there who will go nuts or this thing.

  11. Boe Prox says:

    @Ashleyh Glad you like the utility! Are the servers on a domain or are they standalone systems? If domain, you can use an administrative account that has access to those systems to run the utility. Because of the way I currently have the utility coded, adding alternate credentials will take some time to work. But I do encourage you to log it in the Issue Tracker on the codeplex page.…/basic

    Also, if you wish we can continue this discussion on the discussion page on the site as well.

    Thanks again for comments regarding PoshPAIG!


  12. Any way you can add these options to control the Windows Update service by right-clicking on the server?

    (gwmi win32_service | ?{$ -match 'wuauserv'}).Stop()

    (gwmi win32_service | ?{$ -match 'wuauserv'}).Start()

    (gwmi win32_service | ?{$ -match 'wuauserv'}).Restart()

  13. Boe Prox says:

    I will have to take a look at this and see if I can reproduce the issue. Can you please file a bug here:

  14. jrv says:

    Now try it this way.  It does not require admin role to run queries.  You only need to elevate to run updates.  We can pick an individual update and download it from WU or WSUS or anywhere else.

    $wua=New-Object -ComObject Microsoft.Update.Session




    $results.Updates | select title

    Microsft.Update does not require PsExec to install patches or to execute remotely.

  15. aWp says:

    It would nice to have a column that said "Pending Reboot".  That way when you were running a post patch audit, you could pick up any systems you forgot to reboot.  Awesome work!

  16. John says:

    Nice, Is there a way to query updates based on the os and just download them so it would speed up the install process?

  17. Ashleyh says:

    Hello Boe

    -thanx for a great utility that will make instant querying much easier. Just a quick question?

    I have tested the Powershell GUI on one of my servers and it runs fine, but as soon as I run it against the remote servers, I get and 8007005 error? Anyway to get my login credentials changed in the script, when I attach to these remote servers?


  18. Klaus Schulte says:

    Hi Boe,


    Really awesome … being no admin I can't really test and use it in full detail.

    BUT: I'm very impressed by your code to make it work, which is an excellent learning resource and I can really believe that it was HARD work to get so far!

    THANKS, Klaus

  19. Jose says:

    I am getting this error?

    PS C:PoshPAIG_2_0_1> .Start-PoshPAIG.ps1

    Cannot index into a null array.

    At C:PoshPAIG_2_0_1Start-PoshPAIG.ps1:53 char:9

    +         $Global:maxConcurrentJobs = $Optionshash['MaxJobs']

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

       + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

       + FullyQualifiedErrorId : NullArray

    Cannot index into a null array.

    At C:PoshPAIG_2_0_1Start-PoshPAIG.ps1:54 char:9

    +         $Global:MaxRebootJobs = $Optionshash['MaxRebootJobs']

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

       + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

       + FullyQualifiedErrorId : NullArray

    Cannot index into a null array.

    At C:PoshPAIG_2_0_1Start-PoshPAIG.ps1:55 char:13

    +         If ($Optionshash['ReportPath']) {

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

       + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

       + FullyQualifiedErrorId : NullArray

  20. chien_nguyen says:

    hi gurus,

    Sorry a bit anoying you guys.

    I have tried and run but my interface didn't show any radio button such as audit patchees, Install patches, test network connection and reboot at the bottom.  Should I need to run script on wsus server or client PC.  Am I doing anything wrong or help me via Email

  21. Joel Rotich says:

    Need to add hotfix by browsing and push directly for installation. On version 2.1.5 I cannot see the GUI as above to do this task, am I missing something?

  22. guillermo says:

    The Best Tool for a SMB Admin that i've ever seen to patch windows server.


  23. Blaqjaq says:

    Hi Boe

    When truing to run the utility I am getting following string of error messages. Any chance for you word of advice?

    Add-Type : Could not load file or assembly 'PresentationFramework, Version=, Culture=neutral, PublicKeyToken=31b

    f3856ad364e35' or one of its dependencies. The system cannot find the file specified.

    At C:Documents and SettingsXPMUserdesktopPoshPAIG_2_1_5Start-PoshPAIG.ps1:50 char:9

    + Add-Type <<<<  -assemblyName PresentationFramework

       + CategoryInfo          : NotSpecified: (:) [Add-Type], FileNotFoundException

       + FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.AddTypeCommand

    Add-Type : Could not load file or assembly 'PresentationCore, Version=, Culture=neutral, PublicKeyToken=31bf3856

    ad364e35' or one of its dependencies. The system cannot find the file specified.

    At C:Documents and SettingsXPMUserdesktopPoshPAIG_2_1_5Start-PoshPAIG.ps1:51 char:9

    + Add-Type <<<<  -assemblyName PresentationCore

       + CategoryInfo          : NotSpecified: (:) [Add-Type], FileNotFoundException

       + FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.AddTypeCommand

    Add-Type : Could not load file or assembly 'WindowsBase, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364

    e35' or one of its dependencies. The system cannot find the file specified.

    At C:Documents and SettingsXPMUserdesktopPoshPAIG_2_1_5Start-PoshPAIG.ps1:52 char:9

    + Add-Type <<<<  -assemblyName WindowsBase

       + CategoryInfo          : NotSpecified: (:) [Add-Type], FileNotFoundException

       + FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.AddTypeCommand

    Unable to find type [Windows.Markup.XamlReader]: make sure that the assembly containing this type is loaded.

    At C:Documents and SettingsXPMUserdesktopPoshPAIG_2_1_5Start-PoshPAIG.ps1:1086 char:43

    + $uiHash.Window=[Windows.Markup.XamlReader] <<<< ::Load( $reader )

       + CategoryInfo          : InvalidOperation: (Windows.Markup.XamlReader:String) [], RuntimeException

       + FullyQualifiedErrorId : TypeNotFound

    You cannot call a method on a null-valued expression.

    At C:Documents and SettingsXPMUserdesktopPoshPAIG_2_1_5Start-PoshPAIG.ps1:1125 char:53

    + $uiHash.GenerateReportMenu = $uiHash.Window.FindName <<<< ("GenerateReportMenu")

       + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.

    At C:Documents and SettingsXPMUserdesktopPoshPAIG_2_1_5Start-PoshPAIG.ps1:1126 char:55

    + $uiHash.ClearAuditReportMenu = $uiHash.Window.FindName <<<< ("ClearAuditReportMenu")

       + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.

  24. jeremy says:

    Ran in to something with my test machine for this utility. I audited at 54 and when I selected run, it listed 1 under installed and then gave me "cscript.exe exited on (mycomputernamehere) with error code 0. Any ideas?

  25. RTL says:

    Love the idea of this code, and it generally works OK.

    I have downloaded 2.1.5

    HOWEVER – The right click options for WUAUCLT ‘Detect now’ and Windows Update Service ‘Stop service’ etc don’t work. it updates the bottom text description, and disables the run button, but doesn’t process the rest or update the computer notes. Nothing happens on the target machines

    Any ideas? Thanks.

  26. WhoDunnIt says:

    I run an Detect now on a fresh 7 box, and it finds 199 updates. When I run install updates. It says done quickly, and has not installed a single thing.

    What am I doing wrong?

  27. LMS says:

    Great post. Which ports we need to open if the local firewall is opened

  28. Wolfgang says:

    Hi great tool, I just found version 2.1.5. One patch worked pretty fine but now no more patches are installed.
    Are you still supporting this tool ?
    Regards Wolfgang

  29. Wolfgang says:

    @Boe Prox
    hopefully you got my email from 18th Nov

  30. ryans says:

    This is a great tool, nice work!

  31. Gary Caselman says:

    I have tried to run this multiple times and cannot get it to even launch. running on Win7-64bit with elevated permissions.???????

  32. Chetan G says:

    if i run Audit Patches, it give Error with Audit , if i run Check pending reboot, it gives "unable to determine reboot state"

  33. Stefan says:

    good afternoon,

    so far the tool is working great except two problems we encountered. as someone posted before already, when installing patches, it would only install one patch and then stays like that.

    also it doesn’t do anything when trying to open windowsupdate.log

    thanks for any help

  34. shail says:

    This is Nice Tool … 🙂
    Have 2 Queires —

    1- How to Install patches which were downloaded.
    2- Is firewall need to stop? or any specific port need to open in firewall.

    "Happy New Year 2015".

  35. Anand Nagarajan says: it possible exclude patches that we do not want. For example in my environment. I would only install Security patches and not application patches?

    How do I go about in fixing it?


  36. mano says:

    I’m running this script and I’m getting errors about non-existing methods EditItem at Start-PoshPAIG.ps1 :449 char48
    CommitEdit at Start-PoshPAIG.ps1 :451 char50
    EditItelm at Start-PoshPAIG.ps1 :9 char52
    and couple of more files containing this methods

  37. omdutt says:

    in my environment we are using SCCM to instal the patches so how can this utility can be used in that…..

  38. What am i doing wrong? says:

    Started Powershell as admin, copied the path to file. Enter. Unknown Command. ?!

  39. yusuf says:


    I can say amazing coding. I can see your hard work. Your UI is very nice and you use it perfectly.
    I am facing issue while running audit patches. Error code is given below.
    WARNING: Exception calling "Search" with "1" arguments : Exception from HRESULT: 0x80244018"

    Can you please advise what is wrong here?


  40. Jamesey says:

    fantastic tool, thanks so much!!!!

  41. blucero says:

    Cool Script with XML code.. Really Great Work!!!!!

  42. vinn says:

    hi, this is a lifesaver, one feature that would be nice is to send a flag to the last updated section of the servers so when looking at the "updates were installed" field, it shows when updates were done by this utility. currently I have servers that were
    updated yesterday running this script, however they only show the most recent updates done via manual updating.

  43. TheWintelGuy says:

    Hey Scripting Guy!, Got the app to run but I cant run queries on my servers, access denied.

    Any means of getting it to prompt for authentication?

    Thanks by the by, this will really help me out as We are still in the midst of deploying a patching system.

  44. Tim M. says:

    Hi I am trying to use this to verify patches are being properly installed on newly reimaged PC’s but so far every time I run an audit or try to view a list of installed updates I get nothing. is this tool able to run against Windows 7 /10 systems or is it only for Windows Servers?