Powershell2/bat hybrid?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Powershell2/bat hybrid?

#1 Post by npocmaka_ » 16 Apr 2014 03:51

(UPDATE-Just to ease search here)Here's best way to achieve this according to me:

Code: Select all

<# : 
@echo off
echo start ps
:: $cmdargs variable will contain the command line.
powershell $cmdargs="""%*""";$exp=$(Get-Content '%~f0') -replace """`n""",""";""" ;invoke-expression """$exp"""
exit /b 0
#>

Write-Host "Hello from PowerShell";
Write-Host "Hello from PowerShell"


(end of update.)




Does anybody else have tried something in this direction?
The main impediment are the extension restrictions for both - cmd.exe and powershell.
I haven't find a way to drive the powershell to run a file with extension different from .ps1 .psc1 .psd1 .psm1 . One way is to use a temporary file and additional calling:

Code: Select all

@echo off
rem "installing" a caller.A files with .psc1 extension will be able to execute batch code but is not perfect as the %0 argument is lost
if not exist "c:\caller.bat" (
   echo @echo off
   echo copy "%%~nx1"  "%%temp%%\%%~nx1.bat" /Y ^>nul
   echo "%%temp%%\%%~nx1.bat"  %%*
) > c:\caller.bat

:: to restore use   assoc .psc1=Microsoft.PowerShellConsole.1
assoc .psc1=batps
ftype batps=c:\caller "%1" %*


and a test .psc1 file:

Code: Select all

set dummy="
goto :pscomment
"   
<#
:pscomment

echo echo from bat
PowerShell -NoProfile -ExecutionPolicy Bypass -file "%~dpfnx1"

exit /b 0
#>

echo "echo from powershell"



Probably it can be done with temporary powershell caller . Any idea how powershell manages its extensions? And ideas for a better way to hybrid them?
Last edited by npocmaka_ on 05 Jan 2015 11:13, edited 2 times in total.

siberia-man
Posts: 126
Joined: 26 Dec 2013 09:28
Contact:

Re: Powershell2/bat hybrid?

#2 Post by siberia-man » 16 Apr 2014 07:19

Code: Select all

type filename.bat | powershell -c -

einstein1969
Expert
Posts: 763
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Powershell2/bat hybrid?

#3 Post by einstein1969 » 16 Apr 2014 08:15

Hi,

I don't know... Little brainstorm on graphical managment too:

- But we can add %* to parameter of powershell?

[HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\0\Command]
@="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" \"-file\" \"%1\" %*"

- Or use the "DropHandler" of wsh. Adding an shellext?

- Then Dinamic rotate the verb? 0->open etc.

einstein1969

Squashman
Expert
Posts: 4114
Joined: 23 Dec 2011 13:59

Re: Powershell2/bat hybrid?

#4 Post by Squashman » 16 Apr 2014 09:14

Gosh I wish I could remember all of this. Back in 2008 I got heavily into PowerShell and we added the drag and drop capability with a registry edit. I might have the REG files somewhere.

I am not sure about creating a hybrid file with batch and powershell in the same file.

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Powershell2/bat hybrid?

#5 Post by npocmaka_ » 18 Apr 2014 01:35

I think I've found a way I like - without tickling the registry and no temp/calling files (and inspirited from the siberia-man reply )


Code: Select all

@echo off
powershell "$cmdllineargs="""%*""";$expression=""""";$flag=0;$reader=[System.IO.File]::OpenText("""%~dpsnx0""");try{for(;;){$line=$reader.ReadLine();if($line -eq $null -or $line -eq """###end powershell###"""){break};if($flag -eq 1){$expression=$expression+""";"""+$line}if($line -eq """###start powershell###"""){$flag=1};}}finally{$reader.Close()};Invoke-Expression -Command $expression"

echo echo from bat
exit /b 0

###start powershell###
$a=1
$b=1
$a+$b
"is the sum of 1 and 1"
###end powershell###


