Reputation: 83
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
Upvotes: 1
Views: 4515
Reputation: 437109
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, but it has severe limitations:
$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
'@
# !! THIS MAY OR MAY NOT WORK AS INTENDED, DEPENDING ON THE SPECIFIC COMMANDS.
# Simply sends the commands via stdin.
# /q suppresses printing the prompt between commands, and
# /d suppresses autorun entries - see cmd /?
$commands | cmd /q /d
Limitations:
for
loops and escaped %
chars. do not work,
because, cmd.exe
parses commands provided via stdin expecting interactive command-line syntax, not batch-file syntax, which - regrettably, and for historical reasons - differ:
%%i
as the iterator variable, whereas interactively you must use %i
(just one %
); e.g., providing a statement such as for /l %%i in (1,1,3) do echo %%i
via stdin is a quiet no-op.%
signs as %%
(to use them as literals): for instance, you could use %%PATH%%
to produce literal %PATH%
on output; on the command line - and when piping via stdin - this does NOT work: you end up with %<value of variable>%
.
With this invocation style, cmd
will not automatically 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.)
exit
call to properly set the exit code.Character-encoding caveat: You need to (temporarily) set $OutputEncoding = [Console]::InputEncoding
so as to ensure that batch commands that contain non-ASCII characters are encoded the way cmd.exe
expects (that is, based on the active OEM code page).
Finally, there is a cosmetic issue, which, however, would also affect processing the output programmatically:
@echo off
as the first line, cmd.exe
's copyright message invariably prints first (e.g., Microsoft Windows [Version 10.0.19044.1826]...
), followed by one instance of the prompt string (e.g. C:\>
)For these reasons, you're generally better off writing the commands to a (temporary) batch file and invoking that:
Note: You can also use this function to execute the content of a batch file downloaded from the web with Invoke-WebRequest
/ Invoke-RestMethod
, as requested in this related question.
function Invoke-AsBatchFile {
param(
[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).
}
Sample invocation:
$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." }
Upvotes: 3
Reputation: 10034
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
}
Upvotes: 1