Start process with args which contains a path with blanks - powershell

I need to start a process from a powershell script and pass such params :
-a -s f1d:\some directory\with blanks in a path\file.iss
to do that, I write the folowing code :
$process = [System.Diagnostics.Process]::Start("$setupFilePath", '-a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"')
$process.WaitForExit()
as a result the process starts but the last argument : -f1d:\some directory\with blanks in a path\file.iss
is not passing correctly. Help, please

I think you can use Start-Process:
Start-Process -FilePath $setupFilePath -ArgumentList '-a','-s','-f1"d:\some directory\with blanks in a path\fileVCCS.iss"' |
Wait-Process

I understand your question to be:
How to pass multiple arguments to start a process where one of the arguments has spaces?
I'm assuming the equivalent in a Windows batch file would be something like:
"%setupFilePath%" -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"
where the double quotes allow the receiving process (setupFilePath in this case) to receive three arguments:
-a
-s
-f1"d:\some directory\with blanks in a path\fileVCCS.iss"
To accomplish this with the code snippet in your question I would use back ticks (to the left of the 1 and below the escape key, not to be confused with a single quote; aka Grave-accent) to escape the inner double quotes like this:
$process = [System.Diagnostics.Process]::Start("$setupFilePath", "-a -s -f1`"d:\some directory\with blanks in a path\fileVCCS.iss`"")
$process.WaitForExit()
Note that in addition to using back ticks I also changed the single quotes around your argument list to double quotes. This was necessary because single quotes do not allow the escapes we need here (http://ss64.com/ps/syntax-esc.html).
Aaron's answer should work just fine. If it doesn't then I would guess that setupFilePath is not interpretting -f1"d:\space here\file.ext" as you expect it to.
OPINION ALERT The only thing I would add to his answer is to suggest using double quotes and back ticks in order to allow using a variable within the path for argument -f1:
Start-Process -FilePath $setupFilePath -ArgumentList '-a','-s',"-f1`"$pathToVCCS`"" |
Wait-Process
This way you won't have a hard-coded, absolute path in the middle of a long line.

On PowerShell v3, this works:
& $setupFilePath -a -s -f1:"d:\some directory\with blanks in a path\fileVCCS.iss"
Using the PSCX echoargs command shows this:
25> echoargs.exe -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"
Arg 0 is <-a>
Arg 1 is <-s>
Arg 2 is <-f1d:\some directory\with blanks in a path\fileVCCS.iss>
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" -a -s "-f1d:\some directory\with blanks in a path\fileVCCS.iss"
On V2 use - note the addition of a backtick on the last double quote:
PS> echoargs.exe -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss`"
Arg 0 is <-a>
Arg 1 is <-s>
Arg 2 is <-f1d:\some directory\with blanks in a path\fileVCCS.iss>
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" -a -s -f1"d:\some directory\with blanks in a path\fileVCCS.iss"

Related

How to escape # within a string in PowerShell?

I'm trying to send a HTML request via cURL in PowerShell. The code in question:
$command = 'curl -d #request.txt -o testoutput.xml -X "POST" -H #header.txt -u "username:password" "URL"'
Invoke-Expression $command
The HTML Body (-d) and Header (-H) need to be read from files, hence the # before the filenames.
In order for this to work, I need to escape the # so PowerShell doesn't interpret it as a splat operator - and that's my problem, nothing I've tried so far worked:
putting it in single quotes
here document (#" "#)
here string (#' '#)
using string templates with placeholders ("{0}request.txt" -f "#")
Unicode escape ("`u{0040}request.txt")
How do I escape the # correctly? Or am I on the wrong path entirely? (I'm new to PowerShell sorry)
Invoke-Expression (iex) should generally be avoided; definitely don't use it to invoke an external program or PowerShell script.
Therefore:
invoke curl directly
and quote PowerShell metacharacters such as # (see this answer for the full list) - either individually, with ` (e.g., `#), or by enclosing the entire argument in quotes ('...' or "...", as appropriate).
curl -d `#request.txt -o testoutput.xml -X "POST" -H #header.txt -u "username:password" "URL"
As for what you tried:
The primary concern about Invoke-Expression use is one of security: unwanted execution of (additional) commands potentially injected into the string passed to it.
In terms of functionality, Invoke-Expression is not only not needed for regular calls to external programs, it can create quoting headaches.
However, given that you're passing a '...' string to Invoke-Expression, quoting the # as `# would have worked, as shown in this simple example:
# OK, but generally do NOT do this.
Invoke-Expression 'Write-Output `#'
Had you used a "..." string, the ` would have been "eaten" by the up-front parsing of such an expandable string, based on the escaping rules explained in the conceptual about_Quoting_Rules help topic:
# BREAKS, because the ` is stripped before Invoke-Expression sees it.
Invoke-Expression "Write-Output `#"

Can't figure out how to properly execute exe with arguments

So I have been trying to write a script where I run an executable with arguments to return some information I need for our monitoring. Not long ago I have written a script that successfully managed to do that, using the following command:
$command = "-t vtl -p {1} -m {0} -s"
$check = Invoke-Expression -command ("$exemap\$exe $command" -f $server,$poort)
This worked perfectly. However I am in the process of writing a new script and the exact same thing does not seem to be working anymore. Here is a script I have to reproduce the problem:
$omgeving = "A"
$exemap = "\\cfc01.corp\rpa-{0}\Scripts\Check_actualiteit_RPA" -f $omgeving
#$exe = "echoargs.exe"
$exe = "stmmon.exe"
$exepath = "$exemap\"+"$exe"
$commando = "-t {0} -p {1} -m {2} -s"
$poort = "5062"
$berichttype = "VTL"
$server = "rpa-a-ap001"
$command = ($commando -f $berichttype,$poort,$server) -split " "
#$command = "-t VTL -p 5062 -m rpa-a-ap001 -s"
& $exepath $command
So I have negated some lines that are there for troubleshooting. I have tried using the Invoke-Expression command above and using the & operator. I have googled and tried a lot. I have tried using jobs and Invoke-Command. But all of them have the same result, an explanation from the exe telling me how to use it:
Usage: \\cfc01.corp\rpa-A\Scripts\Check_actualiteit_RPA\stmmon.exe [-v] [-h] -t <type> -p <port> -m <machine> -k <key> [-s]
This makes me believe that the executable is not really acknowleding any arguments. I tried using echoargs and the output from the script above is:
Arg 0 is <-t>
Arg 1 is <VTL>
Arg 2 is <-p>
Arg 3 is <5062>
Arg 4 is <-m>
Arg 5 is <rpa-a-ap001>
Arg 6 is <-s>
Or, if I dont use the -split " " in the $command variable, the echoargs is this:
Arg 0 is <-t VTL -p 5062 -m rpa-a-ap001 -s>
The script above may not be very dynamic, but the actual script im trying to make is going to be. The argumentlist should be configurable and dynamic, which is why im using the -f command on different occasions.
Can anyone see what I am doing wrong here and why the executable won't even acknowledge the existence of arguments?
Use the call operator (&) for running external commands. Use Join-Path for building paths. Use splatting for passing arguments to a program or function.
$omgeving = "A"
$exemap = "\\cfc01.corp\rpa-$omgeving\Scripts\Check_actualiteit_RPA" -f
$exe = "stmmon.exe"
$exepath = Join-Path $exemap $exe
$params = '-t', 'VTL',
'-p', 5062,
'-m', 'rpa-a-ap001',
'-s'
& $exepath #params
Also, judging from the help output, you seem to be missing a required parameter:
Usage: \\...\stmmon.exe [-v] [-h] -t <type> -p <port> -m <machine> -k <key> [-s]
If everything else fails, try this as a workaround:
$type = 'VTL'
$port = 5062
$server = 'rpa-a-ap001'
& cmd /c ('"{0}" -t {1} -p {2} -m {3} -s' -f $exepath, $type, $port, $server)
I am sorry to have wasted people's time here.
I have discovered the problem here. Apparently the 'type' arguments does not allow capital letters. I had not yet tried to change those, but it seems to have fixed the issue.

invoke-expression doesnot throw an error in powershell

I am creating custom forms and adding it to the printer server properties using forms.vbs and running it through cmd. The script is as follows
cscript 'C:\Tools\forms.vbs' -a -n "DD" -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 7.48 -r 7.48
This works fine when running in command prompt.
Now I invoked this code to the powershell as follows and it also works fine
$formname = "DD"
$cmd = "cscript 'C:\Tools\forms.vbs' -a -n " + '"' + $formname + '"' + " -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 7.48 -r 7.48 "
Invoke-Expression $cmd
The issue started when I thought of checking the error handling thing for the powershell invoke expression.
In cmd when we give the expression as
cscript 'C:\Tools\forms.vbs' -a -n "DD" -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 0 -r 0
This will definitely throw error as per the notes given in the form.vbs and it will not create a form.
So when I invoked the same error-thrown script to my powershell, the form is not creating as well as it is not throwing any errors. So I request me to guide in this regard. Thanks in advance.
Invoke-Expression only checks if it's possible to run the command at all. For example, if cscript.exe cannot be found, Invoke-Expression will throw an ObjectNotFound exception.
It doesn't check the exit code of the command or in any way parse its output. You should be able to see the output however.
Make sure you don't mix single and double quotes inside your expression:
$formname = "DD"
# Note double quotes around C:\Tools\forms.vbs
$cmd = 'cscript "C:\Tools\forms.vbs" -a -n ' + '"' + $formname + '"' `
+ ' -u inches -h 7.48 -w 7.48 -t 0 -e 0 -b 7.48 -r 7.48 '
Invoke-Expression $cmd
Output:
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.
Unable to add form DD, error code: 0x1A8. Object required
If you want your code to throw an exception, you need to parse the output manually, e.g.:
try {
$output = Invoke-Expression $cmd
if ($output -like "*error code*") { throw $output }
}
catch [System.Exception] {
$message = ($Error[0].Exception -split [System.Environment]::NewLine)[-1]
$message
}
Output:
Unable to add form DD, error code: 0x1A8. Object required
I have been using Start-Process to manage installs and uninstalls, and recently started using the same approach for arbitrary executables, which seems to be somewhat what you are trying to do, so...
$new.ExitCode > $null
$filepath = 'cscript.exe'
$argumentList = "C:\Forms.vbs"
$exitCode = (Start-Process -FilePath:$filePath -argumentList:$argumentList -wait -errorAction:Stop -PassThru).ExitCode
$exitCode
The VBS just throws up a messagebox and quits with a return code, like so.
MsgBox "Text"
WScript.Quit 4
After I close the message box I get that 4 back at the PowerShell console. With no Wscript.Quit, or no exit code provided, I get the expected 0 back.
Simple example, but maybe gets you close, assuming you can get the error code you need into a variable so you can return it from the VBS. Or maybe someone points out some nuance I am not aware of and we both learn something. ;)

Differences in calling CSVDE from Powershell vs Command Prompt

Can anyone explain why calling the CSVDE utility from an elevated Windows command prompt would differ than using the same string from an elevated Powershell console? The issue I have is that I can successfully export from Active Directory via the command prompt method, but Powershell returns an authentication error, "Simple bind returned 'Invalid Credentials'.
Here is the command used for both, edited for sensitive pieces:
c:\csvde.exe -s domain.company.org -f ExportFile.csv -l "givenName,sn,ipPhone,title,department,company,physicalDeliveryOfficeName,mail" -d "OU=ABC Group,OU=ABC Users,DC=DomainName,DC=org" -a UserDistinguishedName Password
Both sessions are running with Administrator privileges. I am a Powershell novice, and for the life of me, I can't figure this out.
Thanks!
I can see two potential issues. First thought is that it is taking your user name and password as separate arguments, or as Adi Inbar suggested: you've got some special characters that are causing issues. Either way I'd enclose things in single quotes so that arguments are passed as expected, and taken literally.
c:\csvde.exe -s 'domain.company.org' -f 'ExportFile.csv' -l 'givenName,sn,ipPhone,title,department,company,physicalDeliveryOfficeName,mail' -d 'OU=ABC Group,OU=ABC Users,DC=DomainName,DC=org' -a 'UserDistinguishedName' 'Password'
See if that doesn't resolve the issue. In my experience that is usually a safe way to run a executable from PowerShell. I suppose alternatively you can assign them to variables, and then pass those.
$Server = 'domain.company.org'
$OutFile = 'ExportFile.csv'
$Attributes = 'givenName,sn,ipPhone,title,department,company,physicalDeliveryOfficeName,mail'
$SearchRoot = 'OU=ABC Group,OU=ABC Users,DC=DomainName,DC=org'
$UserID = 'CN=TMTech,OU=Users,DC=Some,DC=Company,DC=org'
$Password = 'P#$$w0rd'
CSVDE.exe -s $Server -f $OutFile -l $Attributes -d $SearchRoot -a $UserID $Password

cannot make sqlcmd work after runas

I followed a few examples here, but I still can not get my sqlcmd work after runas.
I can make it work with two steps:
Step one: Use runas to login into a new login and open a command prompt:
runas.exe /savecred /user:DOMAIN_NAME\login_name cmd.exe
Step two: execute the sqlcmd in a script
sqlcmd -S server_name -E /Q"exit(SELECT ##version )"
But I want to make it one step to get the results. I tried to add " " after the runas command as listed below, but it did not work:
runas.exe /savecred /user:DOMAIN_NAME\login_name "sqlcmd -S server_name -E /Q"exit(SELECT ##version )""
Any ideas?
Take a look at this article describing RunAs. Toward the end of the article, he specifically addresses needing to use quotes inside of quotes:
Fortunately, it’s fairly easy to make RunAs happy. All you need to do is use the \ character to “escape” any double quote marks that must to be embedded within the process path.
So, it looks like your command should be:
runas.exe /savecred /user:DOMAIN_NAME\login_name "sqlcmd -S server_name -E /Q\"exit(SELECT ##version )\""
Notice the \ before both of the nested double quotes.