Skip to content

Instantly share code, notes, and snippets.

@OddMorning
Created February 9, 2024 13:33
Show Gist options
  • Save OddMorning/e3720580fe03e8e5245e908acaae6472 to your computer and use it in GitHub Desktop.
Save OddMorning/e3720580fe03e8e5245e908acaae6472 to your computer and use it in GitHub Desktop.
Run PowerShell from Batch
/ 2>nul & @set "a=%* ''" & call set "a=%%a:"='%%"
@PowerShell -Command "$CMDScriptRoot = '%~dp0'; $CMDCommandPath = '%~f0'; ICM $([ScriptBlock]::Create((@('','') + $(Type '%~f0' | Select -Skip 2) | Out-String))) -Args $(echo %a%)" & exit /b
$e=[char]0x1b;"$e[2F$e[J$e[1F";rv e
Write-Host 🏠 Script path: $CMDCommandPath
Write-Host 🏠 Script dir: $CMDScriptRoot
Write-Host ✅ Argument 1: $($args[0])
Write-Host ✅ Argument 2: $($args[1])
###### Notes:
#
# - Supports both ANSI and UTF-8 encodings
# - CMD tries to start BOM as a command, " 2>nul" suppresses an error for UTF8 files, "/" doesn't break ANSI files
# - The rest of the first line converts all " into '
# - $args always contains one argument more than needed ("a=%* ''").
# - Due to how CMD works, "%a%" turns into "='" when no arguments passed, which breaks the whole script
# - ICM is an alias for Invoke-Command
# - @('','') is needed to show proper error line number
# - $PSScriptRoot doesn't work, you have to use $CMDScriptRoot instead
# - $PSCommandPath doesn't work, you have to use $CMDCommandPath instead
# - The third line clears the "/ 2>nul" consequences:
# - $e=[char]0x1b; -- Create "$e" ("`e" doesn't exist in PS v5.1)
# - "[2F" -- Go two lines up that left after "/ 2>nul" execution
# - "[J" -- Clear screen after cursor pos
# - "[1F" -- Kind of shorter version of "Write-Host -NoNewline"
# - rv e -- Remove "$e"
#
######
Put one of these in the beginning of .cmd file:
###### One-liner, the simplest version:
@PowerShell -Command "ICM $([ScriptBlock]::Create((@('') + $(Type '%~f0' | Select -Skip 1) | Out-String)))" & exit /b
###### One-liner (2 arguments, $CMDCommandPath support):
@PowerShell -Command "$CMDCommandPath = '%~f0'; ICM $([ScriptBlock]::Create((@('') + $(Type '%~f0' | Select -Skip 1) | Out-String))) -Args @('%~1','%~2')" & exit /b
######
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment