When invoking PowerShell from cmd/bat files -EncodedCommand is a great way to pass the actual PowerShell code to powershell.exe without worrying about escaping various special characters. This allows you to have just a single batch file (with no external PowerShell scripts whatsoever) which has PowerShell code right inside the file which looks something like:
powershell.exe -EncodedCommand DQAKAA0ACgAJACQAcABhAHIAYQBtAHMAIAA9ACAARwBlAHQALQBDAG8AbgB0AGUAbgB0ACAAJABlAG4AdgA6AFQARQBNAFAAXABwAGEAcgBhAG0AcwAuAHQAeAB0AA0ACgAJACIAUwBlAGUAIAB3AGgAaQBjAGgAIABwAGEAcgBhAG0AZQB0AGUAcgBzACAAUABvAHcAZQByAFMAaABlAGwAbAAgAGcAbwB0ADoAIAAkAHAAYQByAGEAbQBzACIADQAKAAkADQAKAA==
What I was recently pointed to, is that this approach has one limitation: how do you pass parameters to this PowerShell code? For example, say, cmd file gets parameters from command-line and wants to pass them to PowerShell – you obviously don’t know the values in advance so you cannot pre-encode them.
The easiest way that I found is: simply put the value from cmd file to a temporary file, and then read the file from PowerShell code.
So, for illustration purpose, my super-advanced PowerShell script will simply output the parameters:
$params = Get-Content $env:TEMP\params.txt
"See which parameters PowerShell got: $params"
As you can see, I am getting the parameters by reading the content of pre-defined file in %TEMP% location.
Now, let’s encode this by running:
$code = {
$params = Get-Content $env:TEMP\params.txt
"See which parameters PowerShell got: $params"
}
[convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code))
In my case I got:
DQAKAA0ACgAJACQAcABhAHIAYQBtAHMAIAA9ACAARwBlAHQALQBDAG8AbgB0AGUAbgB0ACAAJABlAG4AdgA6AFQARQBNAFAAXABwAGEAcgBhAG0AcwAuAHQAeAB0AA0ACgAJACIAUwBlAGUAIAB3AGgAaQBjAGgAIABwAGEAcgBhAG0AZQB0AGUAcgBzACAAUABvAHcAZQByAFMAaABlAGwAbAAgAGcAbwB0ADoAIAAkAHAAYQByAGEAbQBzACIADQAKAAkADQAKAA==
Now we are ready to put this into cmd:
echo %* > %TEMP%\params.txt
powershell.exe -EncodedCommand DQAKAA0ACgAJACQAcABhAHIAYQBtAHMAIAA9ACAARwBlAHQALQBDAG8AbgB0AGUAbgB0ACAAJABlAG4AdgA6AFQARQBNAFAAXABwAGEAcgBhAG0AcwAuAHQAeAB0AA0ACgAJACIAUwBlAGUAIAB3AGgAaQBjAGgAIABwAGEAcgBhAG0AZQB0AGUAcgBzACAAUABvAHcAZQByAFMAaABlAGwAbAAgAGcAbwB0ADoAIAAkAHAAYQByAGEAbQBzACIADQAKAAkADQAKAA==
Basically, all I do is write the command-line arguments which the batch file got to a temporary file, and then invoke our PowerShell script.
And here’s the proof that this actually works:
c:\Scripts>pass-params.cmd Here are my parameters!
c:\Scripts>echo Here are my parameters! 1>C:\Users\dsotniko\AppData\Local\Temp\
params.txt
c:\Scripts>powershell.exe -EncodedCommand DQAKAA0ACgAJACQAcABhAHIAYQBtAHMAIAA9A
CAARwBlAHQALQBDAG8AbgB0AGUAbgB0ACAAJABlAG4AdgA6AFQARQBNAFAAXABwAGEAcgBhAG0AcwAuA
HQAeAB0AA0ACgAJACIAUwBlAGUAIAB3AGgAaQBjAGgAIABwAGEAcgBhAG0AZQB0AGUAcgBzACAAUABvA
HcAZQByAFMAaABlAGwAbAAgAGcAbwB0ADoAIAAkAHAAYQByAGEAbQBzACIADQAKAAkADQAKAA==
See which parameters PowerShell got: Here are my parameters!
Now you can have a single batch file, encapsulating PowerShell code and capable of passing parameters to it!