Batch files (.bat
and .cmd
) are interpreted by cmd.exe
, the legacy command processor ("Command Prompt"), not by PowerShell.
You therefore cannot pipe the contents of a batch file directly to a PowerShell CLI (pwsh.exe
for PowerShell (Core) 7+) , (powershell.exe
for Windows PowerShell).
While you can pipe directly to cmd.exe
, doing so has severe limitations and may or may not work as intended, depending on the content of the batch file - see this answer.
Thus, you'll have to save the downloaded batch-file content to a (temporary) file and execute it from there, which PowerShell can help you automate:
Invoke-RestMethod -Uri https://foo.bar.dev/script.bat -UseBasicParsing |
ForEach-Object {
$tmpBatchFile = "$env:TEMP\~{0}_{1}.cmd" -f $PID, ([datetime]::Now.ToString('o') -replace '\D')
Set-Content -Encoding OEM $tmpBatchFile -Value $_
& $tmpBatchFile # Execute
Remove-Item $tmpBatchFile
}
Note:
Invoke-WebRequest
was replaced with Invoke-RestMethod
, which directly returns the data of interest and parses it, if appropriate; in the case of plain-text output, it is passed through as-is, as multiline text (after decoding into a .NET string).
It would be easy to create a function wrapper:
Precede the body of the ForEach-Object
statement with
function Invoke-AsBatchFile
, for instance, to define a function by that name.
Replace $_
in the body with $input
You can then use that function in the pipeline:
Invoke-RestMethod ... | Invoke-AsBatchFile
Note:
- If you were to download the content of PowerShell scripts (
*.ps1
), you would execute it via [scriptblock]::Create()
(as the more robust alternative to Invoke-Expression
(iex
)), which has the added advantage of being able to run in-process - but only if the script code doesn't contain exit
statements. See this answer for details.