How To Clean Up WSUS

I recently added Windows 10 to my WSUS Product and Classifications and got very surprised by the 100 GB of updates that was queued for download! Let’s learn how to clean up WSUS content folder.

Unfortunately, cancelling the download queued is not that straight forward, so I decided to use the opportunity to clean up my WSUS content folder and reclaim my VMFS datastore at the same time.

The reason why the updates where 100 GB was because I had all Classifications selected and an Automatic Approval Rule! After the changes below the updates where only 1 GB.

Lesson Learned, Be Careful with Automatic Approval Rules…

Clean Up WSUS

Clean Up WSUS 01

Before you start make sure to disable your Automatic Approval Rule(s). I have a very nice script below that saved me 300% of downloads.

Clean Up WSUS 02

It’s also a good time to verify that only the Products and Languages you actually need are selected.

From Update Files and Languages, make sure that you don’t have Express installation files selected.

Clean Up WSUS 03

Let’s clean up WSUS by running the following commands:

Take a look in Task Manager and you’ll see that the process “SQL Server Windows NT – 64 bit” is consuming all the CPU. This is because all database tables are being checked and any missing hotfixes are being marked for download.

This could take up to 30-60 minutes to complete, depending on the Products and Classifications you have. When the CPU drops you’re ready to proceed.

Let’s start Synchronization.

Clean Up WSUS 07

The thing with WSUS is that it’s going to download everything, even superseded updates. Now the purpose of this post is to also reclaim VMFS storage, so downloading all and then deleting them won’t help much. Luckily there’s a script for that.

Open PowerShell ISE as Administrator and run the script.

Clean Up WSUS 09

WOW! Do you belive that? Out of 6467 updates, 4179 where declined.

Now run the Automatic Approval Rule to start the downloads.

Clean Up WSUS 10

Many people might argue that is unnecessary to run the wsusutil.exe reset command, simply because all updates will be re-downloaded.

Well, you could always search and decline all updates you don’t want and then run the Server Cleanup Wizard, but its PITA.

My WSUS folder went from 75 GB to 20 GB so I’m happy.

Reclaim VMFS Datastore

I’m not sure if you’re aware, but when you’re using Thin Provisioning it doesn’t matter if you delete unwanted files. When the space has been alllocated it will stay that way until you do the following steps below.

My WSUS folder was located on C: then moved to D: and finally E:

To reclaim the space after all unnecessary files has been deleted run sDelete on all volumes.

When finished shutdown the VM and connect to your ESXi host through Putty.

Navigate to your VMFS datastore folder for that VM.

Now run the following command for all disks:

Clean Up WSUS 04

Power up the VM and enjoy. I reclaimed 120 GB in 2 hours on just 1 VM!

Clean Up WSUS 05

Clean Up WSUS 06

Resource