still I'm not sure how robust and fast it is.And need to think about command line arguments.
Last edited by npocmaka_ on 18 Apr 2014 02:05, edited 1 time in total.

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Powershell2/bat hybrid?

#6 Post by npocmaka_ » 18 Apr 2014 02:01

And my chimera script (because hybrid is too weak word ) [ jff ]

batch/jscript/powershell/vbscript script:


Code: Select all

@if (@X)==(@Y) @end/*JScript comment
@echo off
echo produced from bat
mshta vbscript:execute("CreateObject(""Scripting.FileSystemObject"").GetStandardStream(1).Write(""produced from vbscript""):Close") |findstr "^"
powershell "$expression=""""";$flag=0;$reader=[System.IO.File]::OpenText("""%~dpsnx0""");try{for(;;){$line=$reader.ReadLine();if($line -eq $null -or $line -eq """###end powershell###"""){break};if($flag -eq 1){$expression=$expression+""";"""+$line}if($line -eq """###start powershell###"""){$flag=1};}}finally{$reader.Close()};Invoke-Expression -Command $expression"
cscript /E:JScript /nologo "%~f0"
exit /b 0

###start powershell###
"produced from powershell"
###end powershell###
**/
WScript.Echo("Produced from jscript")

siberia-man
Posts: 126
Joined: 26 Dec 2013 09:28
Contact:

Re: Powershell2/bat hybrid?

#7 Post by siberia-man » 21 Apr 2014 14:44

Hi npocmaka_, could you test this code below with more complex scenarios? Does it work properly? Does it support command line arguments?

I have googled this issue and found few good ideas that inspired me to produce the following ugly but working code:

Code: Select all

@echo off

powershell -Command Invoke-Expression $( $i = ( $s = Get-Content '%~f0' ) ^| Select-String -Pattern '^^-=- POWERSHELL -=-$' ^| %% { $_.LineNumber }; if ( -not $i -or $i.length -gt 1 ) { Write-Host 'PoSH-in-CMD Embedding Error' -Foreground Red; exit 255; } [String]::Join( [Environment]::NewLine, $s[$i..$s.length] ) ) %*

goto :EOF

-=- POWERSHELL -=-

Write-Host "Hello from PowerShell"


The same code but the powershell invocation part has broken into several lines for better readability.

Code: Select all

@echo off

powershell -Command Invoke-Expression $( ^
   $i = ( $s = Get-Content '%~f0' ) ^
      ^| Select-String -Pattern '^^-=- POWERSHELL -=-$' ^
      ^| %% { $_.LineNumber }; ^
   if ( -not $i -or $i.length -gt 1 ) { ^
      Write-Host 'PoSH-in-CMD Embedding Error' -Foreground Red; ^
      exit 255; ^
   } ^
   [String]::Join( [Environment]::NewLine, $s[$i..$s.length] ) ^
) %*

goto :EOF

-=- POWERSHELL -=-

Write-Host "Hello from PowerShell"


The main goal was to make the resulting code simpler as much as possible. POSH is far from my favorite languages. Hope, if someone could improve the code above I would have added it to my collection for possible future usage.

connect.microsoft.com/PowerShell/feedback/details/724524/make-it-easier-to-wrap-powershell-scripts-in-batch-files
www.daveamenta.com/2013-03/embed-powershell-inside-a-batch-file/
www.daveamenta.com/2013-03/embed-powershell-inside-a-batch-file/

UPDATE: Little improvement for more controlling of the code parsing to avoid some possible errors and make the script closer to humans.

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Powershell2/bat hybrid?

#8 Post by npocmaka_ » 21 Apr 2014 23:27

Hi siberia-man,

Here's more simplified method inspired from the embedded-in-batch-html that you've shown :D :

Code: Select all


<# :
@echo off
echo start ps
powershell $cmdargs="""%*""";$exp=$(Get-Content '%~f0') -replace """`n""",""";""" ;invoke-expression """$exp"""
exit /b 0
#>

Write-Host "Hello from PowerShell";
Write-Host "Hello from PowerShell"


