Spaces cause split in path with PowerShell - powershell

I'm having an issue with powershell when invoking an exe at a path containing spaces.
PS C:\Windows Services> invoke-expression "C:\Windows Services\MyService.exe"
The term 'C:\Windows' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
It seems to be splitting on the space between 'Windows' and 'Services'. Any idea how to get around this problem?

Would this do what you want?:
& "C:\Windows Services\MyService.exe"
Use &, the call operator, to invoke commands whose names or paths are stored in quoted strings and/or are referenced via variables, as in the accepted answer. Invoke-Expression is not only the wrong tool to use in this particular case, it should generally be avoided.

You can escape the space by using single quotations and a backtick before the space:
$path = 'C:\Windows Services\MyService.exe'
$path -replace ' ', '` '
invoke-expression $path

Not sure if someone still needs it... I needed to invoke msbuild in powershell and following worked fine:
$MSBuild = "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe"
& $MSBuild $PathToSolution /p:OutDir=$OutDirVar /t:Rebuild /p:Configuration=Release

"&'C:\Windows Services\MyService.exe'" | Invoke-Expression
via https://www.vistax64.com/powershell/52905-invoke-expression-exe-has-spaces-its-path.html

For any file path with space, simply put them in double quotations will work in Windows Powershell. For example, if you want to go to Program Files directory, instead of use
PS C:\> cd Program Files
which will induce error, simply use the following will solve the problem:
PS C:\> cd "Program Files"

This worked for me:
$scanresults = Invoke-Expression "& 'C:\Program Files (x86)\Nmap\nmap.exe' -vv -sn 192.168.1.1-150 --open"

Using Powershell on Windows10 in 2018, what worked for me was simply to replace double quotes " by simple quotes '. Adding the backtick before the space, as suggested in an answer, broke the path.

What worked for me (I needed the path to create a MySQL dump), was to place the directory in between 6 double quotes like so:
$path = """C:\Path\To\File"""

Can use the . dot operator.
. "C:\Users\user\AppData\Local\Programs\Microsoft VS Code\bin\code.cmd"
or the Start-Process command
Start-Process -PSPath "C:\Users\user\AppData\Local\Programs\Microsoft VS Code\bin\code.cmd"
or using ProcessStartInfo and Process
$ProcessInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo
$ProcessInfo.FileName = 'C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe'
if($Admin){ $ProcessInfo.Verb = 'runas' }
$ProcessInfo.UseShellExecute = $false
$CommandParameters = '-noexit -noprofile -command Set-Location -LiteralPath c:\; $host.ui.RawUI.WindowTitle = ''[{0}] PS''; Set-PSReadlineOption -HistorySaveStyle SaveNothing;' -f $Cred.UserName
$ProcessInfo.Arguments = $CommandParameters
$ProcessInfo.Domain = ($Cred.UserName -split '\\')[0]
$ProcessInfo.UserName = ($Cred.UserName -split '\\')[1]
$ProcessInfo.Password = $Cred.Password
$ProcessObject = New-Object -TypeName System.Diagnostics.Process
$ProcessObject.StartInfo = $ProcessInfo
$ProcessObject.Start() | Out-Null

There's a hack I've used since the Invoke-Expression works fine for me.
You could set the current location to the path with spaces, invoke the expression, get back to your previous location and continue:
$currLocation = Get-Location
Set-Location = "C:\Windows Services\"
Invoke-Expression ".\MyService.exe"
Set-Location $currLocation
This will only work if the exe doesn't have any spaces in its name.
Hope this helps

Please use this simple one liner:
Invoke-Expression "C:\'Program Files (x86)\Microsoft Office\root\Office16'\EXCEL.EXE"

Try this, simple and without much change:
invoke-expression "'C:\Windows Services\MyService.exe'"
using single quotations at the beginning and end of the path.

