1

how can I execute the following example in a PowershellScript?

 @echo off
 REM Maintenance Mode on
 "C:\ProgramFiles\vdogServer\VDogMasterService.exe" /at:s /rd:C:\vdServerArchive /maintenance:on
 if ERRORLEVEL 1 ECHO "versiondog Server wurde nicht ordnungsgemäß in den Wartungsmodus versetzt." >> d:\log.txt
 if ERRORLEVEL 0 ECHO "versiondog Server wurde ordnungsgemäß in den Wartungsmodus versetzt." >> d:\log.txt

I tried that without success:

$command = @'
@echo off
REM Maintenance Mode on
"D:\vdogServer\VdogMasterService.exe" /at:s /rd:E\vdServerArchive /maintenace :on
if ERRORLEVEL 1 ECHO "NOK" >> d:\MMLOG.txt
if ERRORLEVEL 0 ECHO "OK" >> d:\MMLOG.txt
'@

 Invoke-Expression -Command:$command

Im a Beginner in Powershell yet, would be nice if someone has a solution for that, BR

JaneksCraft
  • 83
  • 1
  • 2
  • 11

2 Answers2

3

You cannot directly execute batch-file (cmd) commands from PowerShell (which speaks a very different language), but you can pipe a series of batch-file commands to cmd, the (legacy) Windows command processor:

$commands = @'
@echo off
REM Maintenance Mode on
"D:\vdogServer\VdogMasterService.exe" /at:s /rd:E\vdServerArchive /maintenace :on
if ERRORLEVEL 1 ECHO "NOK" >> d:\MMLOG.txt
if ERRORLEVEL 0 ECHO "OK" >> d:\MMLOG.txt
'@

# Simply sends the commands via stdin.
#  /q suppresses printing the prompt between commands, and
#  /d suppresses autorun entries - see cmd /?
$commands | cmd /q /d

but it comes with caveats:

  • With this invocation style, cmd will not reflect the last command's exit code in its own exit code, and PowerShell's $LASTEXITCODE will therefore NOT reflect failure. (Contrast this with invoking a batch file containing the same commands.)

  • Windows PowerShell by default uses ASCII as the output encoding ($OutputEncoding); i.e., it sends ASCII characters only to external commands and simply replaces non-ASCII characters with literal ?.

    • Note: In the cross-platform, install-on demand PowerShell (Core) 7+ edition, $OutputEncoding now defaults to (BOM-less) UTF-8.
    • Either way, cmd.exe expects text to be encoded using the current console window's code page, which is the system's legacy OEM code page by default, which in PowerShell is reflected in the encoding stored in [Console]::InputEncoding; therefore, you can (temporarily) set $OutputEncoding = [Console]::InputEncoding to address that.
  • On a more subtle, but possibly much more insidious note, cmd.exe parses commands provided via stdin expecting interactive command-line syntax, not batch-file syntax, which - regrettably, and for historical reasons - differ subtly.

    • This matters mostly when it comes to escaping % signs (using them as literals): for instance, inside a batch file you could use %%PATH%% to produce literal %PATH% on output (i.e., doubling metacharacter % causes it to be treated literally); on the command line - and when piping via stdin - this does NOT work: you end up with %<value of variable>%.
    • For the whole gruesome story, see this answer.

Thus, you're generally better off writing the commands to a (temporary) batch file and invoking that:

function Invoke-AsBatchFile([string] $batchFileContents) {

  # Determine a unique file path to serve as a temp. batch file.
  $tempBatchFile = "$(Join-Path ([IO.Path]::GetTempPath()) ([IO.Path]::GetRandomFileName())).cmd"

  # Write the commands to the batch file.
  # Note: -Encoding OEM assumes that the current console window's
  #       active code page is at its default, the system's active OEM code page.
  $batchFileContents | Set-Content -Encoding OEM -LiteralPath $tempBatchFile

  # Execute the temp. batch file with pass-through arguments, if any.
  # (Reflected in the automatic $args variable.)
  & $tempBatchFile $args

  # Remove the temp. batch file.  
  Remove-Item $tempBatchFile
  # $LASTEXITCODE now contains the temp. batch file's exit code
  # (whereas $? should be ignored).

}


$command = @'
@echo off
REM Maintenance Mode on
"D:\vdogServer\VdogMasterService.exe" /at:s /rd:E\vdServerArchive /maintenace :on
if ERRORLEVEL 1 ECHO "NOK" >> d:\MMLOG.txt
if ERRORLEVEL 0 ECHO "OK" >> d:\MMLOG.txt
'@

Invoke-AsBatchFile $command

if ($LASTEXITCODE -ne 0) { Write-Error "Something went wrong." }
mklement0
  • 312,089
  • 56
  • 508
  • 622
1

Edited to test exit code per comment:

#Maintenance Mode on 
& "C:\ProgramFiles\vdogServer\VDogMasterService.exe" /at:s /rd:C:\vdServerArchive /maintenance:on
if ($LASTEXITCODE -eq 0) {
    "versiondog Server wurde ordnungsgemäß in den Wartungsmodus versetzt." | out-file d:\log.txt -append
} else {
    "versiondog Server wurde nicht ordnungsgemäß in den Wartungsmodus versetzt." | out-file d:\log.txt -append
}
BenH
  • 9,417
  • 1
  • 17
  • 31