How to run a PowerShell script within a Windows batch file How to run a PowerShell script within a Windows batch file powershell powershell

How to run a PowerShell script within a Windows batch file


This one only passes the right lines to PowerShell:

dosps2.cmd:

@findstr/v "^@f.*&" "%~f0"|powershell -&goto:eofWrite-Output "Hello World" Write-Output "Hello some@com & again" 

The regular expression excludes the lines starting with @f and including an & and passes everything else to PowerShell.

C:\tmp>dosps2Hello WorldHello some@com & again


It sounds like you're looking for what is sometimes called a "polyglot script". For CMD -> PowerShell,

@@:: This prolog allows a PowerShell script to be embedded in a .CMD file.@@:: Any non-PowerShell content must be preceeded by "@@"@@setlocal@@set POWERSHELL_BAT_ARGS=%*@@if defined POWERSHELL_BAT_ARGS set POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%@@PowerShell -Command Invoke-Expression $('$args=@(^&{$args} %POWERSHELL_BAT_ARGS%);'+[String]::Join([char]10,$((Get-Content '%~f0') -notmatch '^^@@'))) & goto :EOF

If you don't need to support quoted arguments, you can even make it a one-liner:

@PowerShell -Command Invoke-Expression $('$args=@(^&{$args} %*);'+[String]::Join([char]10,(Get-Content '%~f0') -notmatch '^^@PowerShell.*EOF$')) & goto :EOF

Taken from http://blogs.msdn.com/jaybaz_ms/archive/2007/04/26/powershell-polyglot.aspx. That was PowerShell v1; it may be simpler in v2, but I haven't looked.


Here the topic has been discussed. The main goals were to avoid the usage of temporary files to reduce the slow I/O operations and to run the script without redundant output.

And here's the best solution according to me:

<# :@echo offsetlocalset "POWERSHELL_BAT_ARGS=%*"if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%"endlocal & powershell -NoLogo -NoProfile -Command "$input | &{ [ScriptBlock]::Create( ( Get-Content \"%~f0\" ) -join [char]10 ).Invoke( @( &{ $args } %POWERSHELL_BAT_ARGS% ) ) }"goto :EOF#>param(    [string]$str);$VAR = "Hello, world!";function F1() {    $str;    $script:VAR;}F1;

An even better way (seen here):

<# : batch portion (begins PowerShell multi-line comment block)@echo off & setlocalset "POWERSHELL_BAT_ARGS=%*"echo ---- FROM BATCHpowershell -noprofile -NoLogo "iex (${%~f0} | out-string)"exit /b %errorlevel%: end batch / begin PowerShell chimera #>$VAR = "---- FROM POWERSHELL";$VAR;$POWERSHELL_BAT_ARGS=$env:POWERSHELL_BAT_ARGS$POWERSHELL_BAT_ARGS

where POWERSHELL_BAT_ARGS are command line arguments first set as variable in the batch part.

The trick is in the batch redirection priority - this line <# : will be parsed like :<#, because redirection is with higher priority than the other commands.

But the lines starting with : in batch files are taken as labels - i.e., not executed. Still this remains a valid PowerShell comment.

The only thing left is to find a proper way for PowerShell to read and execute %~f0 which is the full path to the script executed by cmd.exe.