I mentioned yesterday that one can Windows Update a machine via script located at c:\Windows\System32\en-US\WUA_SearchDownloadInstall.vbs
. It’s easy, just run via the following command on at machine:
1 |
cscript.exe c:\Windows\System32\en-US\WUA_SearchDownloadInstall.vbs |
I thought of taking it one step ahead and running on remote computers via PSExec. So I coped the script to the C:\ of all my servers (it’s only present in Server Core by default) and executed it via PSExec:
1 |
psexec \\my-server01 cscript.exe "c:\WUA_SearchDownloadInstall.vbs" |
That worked – sort of. I got a list of updates and I selected to download and install them all, but it just seemed to hang after that. I know the script (and even Windows Update GUI) is slow in general so I gave PsExec a long long time to complete, but that didn’t help.
Side by side I was searching for any PowerShell alternative to this script and came across this one. Compared to the VBScript technique it has an advantage (apart from being in PowerShell!) that I can control the “install updates” and “reboot” behaviors via switches. So all I needed to do was run something like this from a command-prompt window to install all available updates on a machine and then reboot:
1 |
powershell.exe c:\WSUS.ps1 y y |
Neato!
Thought I’d try run this remotely via PsExec but this time I got a lot of errors:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
Downloading Updates... Exception calling "CreateUpdateDownloader" with "0" argument(s): "Access is deni ed. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" At C:\WSUS.ps1:62 char:1 + $Downloader = $UpdateSession.CreateUpdateDownloader() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ComMethodTargetInvocation The property 'Updates' cannot be found on this object. Verify that the property exists and can be set. At C:\WSUS.ps1:63 char:1 + $Downloader.Updates = $UpdatesToDownload + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : PropertyNotFound You cannot call a method on a null-valued expression. At C:\WSUS.ps1:64 char:1 + $Null = $Downloader.Download() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull Installing Updates... Exception calling "CreateUpdateInstaller" with "0" argument(s): "Access is denie d. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" At C:\WSUS.ps1:90 char:5 + $Installer = $UpdateSession.CreateUpdateInstaller() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ComMethodTargetInvocation <snip> |
Looking more into this I came across an MSDN article about using Windows Update Agent (WUA) remotely. Turns out the CreateUpdateDownloader
method that’s erroring above – which from it’s name sounds like the method responsible for downloading updates – is not allowed to be called remotely. Looking at the VBScript too, it has a section like the below where it hangs, so that explains why I couldn’t run that script either remotely.
1 2 3 |
Set downloader = updateSession.CreateUpdateDownloader() downloader.Updates = updatesToDownload downloader.Download() |
I found some more PowerShell scripts that updates Windows machines – for example this and this. All of them use the same methods and so don’t work remotely. The blog post talking about the last script goes into more detail on an alternative method though. The trick is to create a scheduled task with the PowerShell script and run that on demand remotely. Since it runs locally, the PowerShell script will then succeed! I am yet to try it out but it seems like a reasonable workaround. Can deploy it via a GPO after all to all my machines.
From that post though I noticed the author creates the scheduled task as the LOCALSYSTEM
account. So I re-ran PsExec but this time told it to execute the command as the remote LOCALSYSTEM
account. And that worked! So now I can run a command like this
1 |
PsExec.exe \\my-server01 -s powershell.exe c:\WSUS.ps1 y y |
Or this
1 |
PsExec.exe \\my-server01 -s cscript c:\WUA_SearchDownloadInstall.vbs |
And am able to update a machine remotely. Nice! I prefer the PowerShell method as it lets me reboot the machine too without any prompt.