简体   繁体   中英

Run CMD Code in Powershell with ECHO

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

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
}

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.)

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

    • You can (temporarily) set $OutputEncoding = [text.encoding]::Default to address that, which addresses the input side of things and redirecting to output files, but note that console output is a separate issue, and will still misrepresent non-ASCII characters (you'd have to (temporarily) set [Console]::OutputEncoding as well).
  • On a more subtle, but possibly much more insidious note, the commands are parsed with 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 (ie, 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 %<contents of variable %PATH%>% .
    • For the whole gruesome story, see this answer of mine.

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

function Invoke-AsBatchFile([string] $batchFileContents, $ArgumentList) {
  # 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: Not specifying an -Encoding value means that the Default Windows code page 
  # (e.g., Windows 1252 on a en-US system) is used as the output file's encoding.
  # Note that echoing string literals contained in $batchFileContents to files using
  # `>` (output redirection) therefore also creates output files that are encoded that way. 
  $batchFileContents | Set-Content -LiteralPath $tempBatchFile
  # Execute the temp. batch file with optional arguments.
  # Note that output sent to the *console* is by default still interpreted as 
  # *OEM* codepage-encoded; to change that, also (temporarily) set 
  #   [Console]::OutputEncoding = [text.encoding]::Default
  & $tempBatchFile $ArgumentList
  # 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." }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM