powershell sending multiple parameter to a external command - powershell

I am trying to run a external exe from a powershell script.
This exe wants 4 parameters.
I have been trying every combo of invoke-item, invoke-command, & 'C:\program files\mycmd.exe myparam', made a shortcut in C:\ to get rid of the spaces in the path.
I can make it work with one parameter, but not with more. I get various errors.
To sum up, how do you send 4 parameters to an exe?

It's best if shown in longhand. Once you see what's going on, you can shorten it down by just using commas between each argument.
$arg1 = "filename1"
$arg2 = "-someswitch"
$arg3 = "C:\documents and settings\user\desktop\some other file.txt"
$arg4 = "-yetanotherswitch"
$allArgs = #($arg1, $arg2, $arg3, $arg4)
& "C:\Program Files\someapp\somecmd.exe" $allArgs
... shorthand:
& "C:\Program Files\someapp\somecmd.exe" "filename1", "-someswitch", "C:\documents and settings\user\desktop\some other file.txt", "-yetanotherswitch"

In the easy case, passing arguments to a native exe is as simple as using a built-in command:
PS> ipconfig /allcompartments /all
You can run into problems when you specify a full path to an EXE and that path contains spaces. For example if PowerShell sees this:
PS> C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\sn.exe -k .\pubpriv.snk
It interprets the command to be "C:\Program" and "Files\Microsoft" as the first parameter, "SDKs\Windows\v7.0\Bin\sn.exe" as the second parameter, etc. The simple solution is to put the path in a string use the invocation operator & to invoke the command named by the path e.g.:
PS> & 'C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\sn.exe' -k .\pubpriv.snk
The next area we run into problems with is when the arguments are complex and/or use characters that PowerShell interprets specially e.g.:
PS> sqlcmd -v user="John Doe" -Q "select '$(user)' as UserName"
This doesn't work and we can debug this by using a tool from the PowerShell Community Extensions called echoargs.exe which shows you exactly how the native EXE receives the arguments from PowerShell.
PS> echoargs -v user="John Doe" -Q "select '$(user)' as UserName"
The term 'user' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, ...
<snip>
Arg 0 is <-v>
Arg 1 is <user=John Doe>
Arg 2 is <-Q>
Arg 3 is <select '' as UserName>
Note that with Arg3 $(user) is interpreted & evaluated by PowerShell and results in an empty string. You can fix this problem and a good number of similar issues by using single quotes instead of double qoutes unless you really need PowerShell to evaluate a variable e.g.:
PS> echoargs -v user="John Doe" -Q 'select "$(user)" as UserName'
Arg 0 is <-v>
Arg 1 is <user=John Doe>
Arg 2 is <-Q>
Arg 3 is <select $(user) as UserName>
If all else fails, use a here string and Start-Process like so:
PS> Start-Process echoargs -Arg #'
>> -v user="John Doe" -Q "select '$(user)' as UserName"
>> '# -Wait -NoNewWindow
>>
Arg 0 is <-v>
Arg 1 is <user=John Doe>
Arg 2 is <-Q>
Arg 3 is <select '$(user)' as UserName>
Note if you are using PSCX 1.2 you will need to prefix Start-Process like so - Microsoft.PowerShell.Management\Start-Process to use PowerShell's built-in Start-Process cmdlet.

Related

Pass Powershell Variables to Command Prompt line

I want to make a PowerShell script that can be used to connect computers to various client's SonicWall VPNs (specifically through Global VPN and NetExtender). I would like to have it be like a user interface to prompt the user (which will set the variables) and then use that information to pass through to command lines in the command prompt.
I want to be able to have information entered in be applied in the cmd line in the script.
I have tried using the MobileConnect connection through (Using the the app from the app store) and connecting with the Microsoft VPN client, but that does not grab all the network information; specifically DNS servers.
The best way is to install either Global VPN or NetExtender and connect through cmd line; that way will grab the entire network information.
This is the basic command to run it:
Function Connect-VPN {
Set-Location -Path "C:\Program Files (x86)\SonicWALL\SSL-VPN\NetExtender"
cmd /c "NECLI connect -s address:4433 -u Uname -p Password -d Domain -A"
Set-Location -Path C:\
}
Basically, you change the directory and execute the commands with those arguments.
I would like to prompt in POSH, create the variables with the user input, then have those arguments passed down.
What I have right now is:
param(
[string]$Testadd ,
[string]$Testun ,
[string]$TestPW ,
[string]$TestDom
)
If ($Testadd -eq "")
{$Testadd = (Read-Host "test")
}
If ($Testun -eq "")
{$Testun = (Read-Host "test")
}
If ($TestPW -eq "")
{$TestPW = (Read-Host "test")
}
If ($TestDom -eq "")
{$TestDom = (Read-Host "test")
}
Set-Location -Path "C:\Program Files (x86)\SonicWALL\SSL-VPN\NetExtender"
cmd /c "NECLI connect -s "$($Testadd)" -u "$($Testun)" -p "$($TestPW)" -d "$($TestDom)" -A"
Set-Location -Path C:\
The problem is that the all the arguments come out null. I do not know if it is possible, but I wanted to see.
You can try to build the string before running the cmd
param (
[string]$Testadd,
[string]$Testun,
[string]$TestPW,
[string]$TestDom
)
If ($Testadd -eq "")
{
$Testadd = (Read-Host "testadd")
}
If ($Testun -eq "")
{
$Testun = (Read-Host "testun")
}
If ($TestPW -eq "")
{
$TestPW = (Read-Host "testpw")
}
If ($TestDom -eq "")
{
$TestDom = (Read-Host "testdom")
}
Set-Location -Path "C:\Program Files (x86)\SonicWALL\SSL-VPN\NetExtender"
#build the string before
$cmd = "NECLI connect -s " + $($Testadd) + " -u " + $($Testun) + " -p " + $($TestPW) + " -d " + $($TestDom) + " -A"
# Or even like this
$cmd = "NECLI connect -s $Testadd -u $Testun -p $TestPW -d $TestDom -A"
# exec command
cmd /c $cmd
Set-Location -Path C:\
To add to #Desinternauta, I suspect it is how the command is interpreting the quotes and the variables. i.e. when you write out the string as you have it, it adds spaces:
$b = "b"
Write-Host "a"$($b)"c"
Outputs:
a b c
The good news is that double quoted strings allow you to embed the variables into the string:
cmd /c "NECLI connect -s $Testadd -u $Testun -p $TestPW -d $TestDom -A"
Calling external exe / commands that use cmd.exe, require special consideration and outing specifics. You also do not need to call cmd.exe directly, as that will just happen. This is a well documented this. For example:
PowerShell: Running Executables
The Call Operator &
Why: Used to treat a string as a SINGLE command. Useful for dealing
with spaces.
In PowerShell V2.0, if you are running 7z.exe (7-Zip.exe) or another
command that starts with a number, you have to use the command
invocation operator &.
The PowerShell V3.0 parser do it now smarter, in this case you don’t
need the & anymore .
Details: Runs a command, script, or script block. The call operator,
also known as the "invocation operator," lets you run commands that
are stored in variables and represented by strings. Because the call
operator does not parse the command,it cannot interpret command
parameters
# Example:
& 'C:\Program Files\Windows Media Player\wmplayer.exe' "c:\videos\my home video.avi" /fullscreen
Start-Process (start/saps)
Why: Starts a process and returns the .Net process object Jump if
-PassThru is provided. It also allows you to control the environment in which the process is started (user profile, output redirection
etc). You can also use the Verb parameter (right click on a file, that
list of actions) so thatyou can, for example, play a wav file.
Details: Executes a program returning the process object of the
application. Allows you to control the action on a file (verb
mentioned above) and control the environment in which the app is run.
You also have the ability to wait on the processto end. You can also
subscribe to the processes Exited event.
#Example:
#starts a process, waits for it to finish and then checks the exit code.
$p = Start-Process ping -ArgumentList "invalidhost" -wait -NoNewWindow -PassThru
$p.HasExited
$p.ExitCode
10. Stop-Parsing Symbol --%
Why: Its a quick way to handle program arguments that are not standard. Also its the new cool way to do it.
Details: The stop-parsing symbol (--%), introduced in Windows PowerShell 3.0, directs Windows PowerShell to refrain from interpreting input as Windows PowerShell commands or expressions. When calling an executable program in Windows PowerShell, placethe stop-parsing symbol before the program arguments.
After the stop-parsing symbol --% , the arguments up to the end of the line (or pipe, if you are piping) are passed as is.
#Examples:
# icacls in V2
# You must use escape characters to prevent PowerShell from misinterpreting the parentheses.
icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F
# In V3 you can use the stop-parsing symbol.
icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F
See also:
Using Windows PowerShell to run old command line tools (and their weirdest parameters)
Solve Problems with External Command Lines in PowerShell
Quoting
About Quoting Rules
A Story of PowerShell Quoting Rules

