1

I cannot work out how to pass arguments that contain folders with spaces using msdeploy.exe and PowerShell v4.

Sample Powershell Script

write-warning "WITHOUT SPACE"
$fl1 = "d:\nospace\a.txt"
$fl2 = "d:\nospace\b.txt"

$arg1 = "-source:filePath=`"$fl1`""
$arg2 = "-dest:filePath=`"$fl2`""

msdeploy.exe "-verb:sync",$arg1,$arg2

write-warning "WITH SPACE"
$fl1 = "d:\space space\a.txt"
$fl2 = "d:\space space\b.txt"

$arg1 = "-source:filePath=`"$fl1`""
$arg2 = "-dest:filePath=`"$fl2`""

msdeploy.exe "-verb:sync",$arg1,$arg2

When the folder name has no spaces, it works fine, however when it has a space it fails:

msdeploy.exe : Error: Unrecognized argument '"-source:filePath="d:\space'. All arguments must begin with "-".
At E:\PAWS\Payroll System\PES-Branch-FW\Publish\DeployPackage.ps1:253 char:9
+         msdeploy.exe "-verb:sync",$arg1,$arg2
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (Error: Unrecogn...begin with "-".:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

Error count: 1.

Manually calling msdeploy.exe using the following command:

msdeploy -verb:sync -source:filePath="d:\space space\a.txt" -dest:filePath="d:\space space\b.txt"

This works fine from Command Prompt but does not work from PowerShell.

I have used this blog as an aid but without any luck: http://trycatchfail.com/blog/post/The-trials-and-tribulations-of-using-MSDeploy-with-PowerShell.aspx

Update

I have looked into some more examples. If you perform a standard copy operation powershell is able to pass the path to cmd.exe (copy).

write-warning "WITHOUT SPACE"
$fl1 = "d:\nospace\a.txt"
$fl2 = "d:\nospace\b.txt"

$args = ('"{0}" "{1}"' -f $fl1, $fl2)
write-host $args
cmd /c copy $args

write-warning "WITH SPACE"
$fl1 = "d:\space space\a.txt"
$fl2 = "d:\space space\b.txt"

$args = ('"{0}" "{1}"' -f $fl1, $fl2)
write-host $args
cmd /c copy $args

Using the same approach to update the msdeploy snippet still fails because of the space.

write-warning "WITHOUT SPACE"
$fl1 = "d:\nospace\a.txt"
$fl2 = "d:\nospace\b.txt"

$arg1 = '-source:filePath="{0}"' -f $fl1
$arg2 = '-dest:filePath="{0}"' -f $fl2

$args = '-verb:sync',$arg1, $arg2
msdeploy.exe $args

write-warning "WITH SPACE"
$fl1 = "d:\space space\a.txt"
$fl2 = "d:\space space\b.txt"

$arg1 = '-source:filePath="{0}"' -f $fl1
$arg2 = '-dest:filePath="{0}"' -f $fl2

$args = '-verb:sync',$arg1, $arg2
msdeploy.exe $args

One Solution

https://stackoverflow.com/a/12813048/1497635

I would like to add that three escape characters is absolutely crazy. There must be a neater solution to the problem.

Community
  • 1
  • 1
civon
  • 300
  • 3
  • 11
  • Related: http://stackoverflow.com/questions/3499699/how-do-you-call-msdeploy-from-powershell-when-the-parameters-have-spaces?rq=1 Those suggestions did not help. – civon Aug 06 '14 at 06:08
  • Are you sure you need the comas in msdeploy.exe "-verb:sync",$arg1,$arg2 ? – David Brabant Aug 06 '14 at 06:36
  • It's an [System.Object[]] technically. Can build it using [System.Object[]]$args = "argument 1", "argument 2", "argument 3" Just chose to do it the way above to simplify. It was thrown together quickly to allow someone to re-produce it quickly. This issue may not have anything to do with MSDeploy itself but rather how PowerShell passes arguments to other processes like msdeploy.exe or even cmd.exe – civon Aug 06 '14 at 22:40
  • The path to MSDEPLOY.EXE needs to be added to Environment Variables for it to work: Path = C:\Program Files\IIS\Microsoft Web Deploy V3 – civon Aug 06 '14 at 22:58
  • An alternative, and more elegant, solution is offered by using [Web Deploy PowerShell Cmdlets](http://www.iis.net/learn/publish/using-web-deploy/web-deploy-powershell-cmdlets). And it also solves problems with output redirection that can be a pain to with Invoke-Expression, Start-Process and the Call/& operator. – JulianM Jan 09 '15 at 10:46

4 Answers4

3

I used the suggestion from the following: How do you call msdeploy from powershell when the parameters have spaces?

To derive a "cleaner" solution.

    $msdeploy = "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe";

    write-warning "WITHOUT SPACE"
    $fl1 = "d:\nospace\a.txt"
    $fl2 = "d:\nospace\b.txt"

    $md = $("`"{0}`" -verb:sync -source:filePath=`"{1}`" -dest:filePath=`"{2}`"" -f $msdeploy, $fl1, $fl2)
    cmd.exe /C "`"$md`""

    write-warning "WITH SPACE"
    $fl1 = "d:\space space\a.txt"
    $fl2 = "d:\space space\b.txt"

    $md = $("`"{0}`" -verb:sync -source:filePath=`"{1}`" -dest:filePath=`"{2}`"" -f $msdeploy, $fl1, $fl2)
    cmd.exe /C "`"$md`""
Community
  • 1
  • 1
civon
  • 300
  • 3
  • 11
  • 1
    Thank you! I've spent about a day online looking up a solution and this was the only one that worked. – Tor Jun 17 '15 at 15:52
3

When invoking commands PowerShell does some auto quoting that does not work well with MSDeploy. There are a couple of ways to avoid the auto quoting. One is to use the Start-Process cmdlet where you can specify the exact command line that you want but it can become a bit tedious to get the output of the new process to appear as output of the PowerShell script that you are running.

Another option is to use the --% specifier to turn off PowerShell parsing. However, doing that will not allow you to use variables in the command line because - well, parsing has been turned off. But you can get around this by using the Invoke-Expression cmdlet to first build the command line including the --% and whatever variables you want and then let PowerShell evaluate it:

$fl1 = "D:\space space\a.txt";
$fl2 = "D:\space space\b.txt";
$arguments = "-verb:sync -source:filePath=""$fl1"" -dest:filePath=""$fl2"""
$commandLine = 'msdeploy.exe --% ' + $arguments
Invoke-Expression $commandLine
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • Did you run your own code? MSDeploy does not care about quotes but if executed from powershell it does not work. Hence why the post. – civon Aug 11 '14 at 00:31
  • @civon: You are right that my initial answer was completely wrong. However, I have updated my answer with something that hopefully is more useful now. – Martin Liversage Aug 11 '14 at 06:54
  • 1
    Thank you. I confirmed that this script works. I like it as it is a lot easier to read than using that silly escape character. Just need to shift the quotes around $fl1 `-source:filePath=""$fl1""` – civon Aug 12 '14 at 05:22
1

I've found that this works:

$arguments=@(
"-verb:sync"
,"-source:metakey=lm/$IISSite,computername=$computer,includeAcls=true"
,"-dest:metakey=lm/w3svc/$DestSite"
,"-enableLink:appPool"
,"-allowUntrusted"
,"-skip:attributes.name=ServerBindings"
,"-skip:attributes.name=SecureBindings"
#,"-whatif"
)


Write-Output "Running MSDeploy with the following arguments"
$arguments
$logfile="Sync_$(get-date -format yyyyMMdd-HHmm).log"
Start-Process -FilePath "$msdeploy\msdeploy.exe" -ArgumentList $arguments -WorkingDirectory $msdeploy -RedirectStandardError "Error.txt" -RedirectStandardOutput $logfile -Wait -NoNewWindow
1

Found an easy solution. Ref: http://answered.site/all-arguments-must-begin-with--at-cwindowsdtldownloadswebserviceswebservicesidservicepublishedwebsitesidservicedeploymentidservicewsdeployps123/4231580/

$msdeploy = "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe"
$msdeployArgs = @(
"-verb:sync",
"-source:iisApp='Default Web Site/HelloWorld'",
"-verbose",
"-dest:archiveDir='c:\temp1'"
)
Start-Process $msdeploy -NoNewWindow -ArgumentList $msdeployArgs
vineel
  • 3,483
  • 2
  • 29
  • 33