asmfreak
Goto Top

Return-Value eines PS-Scripts in einer Batch-Datei auswerten

Hallo,

ich bin neu, verzeiht mir also bitte Anfangsfehler! Es wäre schön, wenn Ihr mich dann konstruktiv darauf aufmerksam machen könntet. Danke!

Seit einiger Zeit sitze ich an zwei Problemen, von denen ich eines nicht verstehe und beim zweiten nicht weiterkomme. Mein Ziel ist, aus einer Batch-Datei ein PowerShell-Script aufzurufen und ein Return-Wert dieses Scripts in der Batch auszuwerten.

Zunächst das PS-Script. Es funktioniert wie erwartet aus einer PowerShell heraus.
Param(
  [Parameter(Mandatory=$True)]
  [String]$Arg1,
  [String]$Arg2 
)

function CheckSomething
{
  Param(
    [ValidatePattern('^([0-9])$')]  
    [String]$ToCheck
  )
}

function DoSomething
{
  begin {
  }
  process {
    
  }
  end {
  }
}

try {
  CheckSomething Arg1
}
catch {
  Write-Warning "Error 1"  
  Return 1
}

try {
  DoSomething Arg1 
  Write-Host Arg2 
  Return 0
}
catch {
  Write-Warning "Error 2"  
  Return 2
}
Kleiner Schönheitfehler: Aus einer PowerShell aufgerufen, wird nicht nur die jeweilige Meldung angezeigt, sondern auch darunter der Return-Wert. Kann man das verhindern?

Und hier die Batch-Datei, meine beiden Probleme habe ich mit Doppel-Sternchen gerahmt
@echo off
setlocal
set Path=%~f0
set Path=%Path:.bat=.ps1%
set Silent=
set RetValue=

rem do a lot
set Silent=true
rem do more

echo call in main
echo Params:          FilePath: %Path%, SilentSW: %Silent%
echo Powershell call: Powershell.exe -ExecutionPolicy Bypass -File %Path% %Silent%
echo.

**Powershell.exe -ExecutionPolicy Bypass -File %Path% %Silent%**
echo.

echo psExec call:     call :psExec %Path% %Silent% RetValue 
echo.

call :psExec %Path% %Silent% RetValue
echo.
echo RetValue: %RetValue%

exit /b

:psExec <FilePath> <SilentSW> <RetValue>
echo call in function
echo Params:          FilePath: %1, SilentSW: %2
echo. 
echo Argument:        `Powershell -ExecutionPolicy Bypass -File ^%1 ^%2`
echo.
for /F "usebackq tokens=1" %%i in (**`Powershell -ExecutionPolicy Bypass -File %1 %2`**) do set ReturnValue=%%i  
  set "%3=%ReturnValue%"  
Goto:eof

Problem 1:
Die sternchen-gerahmte Zeile Powershell.exe -ExecutionPolicy Bypass -File %Path% %Silent% produziert den Fehler Der Befehl "Powershell" ist entweder falsch geschrieben oder konnte nicht gefunden werden" (s. erster Screenshot unten).
Bevor Ihr fragt: PowerShell ist vorhanden, liegt in PATH, kann aus einer Kommandozeile aufgerufen werden und wird auch, in einer anderen Batch-Datei, mit identischer Zeile korrekt aufgerufen. Das verstehe ich nicht!

Problem 2:
Die gleiche Meldung ergibt sich, wenn das Script über die Funktion psExec ausgeführt wird (s. zweiter Screenshot unten). Da das auch in der anderen Batch-Datei so ist, in der Problem #1 nicht auftritt, scheint das daran zu liegen, wie es dort aufgerufen wird. Ich weiß aber nicht, wo ich den Fehler mache.

Ziel der Funktion psExec ist, das PS-Script auszuführen, dessen Return-Code zu ermitteln und an die Batch zu übergeben. Kann mir jemand dabei helfen?

Danke für Eure Mühe und Hilfe.
_scrtach1
_scrtach2

Content-ID: 671924

Url: https://administrator.de/forum/return-value-eines-ps-scripts-in-einer-batch-datei-auswerten-671924.html

Ausgedruckt am: 16.03.2025 um 10:03 Uhr

rubberman
rubberman 13.03.2025 um 20:51:28 Uhr
Goto Top
Moin.

Der Kardinalfehler ist in Zeile 3 deines Batch Scripts. "Path" ist eine vordefinierte Umgebungsvariable, die die Suchpfade für ausführbare Dateien enthält, für die du keinen Pfad angibst. Heißt, Powershell wird nicht gefunden, weil du diese Variable neu definiert/überschrieben hast. Nutze einen anderen Variablenname und prüfe welche der Probleme noch übrig bleiben.

Gruß
Steffen
ASMFreak
ASMFreak 13.03.2025 um 22:09:34 Uhr
Goto Top
Hallo Steffen

Danke für den Hinweis: Man kann ja so blind sein! Ich schreibe nicht häufig Batch-Scripts (daher auch Problem 2, mit dem ich nicht fertig werde), sondern bewege mich entweder in höheren Regionen (C#, C++) oder lieber noch niedrigeren (ASM). Da "stören" keine Umgebungsvarablen, die man überschreiben könnte.
Das erste Problem ist damit gelöst, für das zweite habe ich die Scripte nochmals eingedampft (und um einen Parameter erweitert):

@echo off
setlocal
set PSPath=%~f0
set PSPath=%PSPath:.bat=.ps1%
set ReturnValue=
set Arg=
set Silent=

REM Das klappt jetzt
Powershell -ExecutionPolicy Bypass -File %PSPath% %Arg% %Silent%
echo.

REM Das noch nicht
call :psExec %HomePath% %Arg% %Silent% ReturnValue
echo %ReturnValue%
echo.

pause
exit /b

:psExec <FilePath> <Param> <SilentSW> <RetValue>
for /F "usebackq tokens=1" %%i in (`Powershell -ExecutionPolicy Bypass -File %1 %2 %3`) do set "%4=%ReturnValue%"  
Goto:eof

und

Param(
  [Parameter(Mandatory=$True)]
  [String]$Arg1,
  [String]$Arg2 
)

function CheckSomething
{
  Param(
    [ValidatePattern('^([0-9])$')]  
    [String]$ToCheck
  )
}

function DoSomething
{
  begin {
  }
  process {
    
  }
  end {
  }
}

try {
  CheckSomething Arg1
}
catch {
  Write-Warning "Error 1"  
  Return 1
}

try {
  DoSomething Arg1 
  Write-Host Arg2 
  Return 0
}
catch {
  Write-Warning "Error 2"  
  Return 2
}

Das Ergebnis siehe Screenshot
_scratch3

Gruß ASMFreak
ASMFreak
ASMFreak 13.03.2025 um 22:49:41 Uhr
Goto Top
Ich habe es heute mit den Paths! Ist schon spät nach einem langen Tag. Da war noch ein %HomePath% im Call-Befehl, aber auch nach Ersetzen durch %PSPath% bleiben zwei Syntaxfehler.

Gehe jetzt erst einmal off...

Gruß ASMFreak
rubberman
Lösung rubberman 13.03.2025 um 23:19:46 Uhr
Goto Top
Haha, ja hab ich gesehen.

@echo off
setlocal

set "PSPath=%~dpn0.ps1"  

REM set "Arg=0"  
set "Arg=X"  

set "Silent=whatever"  

Powershell -ExecutionPolicy Bypass -File "%PSPath%" "%Arg%" "%Silent%"  
set "ReturnValue=%errorlevel%"  

echo(
echo ReturnValue: %ReturnValue%

pause

Param(
  [Parameter(Mandatory=$True)]
  [String]$Arg1,
  [String]$Arg2 
)

function CheckSomething
{
  Param(
    [ValidatePattern('^([0-9])$')]    
    [String]$ToCheck
  )
}

function DoSomething
{
  begin {
  }
  process {
    
  }
  end {
  }
}

try {
  CheckSomething $Arg1
}
catch {
  Write-Warning "Error 1"    
  exit 1
}

try {
  DoSomething $Arg1 
  Write-Host $Arg2 
  exit 0
}
catch {
  Write-Warning "Error 2"    
  exit 2
}

Ich vermute zumindest dass du was in der Art versuchst ...

Gruß
Steffen
ASMFreak
ASMFreak 14.03.2025 um 11:28:00 Uhr
Goto Top
Hallo Steffen,

ja, genau so! Herzlichen Dank für Deine Hilfe.

Gruß
ASMFreak
ASMFreak
ASMFreak 14.03.2025 um 14:42:22 Uhr
Goto Top
Hallo Steffen,

ich nerve nochmal face-wink
Klappt alles ganz prima. Auch wenn ich das PS-Skript mit Adminrechten ausführen will, klappt's. Ich nutze die Zeile (und habe penibel auf die Paths geachtet face-wink )
PowerShell -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File %PSPath% %Arg1% %Arg2% -Verb RunAs}  
Ein Problem habe ich allerdings wieder mit den ReturnValues: Falls der Powershell-Aufruf aus irgendeinem Grund nicht klappt, wird ein ReturnCode zurückgegeben. Klappt der aber, immer "0", egal, ob in der dem zweiten Powershell-Aufruf übergebenen Kommandozeile etwas nicht stimmt, und schon gleich gar nicht, wenn vom Skript ein Fehler gemeldet wird.

Gibt es einen Weg, die Returncodes durch die Kette durchzureichen?

Danke für Deine Hilfe,

Gruß,
ASMFreak
rubberman
Lösung rubberman 14.03.2025 aktualisiert um 17:44:55 Uhr
Goto Top
Naja, je mehr Sprachen mit ihrer eigenen Syntax du über mehrere Prozesse hinweg verschachtelst, um so komplizierter wird das ganze natürlich.
PowerShell -Command ^"^& {exit (Start-Process -FilePath 'PowerShell.exe' -Wait -PassThru -Verb RunAs -ArgumentList @('-ExecutionPolicy', 'Bypass', '-File', '\"%PSPath%\"', '\"%Arg1%\"', '\"%Arg2%\"')).ExitCode}^"  

Gruß
Steffen
ASMFreak
ASMFreak 14.03.2025 um 19:27:14 Uhr
Goto Top
Danke!
Ist klar! Und je mehr Sprachen mit ihrer eigenen Syntax ich über mehrere Prozesse hinweg verschachtle, desto mehr steige ich aus, denn umso komplizierter wird das Ganze natürlich face-wink

Nochmale herzlichen Dank,
Gruß,
ASMFreak