Run MSBuild from PowerShell can't find project file [duplicate]

I've just tested this on PowerShell v1.0. Setup is as follows:
Id CommandLine
-- -----------
1 $msbuild = "C:\Windows\Microsoft.NET\Framework\v3.5\msbuild.exe"
4 $a = "C:\some\project\or\other\src\Solution.sln /target:Clean /target:Build"
.
This line fails with an unintuitive error message:
Id CommandLine
-- -----------
5 & $msbuild $a
.
This line fails because & expects the first argument to be the command itself.
Id CommandLine
-- -----------
10 & "$msbuild $a"
.
This line works:
Id CommandLine
-- -----------
16 cmd /c "$msbuild $a"
.
Please explain. I'm more interested in why the & syntax isn't working, than an MSBuild-specific workaround.
Ugh.
$collectionOfArgs = #("C:\some\project\or\other\src\Solution.sln",
"/target:Clean", "/target:Build")
& $msbuild $collectionOfArgs
This works. & takes a collection of arguments, so you must split up strings containing multiple arguments into a collection of string arguments.
The issues you are seeing results from PowerShell parsing arguments. In the first example, when PowerShell sees $a it passes it as a single parameter msbuild. We can see this using the echoargs utility from PSCX:.
PS> $a = "C:\some\project\or\other\src\Solution.sln /target:Clean /target:Build"
PS> & echoargs $a
Arg 0 is <C:\some\project\or\other\src\Solution.sln /target:Clean /target:Build>
The second example is even worse because you are telling powershell to invoke "$echoargs $a" as the command name and it isn't a valid command name.
The third line works because CMD.exe gets the expanded form of "$echoargs $a" as a single argument which is parses and executes:
You have a couple of options here. First I do it this way:
PS> & $msbuild C:\some\project\or\other\src\Solution.sln `
/target:Clean /target:Build
The other option is to use Invoke-Expression like so:
PS> Invoke-Expression "$msbuild $a"
In general I try to be very careful with Invoke-Expression particularly if any part of the string that gets invoked is provided by the user.
You can also try using the free Invoke-MsBuild powershell script/module. This essentially gives you an Invoke-MsBuild PowerShell cmdlet that you can call instead of trying to invoke the msbuild.exe manually yourself.
That works well for me:
PS> cmd.exe /c 'C:\Windows\Microsoft.NET\Framework\v3.5\msbuild.exe' /target:Clean /target:Build 'C:\some\project\or\other\src\Solution.sln'

Powershell call msbuild with nested quotation marks

Using Powershell and Psake to create package and deployment for a visual studio solution.
Trying to deploy a database project using msbuild - which is working correctly using msdos visual studio command line
msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"
the same method call results in an error when called from powershell
& msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"
relating to spaces - can't figure out how to replicate this call in powershell - sample database connectionstring
Data Source=.\SQL2008;Initial Catalog=DocumentExecution;Integrated Security=True;
Short Version
How do you pass an argument containing quotes into a native command from PowerShell?
Use single quotes instead of double quotes in the argument string:
"/p:Target='Data Source=(local)\SQL;Integrated Security=True'"
→ /p:Target='Data Source=(local)\SQL;Integrated Security=True'
Use backslash-escaping for double quotes in the argument string∗:
'/p:Target=\"Data Source=(local)\SQL;Integrated Security=True\"'
→ /p:Target="Data Source=(local)\SQL;Integrated Security=True"
If the embedded quotes are only being used to treat the argument as a single string, rather than being a required part of the parameter, then the following can be used:
Quote the entire argument string, instead of embedding quotes in the argument:
'/p:Target=Data Source=(local)\SQL;Integrated Security=True'
→ /p:Target=Data Source=(local)\SQL;Integrated Security=True
Escape all PowerShell special characters with backticks∗ (this can only be done as an in-line argument):
/p:Target=`"Data Source=`(local`)\SQL`;Integrated Security=True`"
or /p:Target=Data` Source=`(local`)\SQL`;Integrated` Security=True
→ /p:Target=Data Source=(local)\SQL;Integrated Security=True
Full command line example (using the second alternative):
PS> [string[]]$arguments = #(
'/target:Deploy',
'/p:UseSandboxSettings=False',
'/p:TargetDatabase=UpdatedTargetDatabase',
'/p:TargetConnectionString=\"Data Source=(local)\SQL;Integrate Security=True\"',
'C:\program files\MyProjectName.dbproj'
)
PS> ./echoargs $arguments
Arg 0 is </target:Deploy>
Arg 1 is </p:UseSandboxSettings=False>
Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
Arg 3 is </p:TargetConnectionString="Data Source=(local)\SQL;Integrate Security=True">
Arg 4 is <C:\program files\MyProjectName.dbproj>
Long Version
Calling native commands is something that crops up quite a bit as folks move between the legacy cmd system and PowerShell (almost as much as the "separating parameters with commas" gotcha ;).
I've tried and sum up everything I know on the subject of command invocation in PowerShell (v2 and v3) here, along with all the examples and references I can muster.
1) Calling Native Commands Directly
1.1) At its simplest, for an executable located in the environment path, the command can be called directly, just as you would call a PowerShell cmdlet.
PS> Get-ItemProperty echoargs.exe -Name IsReadOnly
...
IsReadOnly : True
PS> attrib echoargs.exe
A R C:\Users\Emperor XLII\EchoArgs.exe
1.2) Outside of the environment path, for commands in a specific directory (including the current one), the full or relative path to the command can be used. The idea is to have the operator declare explicitly "I want to invoke this file", rather than let an arbitrary file that happened to have the same name get run in its place (see this question for more info on PowerShell security). Failing to use a path when it is required will result in a "term is not recognized" error.
PS> echoargs arg
The term 'echoargs' is not recognized as the name of a cmdlet, function, script file,
or operable program...
PS> ./echoargs arg
Arg 0 is <arg>
PS> C:\Windows\system32\attrib.exe echoargs.exe
A R C:\Users\Emperor XLII\EchoArgs.exe
1.3) If a path contains special characters, the call operator or escape character can be used. For example, an executable starting with a number, or located in a directory containing a space.
PS> $env:Path
...;C:\tools\;...
PS> Copy-Item EchoArgs.exe C:\tools\5pecialCharacter.exe
PS> 5pecialCharacter.exe special character
Bad numeric constant: 5.
PS> & 5pecialCharacter.exe special character
Arg 0 is <special>
Arg 1 is <character>
PS> `5pecialCharacter.exe escaped` character
Arg 0 is <escaped character>
PS> C:\Users\Emperor XLII\EchoArgs.exe path with spaces
The term 'C:\Users\Emperor' is not recognized as the name of a cmdlet, function,
script file, or operable program...
PS> & 'C:\Users\Emperor XLII\EchoArgs.exe' path with spaces
Arg 0 is <path>
Arg 1 is <with>
Arg 2 is <spaces>
PS> C:\Users\Emperor` XLII\EchoArgs.exe escaped` path with` spaces
Arg 0 is <escaped path>
Arg 1 is <with spaces>
2) Calling Native Commands Indirectly
2.1) When you are not typing out a command interactively, but instead have the path stored in a variable, the call operator can also be used to invoke the command named in a variable.
PS> $command = 'C:\Users\Emperor XLII\EchoArgs.exe'
PS> $command arg
Unexpected token 'arg' in expression or statement.
PS> & $command arg
Arg 0 is <arg>
2.2) The arguments passed to a command can also be stored in variables. Arguments in variables can be passed individually, or in an array. For variables containing spaces, PowerShell will automatically escape the spaces so that the native command sees it as a single argument. (Note that the call operator treats the first value as the command and the remaining values as arguments; the arguments should not be combined with the command variable.)
PS> $singleArg = 'single arg'
PS> $mushedCommand = "$command $singleArg"
PS> $mushedCommand
C:\Users\Emperor XLII\EchoArgs.exe single arg
PS> & $mushedCommand
The term 'C:\Users\Emperor XLII\EchoArgs.exe single arg' is not recognized as the
name of a cmdlet, function, script file, or operable program...
PS> & $command $singleArg
Arg 0 is <single arg>
PS> $multipleArgs = 'multiple','args'
PS> & $command $multipleArgs
Arg 0 is <multiple>
Arg 1 is <args>
2.3) The array format is especially useful for building up a dynamic list of arguments for a native command. For each argument to be recognized as a distinct parameter, it is important that the arguments get stored in an array variable, and not just munged together in one string. (Note that the common abbreviation $args is an automatic variable in PowerShell, which can cause values saved in it to get overwritten; instead, it is better to use a descriptive name like $msbuildArgs to avoid the naming conflict.)
PS> $mungedArguments = 'initial argument'
PS> $mungedArguments += 'second argument'
PS> $mungedArguments += $(if( $someVariable ) { 'dynamic A' } else { 'dynamic B' })
PS> ./echoargs $mungedArguments
Arg 0 is <initial argumentsecond argumentdynamic B>
PS> $arrayArguments = #('initial argument')
PS> $arrayArguments += 'second argument'
PS> $arrayArguments += $(if( $someVariable ) { 'dynamic A' } else { 'dynamic B' })
PS> ./echoargs $arrayArguments
Arg 0 is <initial argument>
Arg 1 is <second argument>
Arg 2 is <dynamic B>
2.4) Also, for scripts, functions, cmdlets, and the like, PowerShell v2 can send named arguments contained in a hashtable using a technique called "splatting", without having to worry about parameter order. This does not work with native commands, which do not participate in the PowerShell object model and can only handle string values.
PS> $cmdletArgs = #{ Path = 'EchoArgs.exe'; Name = 'IsReadOnly' }
PS> $cmdlet = 'Get-ItemProperty'
PS> & $cmdlet $cmdletArgs # hashtable object passed to cmdlet
Cannot find path 'C:\Users\Emperor XLII\System.Collections.Hashtable'...
PS> & $cmdlet #cmdletArgs # hashtable values passed to cmdlet
...
IsReadOnly : True
PS> ./echoargs #cmdletArgs
Arg 0 is <Name>
Arg 1 is <IsReadOnly>
Arg 2 is <Path>
Arg 3 is <EchoArgs.exe>
3) Calling Native Commands With Complicated Arguments
3.1) For simple arguments, the automatic escaping used for native commands is generally sufficient. However, for parenthesis, dollar signs, spaces, and such, characters used by PowerShell need to be escaped to be sent as-is to native commands, without having them interpreted by the parser. This can be done with the backtick escape character, `, or by putting the argument inside a single-quote string.
PS> ./echoargs money=$10.00
Arg 0 is <money=.00>
PS> ./echoargs money=`$10.00
Arg 0 is <money=$10.00>
PS> ./echoargs value=(spaces and parenthesis)
The term 'spaces' is not recognized as the name of a cmdlet, function, script file,
or operable program...
PS> ./echoargs 'value=(spaces and parenthesis)'
Arg 0 is <value=(spaces and parenthesis)>
3.2) Unfortunately, this is not so simple when double quotes are involved. As part of argument processing for native commands, the PowerShell processor attempts to normalize all double quotes in an argument so that the contents of the argument, sans quotes, is passed as a single value to the native command. The native command parameter processing occurs as a separate step after parsing, so normal escaping will not work for double quotes; only escaped single quotes, or backslash-escaped double quotes can be used.
PS> ./echoargs value="double quotes"
Arg 0 is <value=double quotes>
PS> ./echoargs 'value="string double quotes"'
Arg 0 is <value=string>
Arg 1 is <double>
Arg 2 is <quotes>
PS> ./echoargs value=`"escaped double quotes`"
Arg 0 is <value=escaped double quotes>
PS> ./echoargs 'value=\"backslash escaped double quotes\"'
Arg 0 is <value="backslash escaped double quotes">
PS> ./echoargs value='single quotes'
Arg 0 is <value=single quotes>
PS> ./echoargs "value='string single quotes'"
Arg 0 is <value='string single quotes'>
PS> ./echoargs value=`'escaped` single` quotes`'
Arg 0 is <value='escaped single quotes'>
3.3) PowerShell v3 added a new stop-parsing symbol --% (see about_Parsing). When used before complicated arguments, --% will pass arguments as-is without any parsing or variable expansion, except for cmd-like %ENVIRONMENT_VARIABLE% values.
PS> ./echoargs User:"$env:UserName" "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash>
PS> ./echoargs User: "$env:UserName" --% "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>
PS> ./echoargs --% User: "%USERNAME%" "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>
This can also be used to de-munge a single string representing multiple arguments, by passing the stop-parsing symbol in a string∗ (although the best practice is to not munge arguments in the first place).
PS> $user = 'User:"%USERNAME%"'
PS> $hash = 'Hash#' + $hashNumber
PS> $mungedArguments = $user,$hash -join ' '
PS> ./echoargs $mungedArguments
Arg 0 is <User:%USERNAME% Hash#555>
PS> ./echoargs --% $mungedArguments
Arg 0 is <$mungedArguments>
PS> ./echoargs '--%' $mungedArguments
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>
4) Debugging Native Commands
There are two key tools for debugging the arguments PowerShell passes to native commands.
4.1) The first is EchoArgs.exe, a console application from the PowerShell Community Extensions that simply writes back the arguments passed to it between angle brackets (as shown in the examples above).
4.2) The second is Trace-Command, a cmdlet that can show many details of how PowerShell processes a pipeline. In particular, the NativeCommandParameterBinder trace source will show what PowerShell receives and passes on to a native command.
PS> Trace-Command *NativeCommand* { ./echoargs value="double quotes" } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: "value=double quotes"
DEBUG: NativeCommandParameterBinder : Argument 0: value=double quotes
PS> Trace-Command *NativeCommand* { ./echoargs 'value="double quotes"' } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: "value="double quotes""
DEBUG: NativeCommandParameterBinder : Argument 0: value=double
DEBUG: NativeCommandParameterBinder : Argument 1: quotes
PS> Trace-Command *NativeCommand* { ./echoargs value=`"double quotes`" } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: value="double quotes"
DEBUG: NativeCommandParameterBinder : Argument 0: value=double quotes
PS> Trace-Command *NativeCommand* { ./echoargs 'value=\"double quotes\"' } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: "value=\"double quotes\""
DEBUG: NativeCommandParameterBinder : Argument 0: value="double quotes"
Other Resources
Articles
2012-01-02 - PowerShell V3 CTP2 Provides Better Argument Passing to EXEs
2011-03-10 - The problem with calling legacy/native apps from PowerShell
2010-11-04 - Escaping Spaces
2010-02-01 - The trials and tribulations of using MSDeploy with PowerShell
2008-10-17 - Executing commands which require quotes and variables is practically impossible [Connect]
2006-05-15 - Cannot enter an argument containing double quotes [Connect]
Questions
2013-09-11 - powershell executing external command not accepting parameter
2013-02-20 - Parameters with double quotes are not properly passed to Scriptblock by ArgumentList
2013-01-02 - ERROR: Description = Invalid query
2012-09-18 - How can I execute an external program with parameters in PowerShell?
2012-09-10 - Invoke executable (w/parameters) from powershell script
2012-08-16 - How do I pass a property value containing a semicolon on the MSBuild command line when running it from PowerShell?
2012-08-08 - Call ruby script from powershell
2012-08-01 - Brackets or quotation marks breaking a powershell command
2012-07-13 - Problems using powershell to perform a source safe get by label
2012-06-13 - Missing argument -m using svn at windows powershell
2012-06-01 - Powershell command line argument with spaces and curly brackets?
2012-04-18 - Spaced paths, msbuild, and psake
2012-04-12 - Make Power shell ignore semicolon
2012-03-08 - Simple Powershell Msbuild with parameter fails
2012-02-10 - Quote Madness in Powershell
2012-01-18 - Powershell: run msiexec with dynamically created parameters
2012-01-18 - PowerShell's call operator (&) syntax and double-quotes
2012-01-16 - PowerShell - passing calculated paths with spaces
2012-01-09 - powershell: script to start a program with parameters?
2011-12-20 - Powershell - calling icacls with parantheses included in parameters
2011-12-15 - Msbuild log doesn't work when executed through powershell
2011-12-06 - Pass parameters to InstallUtil from Powershell
2011-11-23 - Executing an exe with arguments using Powershell
2011-11-08 - Powershell remove quotes when start process
2011-09-16 - Commands executed in PowerShell with variables surrounded in quotes fail. Why?
2011-07-25 - Powershell parsing quotes strangely (includes a short analysis of quote parsing in one of the answers)
2011-07-15 - powershell stripping double quotes from command line arguments
2011-06-14 - In Powershell, how do you execute an arbitrary native command from a string?
2011-06-03 - Powershell call msbuild with nested quotation marks
2011-05-13 - powershell - passing parameters to exe
2011-03-02 - Why does this PowerShell script fail to execute this external command properly?
2011-01-09 - Executing an EXE file using powershell script
2010-12-13 - Command-line arguments to an exe
2010-10-08 - What is up with this PowerShell command line quoting/escaping?
2010-10-05 - Running an exe using powershell from a directory with spaces in it
2010-08-28 - Executing a Command stored in a Variable from Powershell
2010-08-17 - How do you call msdeploy from powershell when the parameters have spaces?
2010-04-12 - How to suppress quotes in Powershell commands to executables
2010-01-26 - powershell sending multiple parameter to a external command
2009-11-04 - How to run exe in powershell with parameters with spaces and quotes
2009-03-16 - PowerShell - Start-Process and Cmdline Switches
2009-01-14 - How to escape command line arguments on Powershell?
This could all be made a lot easier if you used the Start-Process cmdlet with the -ArgumentList parameter. I'm surprised that this hasn't been mentioned already.
Example:
Start-Process -FilePath msbuild.exe -ArgumentList '/target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"';
Here's a method I like to use a bit better, which allows for variable substitution:
$ConnectionString = 'aConnectionWithSpacesAndSemiColons';
$DatabaseProjectPath = 'aDatabaseProjectPathWithSpaces';
$MsbuildArguments = '/target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="{0}" "{1}"' -f $ConnectionString, $DatabaseProjectPath;
Start-Process -FilePath msbuild.exe -ArgumentList $MsbuildArguments;
Put the whole parameter in single quotes:
& msbuild /target:Deploy /p:UseSandboxSettings=false '/p:TargetConnectionString="aConnectionWithSpacesAndSemiColons"' "aDatabaseProjectPathWithSpaces"
The extra level of quoting will mean that PSH doesn't process the content with PSH's rules. (Any single quotes inside the string need to be doubled up—this is the only type of escaping in a PSH single quoted string).
#Richard - Testing this generates a different error saying that no valid project file is provided.
I've run this through echoargs pscx helper to show some more detailed examples.
With single quoatation marks wrapping the TargetConnectionString - Powershell evaluates each space in the connectionstring as a new line:
& echoargs /target:Deploy /p:UseSandboxSettings=false /p:TargetDatabase=UpdatedTargetDatabase /p:TargetConnectionString='"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"' "C:\program files\MyProjectName.dbproj"
Arg 0 is </target:Deploy>
Arg 1 is </p:UseSandboxSettings=false>
Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
Arg 3 is </p:TargetConnectionString=Data>
Arg 4 is <Source=(local)\SQLEXPRESS;Integrated>
Arg 5 is <Security=True;Pooling=False>
Arg 6 is <C:\program files\MyProjectName.dbproj>
Separating each parameter with backticks recreates the initial problem = no quotation marks around the connectionstring:
& echoargs /target:Deploy `
/p:UseSandboxSettings=false `
c
/p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"
"C:\program files\MyProjectName.dbproj"
Arg 0 is </target:Deploy>
Arg 1 is </p:UseSandboxSettings=false>
Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
Arg 3 is </p:TargetConnectionString=Data Source=(local)\SQLEXPRESS;Integrated Se
curity=True;Pooling=False>
Arg 4 is <C:\program files\MyProjectName.dbproj>
Adding backticks to quotation marks behaves the same as example 1:
& echoargs /target:Deploy `
/p:UseSandboxSettings=false `
/p:TargetDatabase=UpdatedTargetDatabase `
"/p:TargetConnectionString=`"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"`" `
"C:\program files\MyProjectName.dbproj"
Using the # operator to try to split the parameters still ignores the quotes:
$args = #('/target:Deploy','/p:UseSandboxSettings=false',' /p:TargetDatabase=UpdatedTargetDatabase','/p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"','C:\program files\MyProjectName.dbproj'); $args
/target:Deploy
/p:UseSandboxSettings=false
/p:TargetDatabase=UpdatedTargetDatabase
/p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"
C:\program files\MyProjectName.dbproj
& echoargs $args
Backticks to escape the connectionstring using line separators - same results as example 1:
& echoargs /target:Deploy `
/p:UseSandboxSettings=false `
/p:TargetDatabase=UpdatedTargetDatabase `
"/p:TargetConnectionString=`"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"`" `
"C:\program files\MyProjectName.dbproj"
Your problem is that PowerShell does not escape quotes when it passes them to command line applications. I ran into this myself and thought that PowerShell was eating the quotes. Just do this.
msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetDatabase=UpdatedTargetDatabase '/p:TargetConnectionString=\"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False\"' "C:\program files\MyProjectName.dbproj"
Thanks to JohnF's answer, I was able to figure this one out, finally.
echoargs /target:clean`;build`;deploy /p:UseSandboxSettings=false /p:TargetConnectionString=`"Data
Source=.`;Integrated Security=True`;Pooling=False`" .\MyProj.dbproj
Arg 0 is </target:clean;build;deploy>
Arg 1 is </p:UseSandboxSettings=false>
Arg 2 is </p:TargetConnectionString=Data Source=.;Integrated Security=True;Pooling=False>
Arg 3 is <.\MyProj.dbproj>
In short, but backticks in front of the double quotes AND the semicolons. Anything less (or more!) will screw it up.
It's mentioned in the Articles from this answer, but with PowerShell 3 you can use --% to stop the normal parsing PowerShell does.
msbuild --% /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"

How to run an EXE file in PowerShell with parameters with spaces and quotes

How do you run the following command in PowerShell?
C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"
When PowerShell sees a command starting with a string it just evaluates the string, that is, it typically echos it to the screen, for example:
PS> "Hello World"
Hello World
If you want PowerShell to interpret the string as a command name then use the call operator (&) like so:
PS> & 'C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe'
After that you probably only need to quote parameter/argument pairs that contain spaces and/or quotation chars. When you invoke an EXE file like this with complex command line arguments it is usually very helpful to have a tool that will show you how PowerShell sends the arguments to the EXE file. The PowerShell Community Extensions has such a tool. It is called echoargs. You just replace the EXE file with echoargs - leaving all the arguments in place, and it will show you how the EXE file will receive the arguments, for example:
PS> echoargs -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass
Arg 0 is <-verb:sync>
Arg 1 is <-source:dbfullsql=Data>
Arg 2 is <Source=mysource;Integrated>
Arg 3 is <Security=false;User>
Arg 4 is <ID=sa;Pwd=sapass!;Database=mydb;>
Arg 5 is <-dest:dbfullsql=Data>
Arg 6 is <Source=.\mydestsource;Integrated>
Arg 7 is <Security=false;User>
Arg 8 is <ID=sa;Pwd=sapass!;Database=mydb; computername=10.10.10.10 username=administrator password=adminpass>
Using echoargs you can experiment until you get it right, for example:
PS> echoargs -verb:sync "-source:dbfullsql=Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;"
Arg 0 is <-verb:sync>
Arg 1 is <-source:dbfullsql=Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;>
It turns out I was trying too hard before to maintain the double quotes around the connection string. Apparently that isn't necessary because even cmd.exe will strip those out.
BTW, hats off to the PowerShell team. They were quite helpful in showing me the specific incantation of single & double quotes to get the desired result - if you needed to keep the internal double quotes in place. :-) They also realize this is an area of pain, but they are driven by the number of folks are affected by a particular issue. If this is an area of pain for you, then please vote up this PowerShell bug submission.
For more information on how PowerShell parses, check out my Effective PowerShell blog series - specifically item 10 - "Understanding PowerShell Parsing Modes"
UPDATE 4/4/2012: This situation gets much easier to handle in PowerShell V3. See this blog post for details.
I had spaces in both command and parameters, and this is what worked for me:
$Command = "E:\X64\Xendesktop Setup\XenDesktopServerSetup.exe"
$Parms = "/COMPONENTS CONTROLLER,DESKTOPSTUDIO,DESKTOPDIRECTOR,LICENSESERVER,STOREFRONT /PASSIVE /NOREBOOT /CONFIGURE_FIREWALL /NOSQL"
$Parms = $Parms.Split(" ")
& "$Command" $Parms
It's basically the same as Akira's answer, but this works if you dynamically build your command parameters and put them in a variable.
Just add the & operator before the .exe name.
Here is a command to install SQL Server Express in silence mode:
$fileExe = "T:\SQLEXPRADV_x64_ENU.exe"
$CONFIGURATIONFILE = "T:\ConfSetupSql2008Express.ini"
& $fileExe /CONFIGURATIONFILE=$CONFIGURATIONFILE
There are quite a few methods you can use to do it.
There are other methods like using the Call Operator (&), Invoke-Expression cmdlet etc. But they are considered unsafe. Microsoft recommends using Start-Process.
Method 1
A simple example
Start-Process -NoNewWindow -FilePath "C:\wamp64\bin\mysql\mysql5.7.19\bin\mysql" -ArgumentList "-u root","-proot","-h localhost"
In your case
Start-Process -NoNewWindow -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync","-source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`"","-dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`"","computername=10.10.10.10","username=administrator","password=adminpass"
In this method you separate each and every parameter in the ArgumentList using commas.
Method 2
Simple Example
Start-Process -NoNewWindow -FilePath "C:\wamp64\bin\mysql\mysql5.7.19\bin\mysql" -ArgumentList "-u root -proot -h localhost"
In your case
Start-Process -NoNewWindow -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync -source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`" -dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`",computername=10.10.10.10,username=administrator,password=adminpass"
This method is easier as it allows to type your parameters in one go.
Note that in powershell to represent the quotation mark ( " ) in a string you should insert the grave accent ( ` ) (This is the key above the Tab key in the US keyboard).
-NoNewWindow
parameter is used to display the new process in the current console window. By default Windows PowerShell opens a new window.
References : Powershell/Scripting/Start-Process
This worked for me:
& 'D:\Server\PSTools\PsExec.exe' #('\\1.1.1.1', '-accepteula', '-d', '-i', $id, '-h', '-u', 'domain\user', '-p', 'password', '-w', 'C:\path\to\the\app', 'java', '-jar', 'app.jar')
Just put paths or connection strings in one array item and split the other things in one array item each.
There are a lot of other options here: https://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx
Microsoft should make this way simpler and compatible with command prompt syntax.
In case somebody is wondering how to just run an executable file:
..... > .\file.exe
or
......> full\path\to\file.exe
See this page:
https://slai.github.io/posts/powershell-and-external-commands-done-right/
Summary using vshadow as the external executable:
$exe = "H:\backup\scripts\vshadow.exe"
&$exe -p -script=H:\backup\scripts\vss.cmd E: M: P:
You can use:
Start-Process -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"
The key thing to note here is that FilePath must be in position 0, according to the Help Guide. To invoke the Help guide for a commandlet, just type in Get-Help <Commandlet-name> -Detailed . In this case, it is Get-Help Start-Process -Detailed.
I was able to get my similar command working using the following approach:
msdeploy.exe -verb=sync "-source=dbFullSql=Server=THESERVER;Database=myDB;UID=sa;Pwd=saPwd" -dest=dbFullSql=c:\temp\test.sql
For your command (not that it helps much now), things would look something like this:
msdeploy.exe -verb=sync "-source=dbfullsql=Server=mysource;Trusted_Connection=false;UID=sa;Pwd=sapass!;Database=mydb;" "-dest=dbfullsql=Server=mydestsource;Trusted_Connection=false;UID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass
The key points are:
Use quotes around the source argument, and remove the embedded quotes around the connection string
Use the alternative key names in building the SQL connection string that don't have spaces in them. For example, use "UID" instead of "User Id", "Server" instead of "Data Source", "Trusted_Connection" instead of "Integrated Security", and so forth. I was only able to get it to work once I removed all spaces from the connection string.
I didn't try adding the "computername" part at the end of the command line, but hopefully this info will help others reading this now get closer to their desired result.
New escape string in PowerShell V3, quoted from New V3 Language Features:
Easier Reuse of Command Lines From Cmd.exe
The web is full of command lines written for Cmd.exe. These commands lines work often enough in PowerShell, but when they include certain characters, for example, a semicolon (;), a dollar sign ($), or curly braces, you have to make some changes, probably adding some quotes. This seemed to be the source of many minor headaches.
To help address this scenario, we added a new way to “escape” the parsing of command lines. If you use a magic parameter --%, we stop our normal parsing of your command line and switch to something much simpler. We don’t match quotes. We don’t stop at semicolon. We don’t expand PowerShell variables. We do expand environment variables if you use Cmd.exe syntax (e.g. %TEMP%). Other than that, the arguments up to the end of the line (or pipe, if you are piping) are passed as is. Here is an example:
PS> echoargs.exe --% %USERNAME%,this=$something{weird}
Arg 0 is <jason,this=$something{weird}>
I use this simple, clean and effective method.
I place arguments in an array, 1 per line. This way it is very easy to read and edit.
Then I use a simple trick of passing all arguments inside double quotes to a function with 1 single parameter. That flattens them, including arrays, to a single string, which I then execute using PS's 'Invoke-Expression'. This directive is specifically designed to convert a string to runnable command.
Works well:
# function with one argument will flatten
# all passed-in entries into 1 single string line
Function Execute($command) {
# execute:
Invoke-Expression $command;
# if you have trouble try:
# Invoke-Expression "& $command";
# or if you need also output to a variable
# Invoke-Expression $command | Tee-Object -Variable cmdOutput;
}
# ... your main code here ...
# The name of your executable app
$app = 'my_app.exe';
# List of arguments:
# Notice the type of quotes - important !
# Those in single quotes are normal strings, like 'Peter'
$args = 'arg1',
'arg2',
$some_variable,
'arg4',
"arg5='with quotes'",
'arg6',
"arg7 \ with \ $other_variable",
'etc...';
# pass all arguments inside double quotes
Execute "$app $args";
I tried all of the suggestions but was still unable to run msiexec.exe with parameters that contained spaces. So my solution ended up using System.Diagnostics.ProcessStartInfo:
# can have spaces here, no problems
$settings = #{
CONNECTION_STRING = "... ..."
ENTITY_CONTEXT = "... ..."
URL = "..."
}
$settingsJoined = ($settings.Keys | % { "$_=""$($settings[$_])""" }) -join " "
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.WorkingDirectory = $ScriptDirectory
$pinfo.FileName = "msiexec.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "/l* install.log /i installer.msi $settingsJoined"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$stdout = $p.StandardOutput.ReadToEnd()
$p.WaitForExit()
You can run exe files in powershell different ways. For instance if you want to run unrar.exe and extract a .rar file you can simply write in powershell this:
$extract_path = "C:\Program Files\Containing folder";
$rar_to_extract = "C:\Path_to_arch\file.rar"; #(or.exe if its a big file)
C:\Path_here\Unrar.exe x -o+ -c- $rar_to_extract $extract_path;
But sometimes, this doesn't work so you must use the & parameter as shown above:
For instance, with vboxmanage.exe (a tool to manage virtualbox virtual machines) you must call the paramterers outside of the string like this, without quotes:
> $vmname = "misae_unrtes_1234123"; #(name too long, we want to change this)
> & 'C:\Program Files\Oracle\VirtualBox\VBoxManage.exe' modifyvm $vmname --name UBUNTU;
If you want to call simply a winrar archived file as .exe files, you can also unzip it with the invoke-command cmdlet and a Silent parameter /S (Its going to extract itself in the same folder than where it has been compressed).
> Invoke-Command -ScriptBlock { C:\Your-path\archivefile.exe /S };
So there are several ways to run .exe files with arguments in powershell.
Sometimes, one must find a workaround to make it work properly, which can require some further effort and pain :) depending on the way the .exe has been compiled or made by its creators.
Cmd can handle running a quoted exe, but Powershell can't. I'm just going to deal with running the exe itself, since I don't have it. If you literally need to send doublequotes to an argument of an external command, that's another issue that's been covered elsewhere.
1) add the exe folder to your path, maybe in your $profile
$env:path += ';C:\Program Files\IIS\Microsoft Web Deploy\'
msdeploy
2) backquote the spaces:
C:\Program` Files\IIS\Microsoft` Web` Deploy\msdeploy.exe
This worked for me:
PowerShell.exe -Command "& ""C:\Some Script\Path With Spaces.ps1"""
The key seems to be that the whole command is enclosed in outer quotes, the "&" ampersand is used to specify another child command file is being executed, then finally escaped (doubled-double-) quotes around the path/file name with spaces in you wanted to execute in the first place.
This is also completion of the only workaround to the MS connect issue that -File does not pass-back non-zero return codes and -Command is the only alternative. But until now it was thought a limitation of -Command was that it didn't support spaces. I've updated that feedback item too.
http://connect.microsoft.com/PowerShell/feedback/details/750653/powershell-exe-doesn-t-return-correct-exit-codes-when-using-the-file-option
An alternative answer is to use a Base64 encoded command switch:
powershell -EncodedCommand "QwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEkASQBTAFwATQBpAGMAcgBvAHMAbwBmAHQAIABXAGUAYgAgAEQAZQBwAGwAbwB5AFwAbQBzAGQAZQBwAGwAbwB5AC4AZQB4AGUAIAAtAHYAZQByAGIAOgBzAHkAbgBjACAALQBzAG8AdQByAGMAZQA6AGQAYgBmAHUAbABsAHMAcQBsAD0AIgBEAGEAdABhACAAUwBvAHUAcgBjAGUAPQBtAHkAcwBvAHUAcgBjAGUAOwBJAG4AdABlAGcAcgBhAHQAZQBkACAAUwBlAGMAdQByAGkAdAB5AD0AZgBhAGwAcwBlADsAVQBzAGUAcgAgAEkARAA9AHMAYQA7AFAAdwBkAD0AcwBhAHAAYQBzAHMAIQA7AEQAYQB0AGEAYgBhAHMAZQA9AG0AeQBkAGIAOwAiACAALQBkAGUAcwB0ADoAZABiAGYAdQBsAGwAcwBxAGwAPQAiAEQAYQB0AGEAIABTAG8AdQByAGMAZQA9AC4AXABtAHkAZABlAHMAdABzAG8AdQByAGMAZQA7AEkAbgB0AGUAZwByAGEAdABlAGQAIABTAGUAYwB1AHIAaQB0AHkAPQBmAGEAbABzAGUAOwBVAHMAZQByACAASQBEAD0AcwBhADsAUAB3AGQAPQBzAGEAcABhAHMAcwAhADsARABhAHQAYQBiAGEAcwBlAD0AbQB5AGQAYgA7ACIALABjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQA9ADEAMAAuADEAMAAuADEAMAAuADEAMAAsAHUAcwBlAHIAbgBhAG0AZQA9AGEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIALABwAGEAcwBzAHcAbwByAGQAPQBhAGQAbQBpAG4AcABhAHMAcwAiAA=="
When decoded, you'll see it's the OP's original snippet with all arguments and double quotes preserved.
powershell.exe -EncodedCommand
Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.
The original command:
C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"
It turns into this when encoded as Base64:
QwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEkASQBTAFwATQBpAGMAcgBvAHMAbwBmAHQAIABXAGUAYgAgAEQAZQBwAGwAbwB5AFwAbQBzAGQAZQBwAGwAbwB5AC4AZQB4AGUAIAAtAHYAZQByAGIAOgBzAHkAbgBjACAALQBzAG8AdQByAGMAZQA6AGQAYgBmAHUAbABsAHMAcQBsAD0AIgBEAGEAdABhACAAUwBvAHUAcgBjAGUAPQBtAHkAcwBvAHUAcgBjAGUAOwBJAG4AdABlAGcAcgBhAHQAZQBkACAAUwBlAGMAdQByAGkAdAB5AD0AZgBhAGwAcwBlADsAVQBzAGUAcgAgAEkARAA9AHMAYQA7AFAAdwBkAD0AcwBhAHAAYQBzAHMAIQA7AEQAYQB0AGEAYgBhAHMAZQA9AG0AeQBkAGIAOwAiACAALQBkAGUAcwB0ADoAZABiAGYAdQBsAGwAcwBxAGwAPQAiAEQAYQB0AGEAIABTAG8AdQByAGMAZQA9AC4AXABtAHkAZABlAHMAdABzAG8AdQByAGMAZQA7AEkAbgB0AGUAZwByAGEAdABlAGQAIABTAGUAYwB1AHIAaQB0AHkAPQBmAGEAbABzAGUAOwBVAHMAZQByACAASQBEAD0AcwBhADsAUAB3AGQAPQBzAGEAcABhAHMAcwAhADsARABhAHQAYQBiAGEAcwBlAD0AbQB5AGQAYgA7ACIALABjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQA9ADEAMAAuADEAMAAuADEAMAAuADEAMAAsAHUAcwBlAHIAbgBhAG0AZQA9AGEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIALABwAGEAcwBzAHcAbwByAGQAPQBhAGQAbQBpAG4AcABhAHMAcwAiAA==
and here is how to replicate at home:
$command = 'C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
$encodedCommand
# The clip below copies the base64 string to your clipboard for right click and paste.
$encodedCommand | Clip
For the executable name, the new-alias cmdlet can be employed to avoid dealing with spaces or needing to add the executable to the $PATH environment.
PS> new-alias msdeploy "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe"
PS> msdeploy ...
To list or modify PS aliases also see
PS> get-alias
PS> set-alias
From Jeffery Hicks Aarticle
Other answers address the arguments.
If you just need to run a file in the current directory and don't feel like spelling out the entire path use Get-Location:
& "$(Get-Location)\example.exe" arg1 arg2 arg3
Note the & at the start. Spaced arguments are to be placed after the quotes.
I had the following code working perfect on my laptop:
& $msdeploy `
-source:package="$publishFile" `
-dest:auto,computerName="$server",includeAcls="False",UserName="$username",Password="$password",AuthType="$auth" `
-allowUntrusted `
-verb:sync `
-enableRule:DoNotDeleteRule `
-disableLink:AppPoolExtension `
-disableLink:ContentExtension `
-disableLink:CertificateExtension `
-skip:objectName=filePath,absolutePath="^(.*Web\.config|.*Environment\.config)$" `
-setParam:name=`"IIS Web Application Name`",value="$appName"
Then when I tried to run that directly on one server I started getting those errors "Unrecognized argument ...etc.... All arguments must begin with "-". "
After trying all possible workarounds (no success), I found out that Powershell on the server (Windows 2008 R2) was version 3.0, while my laptop has 5.0. (you can use "$PSVersionTable" to see version).
After upgrading Powershell to latest version it started working again.
So, I ran into a similar problem and chose to solve it this way instead:
Escape your quote (") characters with a backtick (`)
Surround your new expression with quotes (")
Using the call operator (&), issue the command invoke-expression on the new string
Example solution:
& { invoke-expression "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`" -dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`",computername=10.10.10.10,username=administrator,password=adminpass`"" }
To transfer a batch script using exiftool.exe to a powershell script I had the challange to give '-s, "-s and even ${Filename} to the command and on the other hand fill out variables in these parameters.
For a start: The replacement in using 'echochars' is brilliant. It clearly shows what is grouped as a single parameter and what ends up as the next parameter.
In powershell it is similar to perl (and unix scripting): the used quotes have their meaning.
strings between "-s. The string will be interpreted (variables filled)
Strings between '-s. The string will not be interpreted (or verry limited)
the escape character is ` (the back-quote). The next character looses its special meaning. Comparable with the \ (back stroke) on unix/linux/perl.
Some examples:
${ExifArgs} += "-if `"`${FileName} !~ /desktop.ini/i`""
${ExifArgs} += '-dateFormat "%Y\%Y%m\%Y%m%d_%H%M%S"'
${ExifArgs} += ('"' + "-FileName<${NewFotos}\${SourceName}\" + '${DateTimeOriginal}_${ImageWidth}x${ImageHeight}_${Model;s/ //g}_${FileName;s/^.*([0-9]{4})[^0-9].*$/\1/}.%e' + '"')
A call to echoargs with the above, produces the next output (numbers are hacked for privacy):
Arg 11 is <-if>
Arg 12 is <${FileName} !~ /desktop.ini/i>
Arg 13 is <-dateFormat>
Arg 14 is <%Y\%Y%m\%Y%m%d_%H%M%S>
Arg 15 is <-FileName<D:\Pictures\NewFotos\${DateTimeOriginal}_${ImageWidth}x${ImageHeight}_${Model;s/ //g}_${FileName;s/^.*([0-9]{4})[^0-9].*$/\1/}.%e>
See how the first line produces arg 11 and 12: the outher "-s are removed to store the entire line in the array. The inner "-s, quoted by the `-s are there to keep the argument together (while the -if is the previous argument)
The second shows arg 13 and 14: the use of "-s between '-s. No need to escape using `-s.
In the last line (producing arg 15): the single string is constructed by using powershell ()-s and +-s to concatenate a couple of strings to a single string. It uses both " and ' delimited strings to have som ${}-s filled out by powershell and some for exiftool.
And yes, some powershell special characters are transvered into the archuments.

Powershell Command Processing (Passing in Variables)

I'm creating a Powershell script to deploy some code and part of the process is to call a command-line compression tool called RAR.EXE to back-up some folders.
I'm attempting to dynamically build out the parameters and then have powershell call the command with the variables but I'm running into trouble. It isn't working...
Run the following script and you should see what I'm talking about. The parameters being passed in as a variable are being mangled. If I pass the entire command + parameters in I get the infamous "is not recognized as a cmdlet..." message.
Thanks for any help!
echo "this should succeed"
& cmd /c echo foo
echo "why does this echo out an additional double quote?"
$param = "/c echo foo"
& cmd "$param"
echo "this does the same"
$param = "/c echo foo"
& cmd $param
echo "escaping the slash doesn't work either..."
$param = "`/c echo foo"
& cmd $param
echo "this fails, but why?"
$cmd = "cmd /c echo foo"
&$cmd
The call operator '&' is unnecessary in this case. It is used to invoke a command in a new scope. This is typically used to invoke a command specified by a string or scriptblock. It also has the side benefit that any variables created in say a PowerShell script are discarded after the command finishes and the scope goes away.
However since the cmd is an EXE it executes in a completely different process. FWIW, you get similar output directly from cmd.exe:
> cmd "/c echo foo"
foo"
So the extra quote on the end is a cmd.exe issue. Typically you need to keep the command separate from the parameters when PowerShell is doing the parsing to invoke the command e.g.
45> & { $foo = "foo" }
46> $foo # Note that $foo wasn't found - it went away with the scope
47> . { $foo = "foo" } # dotting executes in the current scope
48> $foo
foo
The notable exception here is that Invoke-Expression behaves like an "evaluate this string" function. Use with care, especially if the user provides the string. Your day could suck if they provided "ri C:\ -r".
In this case, as others have suggested I would pull the /c out of the string $param string and specify it e.g.:
cmd /c $param
Or use Invoke-Expression but use with care. BTW when you are trying to debug issues with sending arguments to EXE from PowerShell, check out the echoargs utility in PowerShell Community Extensions (http://pscx.codeplex.com). It is very handy:
49> $param = "/c echo foo"
50> echoargs $param
Arg 0 is </c echo foo>
This shows that cmd.exe receives "/c echo foo" as a single argument. "/c" should be a separate argument from "echo foo" (the command to execute).
I have had problems with the & call operator in the past when trying to invoke executable type commands like you are trying. Not sure I understand why. Invoke-Expression however, always seems to work in this context:
PS C:\> $cmd = "cmd /c echo foo"
PS C:\> Invoke-expression $cmd
foo
One other way I found to do this was to create an array of arguments for the command line and use that with the apersand & call operator. Something like this:
$exe = "cmd";
[Array]$params = "/c", "echo", "foo";
& $exe $params;
It's worked well for me.
I originally found this technique here:
http://techstumbler.blogspot.com/2009/12/windows-commands-with-arguments-in.html
Your last example if failing because "&" treats the string as one argument, so it is looking for a program named "cmd /c echo foo.exe". :)
This works:
& $cmd $params
As for the double quote issue, it does seem that cmd does not like the quotes around arguments that PowerShell puts. It gets this:
cmd "/c echo foo"
So I think it treats everything after /c as the exact command, so like so:
echo foo"
Some command line programs and funky parsing of the command line (that is why PowerShell takes over this job for functions and cmdlets). In the case of cmd, I would suggest this:
$param = "echo foo"
& cmd /c $param
it's an artifact of using cmd /c, I think. running
$param = "echo foo"
cmd /c $param
works fine. Unless you have a real code example, it's a bit hard to trouble shoot.
Args are treated differently when they are contained in a String:
PS D:\> echo "1 2 3"
1 2 3
PS D:\> echo 1 2 3
1
2
3
The same results occur when you use a variable for the args:
PS D:\> $param = "1 2 3"
PS D:\> echo $param
1 2 3
The SOLUTION is to use an Array:
PS D:\> $param = #(1,2,3)
PS D:\> echo $param
1
2
3