As for the command line - for now I'm defining additional variable cmdline - $cmdline="""*%"""; that later can be used somehow in powershell part.


I've tested the -=- POWERSHELL -=- script and it brokes every time when command line parameters are passed :?

siberia-man
Posts: 126
Joined: 26 Dec 2013 09:28
Contact:

Re: Powershell2/bat hybrid?

#9 Post by siberia-man » 22 Apr 2014 03:23

Thanks for updates, npocmaka_. I knew that suggestion had problems.

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Powershell2/bat hybrid?

#10 Post by npocmaka_ » 25 Apr 2014 00:49

and with self-rename (I consider this as a risky technique):

Code: Select all

<# :
@echo off
echo start ps
( del /q /f "%0.ps1" >nul 2>&1
  ren "%~dpfnx0" "%0.ps1"
  call PowerShell -NoProfile -ExecutionPolicy Bypass -file "%~dpfnx0.ps1" %*
  ren "%~dpfnx0.ps1" "%~nx0"  )
exit /b 0
#>

Write-Host "Hello from PowerShell";
Write-Host "Hello from PowerShell"

siberia-man
Posts: 126
Joined: 26 Dec 2013 09:28
Contact:

Re: Powershell2/bat hybrid?

#11 Post by siberia-man » 03 Nov 2014 17:02

Found few hours ago:
blogs.msdn.com/b/jaybaz_ms/archive/2007/04/26/powershell-polyglot.aspx
stackoverflow.com/a/2611487/3627676

In my opinions this solution is the best of known. Also you can find my attempt to compile all available solutions in one script. See this thread: viewtopic.php?p=37780#p37780

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Powershell2/bat hybrid?

#12 Post by npocmaka_ » 04 Nov 2014 05:45

siberia-man wrote:Found few hours ago:
blogs.msdn.com/b/jaybaz_ms/archive/2007/04/26/powershell-polyglot.aspx
stackoverflow.com/a/2611487/3627676

In my opinions this solution is the best of known. Also you can find my attempt to compile all available solutions in one script. See this thread: viewtopic.php?p=37780#p37780


Interesting indeed ,but the the main advantage according to me is the compatibility with powershell version 1.
the "@@"s make the code harder for reading and it again uses again the same idea -Invoke-Expression and new lines replaced with ";"

siberia-man
Posts: 126
Joined: 26 Dec 2013 09:28
Contact:

Re: Powershell2/bat hybrid?

#13 Post by siberia-man » 04 Nov 2014 06:16

Yep. Seems there are no better ways to hybridize cmd and powershell (or embed powershell into a batch file). Anyway this solution keeps ability for piping and allows using of command lines arguments through $args (I guess this is standard variable in powershell).

siberia-man
Posts: 126
Joined: 26 Dec 2013 09:28
Contact:

Re: Powershell2/bat hybrid?

#14 Post by siberia-man » 22 Mar 2015 17:40

siberia-man wrote:Seems there are no better ways to hybridize cmd and powershell (or embed powershell into a batch file).

I am glad to say that I have been wrong. One man from Russian Gray forum and I have had private discussion regarding ps1+bat hybrid. This discussion gave birth the better solution how to hybridize powershell scripts within batch file.

there is list of advantage
1. the code is little bit shorter now (approx. on 50-60 bytes)
2. the trick with $input variable has been removed because scriptblock allows to pass data from STDIN directly (invoke-expression doesn't allow).
3. with scriptblock it is possible to describe input arguments within "param()" block.
4. it is possible to wrap arguments with double quotes " (there is only option in dos) and single quotes ' (that is possible in powershell)

There is example for tests (just save it as batch file):

Code: Select all

<# :
@echo off
setlocal
set "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
#>

$args;

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Powershell2/bat hybrid?

#15 Post by npocmaka_ » 25 Mar 2015 02:09

Never heard of scriptblock before.Nice feature and pretty useful in this case.
A little bit more info:

http://www.padisetty.com/2014/05/all-ab ... block.html

Post Reply