2

I'd like to run a command such as:

pushd \\myServer\share\scripts
myBatchFile.bat param1 param2 "parameter 3"
popd

Only initiating through powershell.

NB: The name of the batch file is held in a variable, as are each of the parameters.

function Escape-StringForCmd($a)
{
    if(($a -like '*"*') -or ($a -like '* *'))
    {
        ('"{0}"' -f ($a -replace '"','""'))
    }
    else
    {
        $a
    }
}

$batch = "myBatchFile.bat"
$p1 = "param1"
$p2 = "param2"
$p3 = "parameter 3"

$batch = Escape-StringForCmd($batch)
$p1 = Escape-StringForCmd($p1)
$p2 = Escape-StringForCmd($p2)
$p3 = Escape-StringForCmd($p3)

pushd \\myServer\share\scripts

cmd.exe /c $batch $p1 $p2 $p3
#above fails; no error returned; I think because cmd doesn't like the UNC path, so reverts to the system directory

Start-Process "cmd.exe" -ArgumentList "/c",$batch,$p1,$p2,$p3 -NoNewWindow -Wait -WorkingDirectory "\\myServer\share\scripts"
#above also fails; not sure why as looks healthy when running outside of ps1 file

popd

I've also interested in capturing the output - though as at present the batch file's not being run I'll focus on that initially.

I've not yet tried the ProcessStartInfo solution (see link below) as it seems start-process, or simply cmd.exe /c should work (certainly when I've run tests outside of a ps1 file this has worked), but I'll resort to trying that method shortly.

ProcessStartInfo solution: Powershell: Capturing standard out and error with Process object

Community
  • 1
  • 1
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178

2 Answers2

2

Using @JNK's answer along with the below hack, I found a way to get this to work

$tempBatchName = ".\~myTempBatchFile.bat" #put this in a variable so we can easily amend if required

"
pushd \\myServer\share\scripts
$batch $p1 $p2 $p3
popd
" | out-file $tempBatchName -encoding ascii

$MyCmd = ("{0} *>&1" -f $tempBatchName)

$ReturnOutput = Invoke-Expression $MyCmd
$ReturnOutput | out-file ("{0}.log" -f $tempBatchName)
remove-item $tempBatchName
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
1

Is there a reason you can't use invoke-expression for this?

$MyCmd = "$batch $p1 $p2 $p3 *>&1"

$ReturnOutput = Invoke-Expression $MyCmd

The *>&1 puts all output from the StdErr and StdOut to the output stream.

More info on redirection operators here.

JNK
  • 63,321
  • 15
  • 122
  • 138
  • Awesome - I'd not come across `Invoke-Expression` before - thanks. NB: to make this work I also had to make it clear I wanted to execute the batch from the local directory - i.e. ".\$batch" – JohnLBevan Dec 08 '14 at 18:27
  • Actually - just realised I was testing on a local batch - this still suffers from the UNC path problem - though it runs the batch script, the script doesn't execute on the current UNC path (i.e. from powershell's earlier pushd expression)... Sadly I can't change the content of the batch files... any further thoughts? – JohnLBevan Dec 08 '14 at 18:44
  • Can you not put the UNC path before the batch file? – JNK Dec 08 '14 at 18:46
  • Yes, though sadly that doesn't affect the working directory (the batch file references other files in the same directory)... interestingly Invoke-Expression is able to run the batch; only when the batch begins to run it switches to the c:\windows directory. I've also attempted a multi-line expression for invoke-expression where I do the pushd and popd either side of calling the batch; no luck. – JohnLBevan Dec 08 '14 at 18:57
  • fixed it - I just create a temporary batch file with the 3 lines, then call that. Hack, but it works. – JohnLBevan Dec 08 '14 at 19:03