I need to be able to run the following cmd command on a remote computer.
"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:package="\\Server\Share\Package.zip" -dest:auto,computerName=Server1
Powershells Invoke-Command looks promising but I cannot figure out how to pass the arguments to msdeploy.
I've tried
Invoke-Command -ComputerName RemoteServer1 -ScriptBlock { "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:package="\\Server\Share\Package.zip" -dest:auto,computerName=Server1 }
But it says "you must provide a value expression on the right-hand side of the '-' operator.". So I'm guessing the issue is the hyphens but I don't know how to escape them to make the command work.
Use &
to call external executable. Syntax: & "[path] command" [arguments]
.
Also note, that msdeploy supports alternate way of specifying arguments when called from PowerShell:
With a minor modification to its usual syntax, Web Deploy commands can be run from a Windows PowerShell prompt. To do this, change the colon character (:) after the verb, source, and dest arguments of the Web Deploy command to an equal sign (=). In the following example, compare the Web Deploy command with its PowerShell version.
Web Deploy command:
command: msdeploy -verb:sync -source:metakey=/lm/w3svc/1 -dest:metakey=/lm/w3svc/2 -verbose
PowerShell command:
.\msdeploy.exe -verb=sync -source=metakey=/lm/w3svc/1 -dest=metakey=/lm/w3svc/2 -verbose
Note, that arguments are wrapped in the array: this hints PowerShell how to pass them correctly to the target application.
Example:
Invoke-Command -ComputerName RemoteServer1 -ScriptBlock {&"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" @('-verb=sync', '-source=package="\\Server\Share\Package.zip"', '-dest=auto,computerName=Server1')}
From your comments I'm seeing that now PowerShell successfully runs msdeploy
on remote server, but msdeploy
can't access the remote share:
While the command executes, now msdeploy it saying:
"More Information: Object of type 'package' and path '\Server\Share\Package.zip' cannot be created. Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_EXCEPTION_WHILE_CREATING_OBJECT.
Error: The Zip package '\Server\Share\Package.zip' could not be loaded. Error: Access to the path '\Server\Share\Package.zip' is denied. Error count: 1."
Even though the user has access to the share (read/write).
That's because you actually trying to establish a remoting session from computer A (client) to computer B (server) and then from computer B, you trying to access the file in a share on computer C (\\Server\Share\Package.zip
).
Invoke-Command
fails because remote session tries to access the file share using the machine credentials instead of the credentials used to invoke the remote session. There is a way to pass or delegate credentials from the client so that we can authenticate to the file share. This is what is called multi-hop authentication and PowerShell remoting enables this using CredSSP.
To enable CredSSP, run those commands from elevated prompt:
On your PC: Enable-WSManCredSSP -Role Client -DelegateComputer
"TargetServer.FQ.DN"
DelegateComputer
parameter is used to specify the server or servers that receive the delegated credentials from the client. The DelegateComputer
accepts wildcards (*.FQ.DN
). You can also specify *
to specify all computers in the network.
On target server: Enable-WSManCredSSP -Role Server
Now, you should be able to run Invoke-Command
with CredSSP as the authentication method and pass the credentials:
Invoke-Command -ComputerName RemoteServer1 -Authentication Credssp -Credential Domain\Username -ScriptBlock {&"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" @('-verb=sync', '-source=package="\\Server\Share\Package.zip"', '-dest=auto,computerName=Server1')}
How would I go about having the server parameterized. If I have a parameter
$Server
as the server name, how would I go about putting that in as a replacement for the-dest=auto,computerName=Server1
part?
To pass arguments to a scriptblock, use ArgumentList
parameter:
$Servers = @('Server1', 'Server2', 'Server3')
$Command = {
Param($Srv)
&"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" @('-verb=sync', '-source=package="\\Server\Share\Package.zip"', "-dest=auto,computerName=$Srv")
}
$Servers |
ForEach-Object {
Invoke-Command -ComputerName RemoteServer1 -Authentication Credssp -Credential Domain\Username -ScriptBlock $Command -ArgumentList $_
}
And going further:
Нow would I go about adding extra parameters dynamically to the command. I need to add in
-skip:objectName=dirPath,absolutePath="<folder>"
to the arguments in the&"C:\Program Files\..."
line, for each folder in an array of strings.
If you have one set of folders to exclude for all servers:
$Servers = @('Server1', 'Server2', 'Server3')
$SkipPaths = @('C:\folder\to\skip1', 'C:\folder\to\skip2', 'C:\folder\to\skip3')
$SkipCmd = $SkipPaths | ForEach-Object {"-skip=objectName=dirPath,absolutePath=$_"}
$Command = {
Param($Srv, $Skp)
&"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" $(@('-verb=sync', '-source=package="\\Server\Share\Package.zip"', "-dest=auto,computerName=$Srv") + $Skp)
}
$Servers |
ForEach-Object {
Invoke-Command -ComputerName RemoteServer1 -Authentication Credssp -Credential Domain\Username -ScriptBlock $Command -ArgumentList ($_, $SkipCmd)
}
If you have different set of folders for each of servers:
$Servers = @{
Server1 = @('C:\folder\to\skip_1', 'C:\folder\to\skip_2', 'C:\folder\to\skip_3')
Server2 = @('C:\folder\to\skip_A', 'C:\folder\to\skip_B', 'C:\folder\to\skip_C')
Server3 = @('C:\folder\to\skip_X', 'C:\folder\to\skip_Y', 'C:\folder\to\skip_Z')
}
$Command = {
Param($Srv, $Skp)
&"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" $(@('-verb=sync', '-source=package="\\Server\Share\Package.zip"', "-dest=auto,computerName=$Srv") + $Skp)
}
$Servers.GetEnumerator() |
ForEach-Object {
$SkipCmd = $_.Value | ForEach-Object {"-skip=objectName=dirPath,absolutePath=$_"}
Invoke-Command -ComputerName RemoteServer1 -Authentication Credssp -Credential Domain\Username -ScriptBlock $Command -ArgumentList ($_.Key, $SkipCmd)
}