I open PowerShell as admin and use the following line of code to run an offline file for windows updates. It works fine
Start-Process 'wusa.exe' -ArgumentList 'C:\Temp\windows10.0-kb5032189-x64_0a3b690ba3fa6cd69a2b0f989f273cfeadba745f.msu' -verb runas
But now I am trying to somehow use this same code to run the file on remote computers. The windows update file has the same name and the exact location on the remote PCs
I came up with this code below which first gets admin credentials and passes it to the the invoke-command. Then the invoke-command runs the Start-Process code.
$Username = 'username123'
$Password = '84fWfghnsf&5Fh'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
Invoke-Command -ComputerName 8HPF31J7V6.domain.local -Credential $Cred -ScriptBlock {Start-Process 'wusa.exe' -ArgumentList 'C:\Temp\windows10.0-kb5032189-x64_0a3b690ba3fa6cd69a2b0f989f273cfeadba745f.msu' -verb runas}
Problem is, when I do this, nothing happens on the remote PC
I also don't get any errors when running
Any ideas on what I am doing wrong, or any other solutions besides this?
Add -Wait
to your remote Start-Process
call to ensure that wusa.exe
runs to completion before returning from the remote Invoke-Command
call.
-ComputerName
parameter, the Start-Process
-launched process is automatically terminated when the Invoke-Command
call returns.Code executed via PowerShell's remoting runs invisibly on the target machines, so the use of -Verb RunAs
is pointless:
If the remote process already is elevated, it has no effect. Note that remote processes are automatically elevated if the user identity running the remote command is an administrator on the target machine.
If it isn't (this would only happen if you explicitly gave non-administrative users permission to use PowerShell remoting), the call invariably fails, because no UAC dialog can be presented.
Caveat:
While the information below in this answer is correct in principle, js2010 notes that in order to successfully run wusa.exe
remotely, i.e. in order to install Windows Updates, running in an implicitly elevated remote session alone may not be sufficient.
This ServerFault answer provides background information, and third-party module PSWindowsUpdate
may provide a solution, if used with its scheduling features.
Therefore, with synchronous execution:
# ... credential construction code ($Cred) omitted
# Note: If the *current user* is allowed to make remoting calls,
# you may not need to construct credentials and don't need the
# -Credential parameter below.
# Note the use of -Wait, removal of -Verb RunAs
Invoke-Command -ComputerName 8HPF31J7V6.domain.local -Credential $Cred -ScriptBlock {
Start-Process -Wait wusa.exe -ArgumentList 'C:\Temp\windows10.0-kb5032189-x64_0a3b690ba3fa6cd69a2b0f989f273cfeadba745f.msu'
}
Read on for an asynchronous alternative.
Note that the (Start-Process -PassThru …).ExitCode
technique shown below, for reporting the remote process' exit code, can equally be used with the synchronous approach above.
Asynchronous execution:
If you don't want the Invoke-Command
call to wait for the remotely launched process (wusa.exe
) to terminate, you have two options:
In the simplest case, add the -AsJob
switch to the call above, which makes Invoke-Command
return a job object that can be queried for output and completion later, on demand, with Receive-Job
and Wait-Job
, as shown below.
Create a remote session explicitly, via New-PSSession
, and pass it to Invoke-Command
's -Session
parameter. Such a session stays open until it is either explicitly removed with Remove-PSSession
or times out due to inactivity.
-Wait
with Start-Process
, and track the lifetime of the process in the remote session, by adding -PassThru
to output a process-information object that you must capture in a variable, and consult again in a later Invoke-Command
call with the same -Session
argument.Asynchronous variant with -AsJob
, which additionally demonstrates how to report the remote process' exit code:
# ... credential construction code omitted
# Note the use of -AsJob and the use of -PassThru with Start-Process
# so as to be able to report the process' exit code.
$remoteJob =
Invoke-Command -AsJob -ComputerName 8HPF31J7V6.domain.local -Credential $Cred -ScriptBlock {
(
Start-Process -Wait -PassThru wusa.exe -ArgumentList 'C:\Temp\windows10.0-kb5032189-x64_0a3b690ba3fa6cd69a2b0f989f273cfeadba745f.msu'
).ExitCode
}
# ... perform foreground activity here.
# Now wait for the remote job to complete - which happens when
# wusa.exe terminates - and report its exit code.
$exitCode =
$remoteJob | Receive-Job -Wait -AutoRemoveJob