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.