Pass parameter to powershell encoded command

4k views Asked by At

I have a script which has quite a lot of lines. I can easily paste this script in a scriptblock parameter without having to edit it (e.g. put backslashes in front of quotes in the script). I can then encode the script so it can be passed to powershell as en encoded parameter:

$myscript = {
#paste of simplified script
$calc = 6 + 9
echo $calc
}

# Convert script to a string
$command = $carvingScript.ToString()
# Convert string to base64 encoded command
$bytes = [System.Text.Encoding]::Unicode.GetBytes( $command )
$encodedCommand = [Convert]::ToBase64String( $bytes )

I would like to be able to pass one parameter in the script that gets base64 converted. Like this:

$parameter = 9
$myscript = {
$calc = 6 + $parameter
echo $calc
}

Any ideas how to tackle this? I know scriptblock can contain arguments, but in order to parse the argument the whole script needs to be parsed, not just the one parameter

2

There are 2 answers

3
Patrick Meinecke On BEST ANSWER

The direct answer to how to add variables to a script block is this:

$parameter = 9

$myscript = @'
$calc = 6 + {0}
echo $calc
'@ -f $parameter

$scriptblock = [scriptblock]::Create($myscript)

Basically build it as a string and use the create method from [scriptblock] to convert.

But you can skip creating the scriptblock since you will just convert it back to a string directly afterwards.

0
Gucu112 On

It's an old post, but I found this article which worked for me, so I want to share it with you dear community :)

You can use param block with mandatory parameters inside your script block:

$myscript = {
    param
    (
        [Parameter(Mandatory)]
        [decimal]
        $First,

        [Parameter(Mandatory)]
        [decimal]
        $Second
    )
    [decimal]($First + $Second)
}

$bytes = [System.Text.Encoding]::Unicode.GetBytes($myscript)
$encodedCommand = [Convert]::ToBase64String($bytes)
$encodedCommand | Set-Content 'C:\temp\encodedCommand.txt' -Encoding UTF8

Then pass parameters by pipeline between two powershell.exe calls:

powershell.exe -noprofile -command "3.3, 2.7" | powershell.exe -encodedcommand DQAKACAAIAAgACAAcABhAHIAYQBtAA0ACgAgACAAIAAgACgADQAKACAAIAAgACAAIAAgACAAIABbAFAAYQByAGEAbQBlAHQAZQByACgATQBhAG4AZABhAHQAbwByAHkAKQBdAA0ACgAgACAAIAAgACAAIAAgACAAWwBkAGUAYwBpAG0AYQBsAF0ADQAKACAAIAAgACAAIAAgACAAIAAkAEYAaQByAHMAdAAsAA0ACgANAAoAIAAgACAAIAAgACAAIAAgAFsAUABhAHIAYQBtAGUAdABlAHIAKABNAGEAbgBkAGEAdABvAHIAeQApAF0ADQAKACAAIAAgACAAIAAgACAAIABbAGQAZQBjAGkAbQBhAGwAXQANAAoAIAAgACAAIAAgACAAIAAgACQAUwBlAGMAbwBuAGQADQAKACAAIAAgACAAKQANAAoAIAAgACAAIABbAGQAZQBjAGkAbQBhAGwAXQAoACQARgBpAHIAcwB0ACAAKwAgACQAUwBlAGMAbwBuAGQAKQANAAoA

This is using Powershell interactive input mode which is visible in the overall output, so be aware if you pass any passwords or secrets:

cmdlet  at command pipeline position 1
Supply values for the following parameters:
First: 3.3
Second: 2.7
6.0

If you ever try to have list (array) parameter and pass list of values to the encoded command then you need to remember that last array element must be an empty string - this is how you trick interactive input mode into setting the list parameter.

You also need to remember to do not mark list parameter as ValueFromPipeline otherwise, it will not consume values properly.

$command = {
    param
    (
        [Parameter(Mandatory)]
        [string[]]
        $MyList
    )
    $MyList | ForEach-Object { Write-Host $_ }
}

$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
"powershell.exe -noprofile -command `"'test1', 'test2', 'test3', ''`" | powershell.exe -encodedcommand $encodedCommand" | Set-Content 'C:\temp\test.txt' -Encoding UTF8
PS C:\temp> powershell.exe -noprofile -command "'test1', 'test2', 'test3', ''" | powershell.exe -encodedcommand DQAKACAAIAAgACAAcABhAHIAYQBtAA0ACgAgACAAIAAgACgADQAKACAAIAAgACAAIAAgACAAIABbAFAAYQByAGEAbQBlAHQAZQByACgATQBhAG4AZABhAHQAbwByAHkAKQBdAA0ACgAgACAAIAAgACAAIAAgACAAWwBzAHQAcgBpAG4AZwBbAF0AXQANAAoAIAAgACAAIAAgACAAIAAgACQATQB5AEwAaQBzAHQADQAKACAAIAAgACAAKQANAAoAIAAgACAAIAAkAE0AeQBMAGkAcwB0ACAAfAAgAEYAbwByAEUAYQBjAGgALQBPAGIAagBlAGMAdAAgAHsAIABXAHIAaQB0AGUALQBIAG8AcwB0ACAAJABfACAAfQANAAoA


cmdlet  at command pipeline position 1
Supply values for the following parameters:
MyList[0]: test1
MyList[1]: test2
MyList[2]: test3
MyList[3]:
test1
test2
test3

I hope it'll help someone in the future. Peace!