63 Responses to How To Clean Up WSUS

  1. Hi
    thanks for the script however my server name has a hyphen “abc-def” and the script errors!

  2. Maybe this is obvious and I’m just being dense, but in the batch file what is the “echo Delete WSUS Folder Content” for? Am I supposed to manually delete this folder and then allow the batch file to continue?

  3. The script to decline the updates keeps failing. Getting this when trying to run it:

    Error Occurred
    Exception Message:
    The specified string is invalid.
    Parameter name: ServerName
    at Microsoft.UpdateServices.Administration.AdminProxy.CreateUpdateServer(Object[] args)
    at CallSite.Target(Closure , CallSite , RuntimeType , Object , Object , Object )

      • Still getting error

        Error Occurred
        Exception Message:
        The specified string is invalid.
        Parameter name: ServerName
        at Microsoft.UpdateServices.Administration.AdminProxy.CreateUpdateServer(Object[] args)
        at Microsoft.UpdateServices.Administration.AdminProxy.GetUpdateServer(String serverName, Boolean useSecureConnection, Int32 portNumber)
        at GetUpdateServer(Object , Object[] )
        at System.Management.Automation.MethodInformation.Invoke(Object target, Object[] arguments)
        at System.Management.Automation.DotNetAdapter.AuxiliaryMethodInvoke(Object target, Object[] arguments, MethodInformation methodInformation, Object[] originalArguments)

  4. Great post used it on a new WSUS setup. Before doing your steps I was it over 300 GB of updates. Redid the sever now only downloading 62 GB. Total Declined Updates: 3690

    Thanks

  5. it should be: “.\WsusUtil.exe reset” otherwise you get an error that it cannot find the program (“mistyped”)

  6. Does the script need to be run from the wsus server itself? or can you run it from another server? i am getting the same errors as Vivek

  7. Hi

    I am getting the below error when running the script:

    Exception calling “GetUpdates” with “1” argument(s): “The operation has timed out”
    At line:1 char:1
    + $u=$updateServer.GetUpdates($updatescope )
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : WebException

  8. Any idea why I am getting the above exception when running the script. Your answer is highly appreciated.

  9. I get the below error while running the script in the second box of the page. Any thoughts?

    Error Occurred
    Exception Message:
    Method invocation failed because [System.String] does not contain a method named ‘GetU
    pdates’.
    at CallSite.Target(Closure , CallSite , Object , Object )
    at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFra
    me frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(Int
    erpretedFrame frame)

  10. Hi, I cannot run this script normally, after running it about 2-3 mins it returns error, here is my result:

    <<>>
    Error Occurred
    Exception Message:
    要求已經中止: 作業逾時。 <

  11. Hi, I cannot run this script normally, after running it about 2-3 mins it returns error, here is my result:

    Connected sucessfully
    Error Occurred
    Exception Message:
    要求已經中止: 作業逾時。 (it means request has stopped: time out.)
    於 System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request
    )
    於 System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest req
    uest)
    於 Microsoft.UpdateServices.Internal.DatabaseAccess.ApiRemotingCompressionProxy.GetW
    ebResponse(WebRequest webRequest)
    於 System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Ob
    ject[] parameters)
    於 Microsoft.UpdateServices.Internal.ApiRemoting.ExecuteSPSearchUpdates(String updat
    eScopeXml, String preferredCulture, Int32 publicationState)
    於 Microsoft.UpdateServices.Internal.DatabaseAccess.AdminDataAccessProxy.ExecuteSPSe
    archUpdates(String updateScopeXml, String preferredCulture, ExtendedPublicationState p
    ublicationState)
    於 Microsoft.UpdateServices.Internal.BaseApi.Update.SearchUpdates(UpdateScope search
    Scope, ExtendedPublicationState publicationState, UpdateServer updateServer)
    於 CallSite.Target(Closure , CallSite , Object , Object )

    How can I solve this problem?

    • I am using the script unchanged and I too have the same problem on a 2012 R2 Server as follows:

      <<>>
      Error Occurred
      Exception Message:
      The operation has timed out
      at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request)
      at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
      at Microsoft.UpdateServices.Internal.DatabaseAccess.ApiRemotingCompressionProxy.GetWebResponse(WebRequest webRequest)

      at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
      at Microsoft.UpdateServices.Internal.ApiRemoting.ExecuteSPSearchUpdates(String updateScopeXml, String preferredCultur
      e, Int32 publicationState)
      at Microsoft.UpdateServices.Internal.DatabaseAccess.AdminDataAccessProxy.ExecuteSPSearchUpdates(String updateScopeXml
      , String preferredCulture, ExtendedPublicationState publicationState)
      at Microsoft.UpdateServices.Internal.BaseApi.Update.SearchUpdates(UpdateScope searchScope, ExtendedPublicationState p
      ublicationState, UpdateServer updateServer)
      at CallSite.Target(Closure , CallSite , Object , Object )

      Any Ideas?

      Kind regards,

      Chris

  12. Ok guys i had the same problem with the dash in the hostname,and made it work with your suggestion to evek.
    Thanks for the great post.

  13. i see a few techs having issues with server name….can you post on how you worked out the problem?

    • I ended up renaming my VM and it worked fine – I tried everything to get it to work with hyphenated host name and couldn’t

  14. I have not checked above solution , However Following command help me clean the WSUS server . Run all the command one by one – if you get any error like ” Invoke-WsusServerCleanup : Execution Timeout Expired.

    Re-run the command till it give you result. I cleaned up around 250 GB

    Invoke-WsusServerCleanup -CleanupUnneededContentFiles
    Invoke-WsusServerCleanup -DeclineExpiredUpdates
    Invoke-WsusServerCleanup -CleanupObsoleteComputers
    Invoke-WsusServerCleanup -CleanupObsoleteUpdates
    Invoke-WsusServerCleanup -CleanupUnneededContentFiles
    Invoke-WsusServerCleanup -CompressUpdates

  15. Hello,

    Thanks for the great infos and scripts but I’ve a question.

    When doing the procedure should not the Approved And Declined update get back to 0?

    In my case I still see the previous horrendous count of 6k approved and 7k declined.

    Did I do something wrong? When starting the service again I noticed the CPU climbing up but not for more than 5-6 minutes.

    Regards

  16. Hi, the PS script is not working for me:

    Error Occurred
    Exception Message:
    Invalid URI: The hostname could not be parsed.
    at Microsoft.UpdateServices.Administration.AdminProxy.CreateUpdateServer(Object[] args)
    at Microsoft.UpdateServices.Administration.AdminProxy.GetUpdateServer(String serverName, Boolean useSecureConnection, Int32 portNumber)
    at CallSite.Target(Closure , CallSite , RuntimeType , Object , Object , Object )
    Exception calling “GetUpdateServer” with “3” argument(s): “Invalid URI: The hostname could not be parsed.”
    At line:14 char:1
    + $updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateS …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : UriFormatException

    <<>>
    Error Occurred
    Exception Message:
    You cannot call a method on a null-valued expression.
    at CallSite.Target(Closure , CallSite , Object , Object )
    at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
    at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
    You cannot call a method on a null-valued expression.
    At line:20 char:1
    + $u=$updateServer.GetUpdates($updatescope )
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    OS: Windows Server 2012 R2

    HELP PLEASE!!!

  17. Hi,

    I’m confused on where exactly to run the script. I’ve done the reset.

    Pls help.

    Thanks.

  18. actually i was referring to the 2nd script
    #Change server name and port number and $True if it is on SSL

    I opened powershell and copy the whole thing and change the computer name but noting seems to happen…the whole 350GB data keep downloading after i cleared up the WSUS content folder

    • PS C:\Windows\system32> $updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($updateSer
      ver1,$useSecureConnection,$portNumber)
      Exception calling “GetUpdateServer” with “3” argument(s): “The specified string is invalid.
      Parameter name: ServerName”
      At line:1 char:1
      + $updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateS …
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : ArgumentException

      PS C:\Windows\system32>
      PS C:\Windows\system32> write-host “<<>>” -foregroundcolor “yellow”
      <<>>
      PS C:\Windows\system32>
      PS C:\Windows\system32> $updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
      PS C:\Windows\system32>
      PS C:\Windows\system32> $u=$updateServer.GetUpdates($updatescope )
      You cannot call a method on a null-valued expression.
      At line:1 char:1
      + $u=$updateServer.GetUpdates($updatescope )
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : InvalidOperation: (:) [], RuntimeException
      + FullyQualifiedErrorId : InvokeMethodOnNull

  19. If you get error:
    Error Occurred
    Exception Message:
    The specified string is invalid.
    Parameter name: ServerName

    Change line 4 to: $Computer = $env:ComputerName

  20. I have an issue with my WSUS server and I would love your advice. In an effort to clean up the server I selected the option under “Update Files and Languages” to “Do not store updates files locally; computers install from Microsoft Update”. Since the status has been “Cannot save configuration because the server is still processing a previous configuration change”. My plan was to set that option, run the cleanup wizard to purge the updates and then set it back to storing updates locally. It’s been over 24hrs and the status is the same. From what I’ve read there’s not a lot of ways to stop this. Ideas? Suggestions? Thanks!

  21. Hi Trond,

    I don’t mean to spam your blog post, but can I offer an alternative, and a much better, more user friendly way of cleaning out WSUS for your readers. It does way more than what you’re post says, and it’s so easy to setup and use.

    Have a peek at my Adamj Clean-WSUS script. It is the last WSUS Script you will ever need!

    http://community.spiceworks.com/scripts/show/2998-adamj-clean-wsus

    What it does:

    1. Add WSUS Index Optimization to the database to increase the speed of many database operations in WSUS by approximately 1000-1500 times faster.
    2. Remove all Drivers from the WSUS Database (Default; Optional).
    3. Shrink your WSUSContent folder’s size by declining multiple types of updates including by default any superseded updates, preview updates, expired updates, Itanium updates, and beta updates. Optional extras: Language Packs, IE7, IE8, IE9, IE10, Embedded, NonEnglishUpdates, ComputerUpdates32bit, WinXP.
    4. Remove declined updates from the WSUS Database.
    5. Clean out all the synchronization logs that have built up over time (configurable, with the default keeping the last 14 days of logs).
    6. Compress Update Revisions.
    7. Remove Obsolete Updates.
    8. Computer Object Cleanup (configurable, with the default of deleting computer objects that have not synced within 30 days).
    9. Application Pool Memory Configuration to display the current private memory limit and easily set it to any configurable amount including 0 for unlimited. This is a manual execution only.
    10. Checks to see if you have a dirty database, and if you do, fixes it. This is primarily for Server 2012 WSUS, and is a manual execution only.
    11. Run the Recommended SQL database Maintenance script on the actual SQL database.
    12. Run the Server Cleanup Wizard.

    It will email the report out to you or save it to a file, or both.

    Although the script is lengthy, it has been made to be super easy to setup and use so don’t over think it. There are some prerequisites and instructions at the top of the script. After installing the prerequisites and configuring the variables for your environment (email settings only if you are accepting all the defaults), simply run:

    .\Clean-WSUS.ps1 -FirstRun

    If you wish to view or increase the Application Pool Memory Configuration, or run the Dirty Database Check, you must run it with the required switch. See Get-Help .\Clean-WSUS.ps1 -Examples

    If you’re having trouble, there’s also a -HelpMe option that will create a log so you can send it to me for support.

  22. To resolve error with regards to Servername
    ——-
    Error Occurred
    Exception Message:
    The specified string is invalid.
    Parameter name: ServerName
    at Microsoft.UpdateServices.Administration.AdminProxy.CreateUpdateServer(Object[] args)
    at CallSite.Target(Closure , CallSite , Type , Object , Object , Object )

    ——-

    You need not change anything from the script. Just run it as is and run Windows Powershell ISE as Administrator. Running Windows Server 2012 R2.

    Thanks.

  23. I was having the same problem related to the hostname inside the PowerShell script. I have managed to solve it using:

    $Computer = “FULL_FQDN_HOSTNAME” (using quotation marks)

    Thanks for this great post!!!

  24. How do the script declining the updates take care of superseeded updates which is needed by some computers in my organization. Sorry for my inability to understand Powershell. I have understood that updates needed by a computer in my organisation should not be made inavailable.
    /Finn Knudsen

Leave a reply