Due to several PowerShell quoting rules that are used for passing arguments to native commands which also have specific experimental Features in PowerShell, quoting might get very confusing. Therefore the solution in some cases might be simply to don't go down the rabbit hole:
Avoid quoting file paths with spaces by using the 8.3 filenames
$FSO = New-Object -ComObject Scripting.FileSystemObject
$FSO.getfile('C:\Windows Services\MyService.exe').ShortPath
C:\WINDOW~1\MYSERV~1.EXE

Just put ${yourpathtofile/folder}
PowerShell does not count spaces; to tell PowerShell to consider the whole path including spaces, add your path in between ${ & }.

Simply put the path in double quotes in front of cd, Like this:
cd "C:\Users\MyComputer\Documents\Visual Studio 2019\Projects"

enter the root C drive by entering command
C:
type cd and then press Tab key, it will toggle through all available locations and press enter when you have reached the desired one
cd {press tab}

Related

Convert cmd to powershell

How can I convert this cmd to powershell
cd C:\Program Files (x86)\Image Instruments\abcClient
“XYZ.exe” -PatId=”11111” -Firstname=“John” -Lastname=“Do” -Birthday=”19971101” -Sex=“M” -City=“Frankfurt”
I tried something like this, but does not work. It opens the .exe without arguments:
$pathExe = Set-Location “C:\Program Files (x86)\Image Instruments\abcClient”
$openExe = Start-Process “XYZ.exe”
$PatId = ”11111”
$Firstname = “John”
$Lastname = “Doe”
$Birthday = ”19971101”
$Sex = “M”
$City = “Frankfurt”
$pathExe; & $openExe#('-PatID='+$PatId, '-Firstname=’+$Firstname, '-Lastname='+$Lastname, ’-Birthday=’+$Birthday, ‘-Sex=’+$Sex, '-City='+$City)
As I have no experience with programming, how I could bring this to work?
Thank you for any advice
Just like cmd, PowerShell is a shell that supports invoking programs directly, with arguments.
Therefore, your command looks very similar in PowerShell:
Set-Location "C:\Program Files (x86)\Image Instruments\abcClient"
XYZ.exe -PatId="11111" -Firstname="John" -Lastname="Do" -Birthday="19971101" -Sex="M" -City="Frankfurt"
The equivalent of cd in PowerShell is Set-Location (although cd works too, because it is defined as an alias for it).
Note the need to quote, the target directory passed to Set-Location, given that its path contains spaces.
Unquoted use of XYZ.exe allows its direct invocation; if you quote the program name (e.g., as "XYZ.exe"), you would have to prepend & , the call operator.
If you want to use variables in your arguments, simply use them in lieu of the literal strings; e.g. -PatId="11111" can be replaced with -PatId="$PatId", assuming that you've defined $PatId = "11111" beforehand.
Though they do not come into play here, there are differences between cmd and PowerShell with respect to what characters need quoting when you pass arguments and how special characters are escaped - see Get-Help about_parsing
If XYZ.exe is a console application (which appears to be the case), PowerShell will execute it synchronously - that is, PowerShell will wait until the application has exited and will reflect its exit code in automatic variable $LASTEXITCODE.
So, the ProcessStartInfo object defines parameters to pass into a process:
FileName - This is what you'll be executing
WorkingDirectory - The execution path that it will be running from (not always the same as the file's directory but often is). Important if you have things like relative paths
Arguments - This is what is getting passed as the process arguments.
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "C:\Program Files (x86)\Image Instruments\abcClient\XYZ.exe"
$startInfo.WorkingDirectory = "C:\Program Files (x86)\Image Instruments\abcClient\"
$startInfo.Arguments = "-PatId=11111 -Firstname=John -Lastname=Do -Birthday=19971101 -Sex=M -City=Frankfurt"
Then you start a process object, and wait for it to complete.
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start()
$process.WaitForExit()
Then get it's return code (usually EXEs with a 0 mean success).
$exitCode = $process.ExitCode
Get / Convert / Access / Translate Cmd COMMAND Variables in PowerShell:
You may want to try the following which I have 'found' works in a single PC environment:
#- Set up Cmd Variable -----
$zCmdVariable = "%UserProfile%"
#- Get Contents from Cmd -----
$zConvertedVariable = (cmd /c "echo $zCmdVariable")
#- Use contents in Powershell -----
Get-Item -Path $zConvertedVariable
I hope this helps; Pass It forward.

How do you call Windows Explorer with a file selected from Powershell?

I have run into a problem while writing my first basic PowerShell utility. I need to open an Explorer window with a file selected, but can't get the syntax of the command right.
I found this answer on SO, https://stackoverflow.com/a/12162855/957246 and had a read of this excellent blog on external commands, http://edgylogic.com/blog/powershell-and-external-commands-done-right/ - but still can't get it to work.
This is my example script (test.ps1):
$myFile = "C:\Projects\Scripts\any.txt"
# The backslash-backticks are to escape the speech marks, once for PowerShell and then again for DOS
& "C:\Projects\Scripts\EchoArgs.exe" /select",\`"$myFile\`""
& "explorer" /select",\`"$myFile\`""
..and this is the batch file that calls it, in case there's something wrong with the way I'm calling the PowerShell script:
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& 'C:\Projects\Scripts\test.ps1'"
I've tried a few different combinations and the output from echoargs suggests that the syntax is right (assuming the parameter string for explorer is taken as a single string) but whatever I try just opens an explorer window on 'my documents' and the parameters are ignored/being thrown away somewhere.
There's a bit on the MSDN page for explorer.exe switches that says the comma is an empty parameter, maybe that's the thing I need to be providing by formatting the command differently?
What is the point of using batch commands from powershell? Your only going to confuse yourself like that.. and me for that matter.
$myFile = "C:\Projects\Scripts\any.txt"
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.InitialDirectory = Split-Path $myFile -Parent
$OpenFileDialog.FileName = Split-path $myfile -leaf
$OpenFileDialog.ShowDialog() | Out-Null
EDIT
If you need to keep going the explorer route try this :
Start-Process -FilePath C:\Windows\explorer.exe -ArgumentList "/select, ""$myFile"""
Also you could just use:
$dir = "\\PATH\TO\YOUR\DIRECTORY"
C:\Windows\explorer.exe "/select,$dir"

PowerShell: Start a process with unquoted arguments

My PowerShell script should start an external executable with specified parameters. I have two strings: The file name, and the arguments. This is what process starting APIs usually want from me. PowerShell however fails at it.
I need to keep the executable and arguments in a separate strings because these are configured elsewhere in my script. This question is just about using these strings to start the process. Also, my script needs to put a common base path in front of the executable.
This is the code:
$execFile = "SomeSetup.exe"
$params = "/norestart /verysilent"
& "$basePath\$execFile" $params | Out-Host
# Pipe to the console to wait for it to finish
This is the actual result (does not work with this program):
Process file name: "C:\My\Base path\SomeSetup.exe"
Process command line: "/norestart /verysilent"
This is what I'd expect to have (this would work):
Process file name: "C:\My\Base path\SomeSetup.exe"
Process command line: /norestart /verysilent
The problem is that the setup recognises the extra quotes and interprets the two arguments as one - and doesn't understand it.
I've seen Start-Process but it seems to require each parameter in a string[] which I don't have. Splitting these arguments seems like a complicated shell task, not something I'd do (reliably).
What could I do now? Should I use something like
& cmd /c "$execFile $params"
But what if $execFile contains spaces which can well happen and usually causes much more headache before you find it.
You can put your parameters in an array:
$params = "/norestart", "/verysilent"
& $basepath\$execFile $params
When you run a legacy command from Powershell it has to convert the powershell variables into a single string that is the legacy command line.
The program name is always enclosed in quotes.
Any parameters that contain a space character are enclosed in double
quotes (this is of course the source of your problem)
Each element of an array forms a separate argument.
So given:
$params = "/norestart /verysilent"
& "$basePath\$execFile" $params
Powershell will run the command:
"\somepath\SomeSetup.exe" "/norestart /verysilent"
The solution is to store separate arguments in an array:
$params = "/norestart","/verysilent"
& "$basePath\$execFile" $params
will run:
"\somepath\SomeSetup.exe" /norestart /verysilent
Or if you already have a single string:
$params = "/norestart /verysilent"
& "$basePath\$execFile" ($params -split ' ')
will work as well.
$execFile = "SomeSetup.exe"
$params = "/norestart /verysilent"
Invoke-Expression ($basePath + "\" + $execFile + " " +$params)
Try it this way:
& $execFile /norestart /verysilent
Bill
Just use single quotes:
$execFile = "SomeSetup.exe"
$params = "/norestart /verysilent"
& "'$basePath\$execFile' $params" | Out-Host
# Pipe to the console to wait for it to finish
Also I would use join-path instead of concatenating the two strings:
$path = Join-Path $basePath $execFile
& "$path $params" | out-host

How to call an executable with parameters from powershell script

I am seeking help on how to call cmd with specific parameters from a powershell script. So far what I have written is below, but it gives me an error message saying $_cmd is not recognized.
I am trying to pass the from date and to date to a an exe... The from date as you can see needs to be today - 1 and the to date should be now. The path of the executable is D:\DataService and that's why I am setting the path early in the script.
Write-Host "Get data from service"
$path ="D:\DataService"
Push-Location $path
$Date = Get-Date
$DateFrom = $Date.ToString("yyyy-MM-dd HH:mm:ss")
$DateTo = $Date.AddDays(-1).ToString("yyyy-MM-dd")
$_cmd = "ReportGen.exe -ReportType Data -DateFrom $DateFrom $DateTo"
%$_cmd%
Any suggestions please?
Don't make a command string. Simply use the call operator (&):
Write-Host 'Get data from service'
$path = 'D:\DataService'
Push-Location $path
$Date = Get-Date
$DateFrom = $Date.ToString('yyyy-MM-dd HH:mm:ss')
$DateTo = $Date.AddDays(-1).ToString('yyyy-MM-dd')
& ReportGen.exe -ReportType Data -DateFrom $DateFrom $DateTo
%$_cmd% looks like a mixture of PowerShell and cmd syntax. The %'s have no special significance. PowerShell interprets that as the literal name of a command, which of course is not recognized. To execute the contents of the string, use
Invoke-Expression $_cmd
However, that will only work if ReportGen.exe is in the path, and cmd doesn't even get involved, because you're not calling it anywhere. If for some reason, as you say, you specifically want to execute that command with cmd, you should add cmd /c or cmd /k at the beginning. However, you don't even need to assign to a string, you can just call cmd directly:
cmd /c ReportGen.exe -ReportType Data -DateFrom $DateFrom $DateTo
/c means that cmd will exit after executing the command. /k means the cmd prompt will remain open after the command is executed. You probably want /c so that you'll return to the PowerShell prompt after executing the script.
You want to use Invoke-Expression as per the comments below.
Invoke-Expression $_cmd
Original comment, which is wrong:
Did you try putting an ampersand in front. e.g.:
& $_cmd
Not sure why you are using the % characters.
A couple things. One, stop using Write-Host. Honestly, let this be the final time you ever use it (unless you truly need it - and know why you need it). Instead, use Write-Output - even when you know your script is going to run in the console. Second, you could also consider using the Start-Process cmdlet and its parameter -ArgumentList.
Your $DateFrom and $DateTo seem to be backwards, since you are making $DateTo set to yesterday. So unless you are going from today to yesterday you may want to adjust that. Also, you specify the from date, but just tack the to date on the end, not sure if you need to specify what it is, or if both dates are a part of the same parameter. As for running a command with arguments, use Invoke-Command with arguments comma delimited as such:
Invoke-Command -FilePath "D:\DataService\ReportGen.exe" -ArgumentList '-ReportType Data','-DateFrom $DateFrom','$DateTo'
I'd do it something like this.
$CustomProcess = New-Object System.Diagnostics.ProcessStartInfo
$CustomProcess.FileName = "ReportGen.exe"
$CustomProcess.arguments = "-ReportType Data -DateFrom $DateFrom $DateTo"
[System.Diagnostics.Process]::Start($CustomProcess)

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.