Pass string array through nested Invoke-Expression - powershell

My usecase consists 3 Scripts:
Script A.ps1 ← start script
Script B.ps1 ← script in the middle
Script C.ps1 ← target script to execute
Constraints: process spaces in path string[] array variables
Script A.ps1:
#SCRIPT EXPRESSION (TO PASS AS ARGUMENT)
$scriptC = "Script C.ps1"
$major = 1
$minor = 2
[string[]]$output = "Output A.txt", "Output B.txt", "Output C.txt"
$scriptExpression = 'powershell -File \"{0}\" -Major {1} -Minor {2} -Output {3}' -f ($scriptC, $major, $minor, $output)
Write-Host $scriptExpression -ForegroundColor Green
#SCRIPT EXPRESSION (TO CALL)
$scriptB = "Script B.ps1"
$config = "Debug"
$flag = 1
[string[]]$array = "String with space A", "String with space B"
$params = #("-File", "$scriptB", "-Config", $config, "-Flag", "$flag", "-ScriptExpression", $scriptExpression, "-Array", $array)
Write-Host "& powershell $params" -ForegroundColor Green
& powershell $params
Script B.ps1:
Param([string]$Config, [int]$Flag, [string]$ScriptExpression, [string[]]$Array)
Write-Host "`n_______________________________________________________________________________________`n"
Write-Host "Script B:`nConfig = $Config ($($Config.GetType()))`nFlag = $Flag ($($Flag.GetType()))`nScriptExpression = $ScriptExpression ($($ScriptExpression.GetType()))`nArray = $Array (Type: $($Array.GetType()) Length: $($Array.Length) <- WRONG LENGTH (2))" -ForegroundColor Yellow
Write-Host "`nCall Script C!" -ForegroundColor Yellow
Invoke-Expression $ScriptExpression
Script C.ps1:
Param([int]$Major, [int]$Minor, [string[]]$Output = #())
Write-Host "`n_______________________________________________________________________________________`n"
Write-Host "Script C:`nMajor = $Major ($($Major.GetType()))`nMinor = $Minor ($($Minor.GetType()))`nOutput = $Output (Type: $($Output.GetType()), Length: $($Output.Length)) <- WRONG EVERYTHING" -ForegroundColor Green
Output:
powershell -File \"Script C.ps1\" -Major 1 -Minor 2 -Output System.String[]
& powershell -File Script B.ps1 -Config Debug -Flag 1 -ScriptExpression powershell -File \"Script C.ps1\" -Major 1 -Minor 2 -Output System.String[] -Array System.String[]
_______________________________________________________________________________________
Script B:
Config = Debug (string)
Flag = 1 (int)
ScriptExpression = powershell -File "Script C.ps1" -Major 1 -Minor 2 -Output System.String[] (string)
Array = String with space A String with space B (Type: string[] Length: 1 ← WRONG LENGTH (2))
Call Script C!
_______________________________________________________________________________________
Script C:
Major = 1 (int)
Minor = 2 (int)
Output = System.String[] (Type: string[], Length: 1) ← WRONG EVERYTHING
How is it possible to pass these string[] arrays with spaces to another script?

I could achieve to call a Script C.ps1 from Script A.ps1 over Script B.ps1 with: (Content of Script B and C is in question)
$output = #("Output A.txt", "Output B.txt", "Output C.txt")
$array = #("String with space A", "String with space B")
#INVOKE EXPRESSION SCRIPT C
$varScript = $("'{0}\Script C.ps1'" -f ($PSScriptRoot))
$varMajor = 1
$varMinor = 2
$varOutput = "'" + $($output -join "','") + "'"
$expression = "& $varScript -Major $varMajor -Minor $varMinor -Output $varOutput"
$expression = """{0}""" -f ($expression) #WRAP IN DOUBLE QUOTES
#INVOKE EXPRESSION SCRIPT B
$varScript = $("'{0}\Script B.ps1'" -f ($PSScriptRoot))
$varConfig = "Debug"
$varFlag = 1
$varArray = "'" + $($array -join "','") + "'"
$call = "& $varScript -Config $varConfig -Flag $varFlag -ScriptExpression $expression -Array $varArray"
Invoke-Expression $call
Output:
Script B:
Config = Debug (string)
Flag = 1 (int)
ScriptExpression = & 'C:\ScriptTest\Script C.ps1' -Major 1 -Minor 2 -Output 'Output A.txt','Output B.txt','Output
C.txt' (string)
Array = String with space A String with space B (Type: string[] Length: 2)
Call Script C!
_______________________________________________________________________________________
Script C:
Major = 1 (int)
Minor = 2 (int)
Output = Output A.txt Output B.txt Output C.txt (Type: string[], Length: 3)
- Output A.txt
- Output B.txt
- Output C.txt

Related

Tshark captures on remote server with foreach -parallel loop on powershell

I'm traing to start 2 remote packet captures at same time on a winServer2016 with two nics, with tshark 3.4.5 and powershell 7.2.1.
The problem is that I can't found the correct sintax to pass variables to tshark...
$ScriptPath = "E:\CC12\Scripts\TShark"
$dateForDirLogs = (Get-Date).ToString('yyyy-MM-dd-HH')
$dateForLogs = (Get-Date).ToString('yyyy-MM-dd-HH.mm')
$logDir = "$ScriptPath\Logs"
$MyServer = "SRV1"
$LogFile = "$logDir\$($MyServer)_$($dateForLogs).txt"
$MySession = New-PSSession $MyServer -ConfigurationName PowerShell.7.2.1
Invoke-Command -Session $MySession -ScriptBlock {
$CptPathName = "E:\Captures\$using:dateForDirLogs"
$JobLogFile = "$CptPathName\RmJobsLog.txt"
$HName = $using:MyServer
$CptFilePub = "$CptPathName\$($HName)_PUB_$using:dateForLogs.pcapng"
$CptFilePri = "$CptPathName\$($HName)_PRI_$using:dateForLogs.pcapng"
$TsharkBin = "C:\Program Files\Wireshark\tshark.exe"
[string]$NicPub = & $TsharkBin -D | Select-String "Public"
$ifNumPub = $NicPub.Split("\")[0]
$NicPub = $NicPub.Replace($ifNumPub,'')
$NicPub = $NicPub.Replace(' (Public)','')
[string]$NicPri = & $TsharkBin -D | Select-String "Private"
$ifNumPri = $NicPri.Split("\")[0]
$NicPri = $NicPri.Replace($ifNumPri,'')
$NicPri = $NicPri.Replace(' (Private)','')
$FilterPub = "dst net 10.49.94.0/24"
$FilterTimePub = 300
$FilterSizePub = 307200
$FilterPri = "dst net 10.56.128.0/25"
$FilterTimePri = 300
$FilterSizePri = 307200
# echo variables
$CptPathName
$JobLogFile
$HName
$CptFilePub
$CptFilePri
$NicPub
$NicPri
$FilterPub
$FilterPri
$CptCMDs = #(
"-i $NicPub -f $FilterPub -a duration:$FilterTimePub -w $CptFilePub"
"-i $NicPri -f $FilterPri -a duration:$FilterTimePri -w $CptFilePri"
)
$CptCMDs | ForEach-Object -Parallel {
$TsharkBin = "C:\Program Files\Wireshark\tshark.exe"
& $TsharkBin $_
} -ThrottleLimit 2
}
I've tried to quoting the "qoutes" like that, but doesn't works:
$NicPub = "`"$NicPub`""
Seems that tshark reads the $CptCMDs as a single parameter the interface name! Seems skips its commands switch...
This is the output, if I ran the script interactively:
E:\Captures\2022-09-16-15
E:\Captures\2022-09-16-15\RmJobsLog.txt
SRV1
E:\Captures\2022-09-16-15\SRV1_PUB_2022-09-16-15.06.pcapng
E:\Captures\2022-09-16-15\SRV1_PRI_2022-09-16-15.06.pcapng
"\Device\NPF_{3578AB86-0318-4116-818C-87BC171F2B6F}"
"\Device\NPF_Loopback"
dst net 10.49.94.0/24
dst net 10.56.128.0/25
Capturing on ' \Device\NPF_{3578AB86-0318-4116-818C-87BC171F2B6F} -f dst net 10.49.94.0/24 -a duration:300 -w E:\Captures\2022-09-16-15\SRV1_PUB_2022-09-16-15.06.pcapng'
Capturing on ' \Device\NPF_{34234H86-5488-5546-212C-57867G57FR2Y} -f dst net 10.56.128.0/25 -a duration:300 -w E:\Captures\2022-09-16-15\SRV1_PRI_2022-09-16-15.06.pcapng'
tshark: The capture session could not be initiated on interface ' \Device\NPF_{3578AB86-0318-4116-818C-87BC171F2B6F} -f dst net 10.49.94.0/24) -a duration:300 -w E:\Captures\2022-09-16-15\SRV1_PUB_2022-09-16-15.06.pcapng' (Error opening adapter: The filename, directory name, or volume label syntax is incorrect. (123)).
Please check that you have the proper interface or pipe specified.
0 packets captured
tshark: The capture session could not be initiated on interface ' \Device\NPF_{34234H86-5488-5546-212C-57867G57FR2Y} -f dst net 10.56.128.0/25 -a duration:300 -w E:\Captures\2022-09-16-15\SRV1_PRI_2022-09-16-15.06.pcapng' (Error opening adapter: The filename, directory name, or volume label syntax is incorrect. (123)).
Please check that you have the proper interface or pipe specified.
0 packets capture
Can Anyone help me?
Somehow the arguments would have to be split into a list like:
$list1 = 1,2,3
$list2 = 4,5,6
$prog = 'echoargs'
$list1,$list2 | % { & $prog $_ }
Arg 0 is <1>
Arg 1 is <2>
Arg 2 is <3>
Arg 0 is <4>
Arg 1 is <5>
Arg 2 is <6>
Try it this way:
$list1 = '-i',$NicPub,'-f',$FilterPub,'-a',"duration:$FilterTimePub",'-w',$CptFilePub
$list2 = '-i',$NicPri,'-f',$FilterPri,'-a',"duration:$FilterTimePri",'-w',$CptFilePri
$CptCMDs = $list1,$list2
$CptCMDs | ForEach-Object -Parallel {
# ...

How to call a powershell script in vbscript?

I'm trying to call a powershell script in-between one of my project steps in Visual Build.
I've created a new script within visual build and having that call my powershell script.
I selected vbscript and this is the code within the script:
Dim paths, source1
paths = "C:\Dev\"
source1 = "\\10.156.3.14\win"
sCmd = "powershell.exe -noexit -ExecutionPolicy Unrestricted -file C:\Dev\downloadfiles.ps1 -target """ & paths & """ -source """ & source1 & """"
Set xShell = CreateObject("Wscript.Shell")
rReturn = xShell.Run(sCmd, 0, true)
The script timeouts my build.
The powershell script works fine when ran through the console.
Is there something I'm missing?
download.files.ps1 paramaters:
param (
[string[]]$target,
[string[]]$source
)
Additionally is there any way I could see the console output whilst it's running. Even with "-noexit" I'm seeing nothing.
Update --
The first part of the script runs and returns some of the relevant files.
Although the part that takes in the parameters are not functioning.
This seems to be the better alternative as the script is now taking in parameters :
Set objShell = CreateObject("Wscript.Shell")
objShell.run("powershell.exe -noexit -ExecutionPolicy Unrestricted -file .\downloadfiles.ps1 -target """ & paths & """ -source """ & source1 & """")
Follow up question. How would I go about passing in a string arrray through the vbscript call?
e.g
$target = #('c:\dev','d:\lib')
When using -File, I'm afraid all array elements in $target will be forwarded to the PowerShell script as a single string.
Try
VbScript
Option Explicit
'I hate writing """something""" or Chr(34) & "something" & Chr(34)
'all the time, so I use this little helper function
Private Function Quote(text)
Quote = Chr(34) & text & Chr(34)
End Function
Dim paths, source1, script, sCmd, objShell
'join the quoted path elements with a semi-colon
paths = Join(Array(Quote("C:\Dev"), Quote("D:\lib")), ";")
source1 = Quote("\\10.156.3.14\win")
script = Quote("D:\Test\downloadfiles.ps1")
sCmd = "powershell.exe -NoExit -NoLogo -ExecutionPolicy Unrestricted -File " & script & " -target " & paths & " -source " & source1
Set objShell = CreateObject("Wscript.Shell")
objShell.run(sCmd)
Test with PowerShell
downloadfiles.ps1
param (
[string[]]$target,
[string[]]$source
)
$target = $target | ForEach-Object { $_ -split ';' }
$source = $source | ForEach-Object { $_ -split ';' }
Write-Host "Elements in target: $($target.Count)"
Write-Host "Elements in source: $($source.Count)"
Write-Host
for ($i = 0; $i -lt $target.Count; $i++) {
'$target[{0}]: {1}' -f $i, $target[$i]
}
Write-Host
for ($i = 0; $i -lt $source.Count; $i++) {
'$source[{0}]: {1}' -f $i, $source[$i]
}
Output in PowerShell console:
Elements in target: 2
Elements in source: 1
$target[0]: C:\Dev
$target[1]: D:\lib
$source[0]: \\10.156.3.14\win

Powershell call -Command property with spaces

I have script D, C and B :
ScriptD.ps1 ← caller
ScriptC.ps1 ← script path without space
Script B.ps1 ← script path with space
Script B & ScriptC:
Param([int]$Major, [int]$Minor, [String[]]$Output = #())
Write-Host "`n_______________________________________________________________________________________`n"
Write-Host "Script C:`nMajor = $Major ($($Major.GetType()))`nMinor = $Minor ($($Minor.GetType()))`nOutput = $Output (Type: $($Output.GetType()), Length: $($Output.Length))" -ForegroundColor Green
foreach($string in $Output) {
Write-Host "`t- $string"
}
Then I call ScriptC.ps1, Script B.ps1 from ScriptD.ps1:
$cmd1 = "C:\ScriptTest\ScriptC.ps1 -Major 1 -Minor 2 -Output A,B"
powershell -Command $cmd1 #WORK
$cmd2 = "C:\ScriptTest\Script B.ps1 -Major 1 -Minor 2 -Output A,B"
powershell -Command $cmd2 #DON'T WORK
$cmd2 = "'C:\ScriptTest\Script B.ps1' -Major 1 -Minor 2 -Output A,B" #DON'T WORK
$cmd2 = '"C:\ScriptTest\Script B.ps1" -Major 1 -Minor 2 -Output A,B' #DON'T WORK
$cmd2 = $('"{0}"' -f ("C:\ScriptTest\Script B.ps1")) + " -Major 1 -Minor 2 -Output A,B" #DON'T WORK
If there are spaces in the script path or in a variable the call don't work. Adding single quotes will not solve that problem.
What's wrong?
How could I use the -Command parameter with spaces in path and passed variables?
Don't do what you're doing. There is zero reason to invoke PowerShell scripts from another PowerShell script the way you do.
Change
$cmd1 = "C:\ScriptTest\ScriptC.ps1 -Major 1 -Minor 2 -Output A,B"
powershell -Command $cmd1
$cmd2 = "C:\ScriptTest\Script B.ps1 -Major 1 -Minor 2 -Output A,B"
powershell -Command $cmd2
into
C:\ScriptTest\ScriptC.ps1 -Major 1 -Minor 2 -Output A,B
& "C:\ScriptTest\Script B.ps1" -Major 1 -Minor 2 -Output A,B
and everything will work.
Even if you needed to start the other scripts in a separate process you wouldn't use the approach you chose, but something like this:
$paramsc = '-File', 'C:\ScriptTest\ScriptC.ps1',
'-Major', 1, '-Minor', 2, '-Output', 'A,B'
Start-Process 'powershell.exe' -ArgumentList $paramsc
$paramsb = '-File', '"C:\ScriptTest\Script B.ps1"',
'-Major', 1, '-Minor', 2, '-Output', 'A,B'
Start-Process 'powershell.exe' -ArgumentList $paramsb
The ugly nested quotes in the second example are required because the script path contains a space and must thus be in double quotes for the creation of the external process. However, I doubt that you'll be able to pass output variables back to the caller across process boundaries.

How to write out or trace specific commands in a PowerShell script?

In a PowerShell script that I'm creating, I want to output specific commands with the parameter values being passed. The output could go to a log file and/or the console output. The following will output what I want to the console but I have to duplicate the line of script of interest and at some point a subtle mistake will be made where the commands don't match. I've tried Set-PSDebug and Trace-Command and neither give the result I seek. I've thought about putting the line of script into a string, writing it out, and then calling Invoke-Expression but I'll give up autocompletion/intellisense.
Example with duplicated line for writing and execution:
Write-Output "New-AzureRmResourceGroup -Name $rgFullName -Location $location -Tag $tags -Force"
New-AzureRmResourceGroup -Name $rgFullName -Location $location -Tag $tags -Force
Output result with expanded variables. $tags didn't expand to actual hashtable values:
New-AzureRmResourceGroup -Name StorageAccounts -Location West US -Tag System.Collections.Hashtable -Force
What other options or commandlets can I use to achieve the tracing without writing duplicated code and maybe even expanding the hashtable?
There is no built-in feature I'm aware of that echoes a version of a command being executed with variables and expressions used in arguments expanded.
Even if there were, it would only work faithfully in simple cases, because not all objects have literal representations.
However, with limitations, you can roll your own solution, based on &, the call operator, and parameter splatting via a hashtable of argument values defined up front:
# Sample argument values.
$rgFullName = 'full name'
$location = 'loc'
$tags = #{ one = 1; two = 2; three = 3 }
# Define the command to execute:
# * as a string variable that contains the command name / path
# * as a hashtable that defines the arguments to pass via
# splatting (see below.)
$command = 'New-AzureRmResourceGroup'
$commandArgs = [ordered] #{
Name = $rgFullName
Location = $location
Tag = $tags
Force = $True
}
# Echo the command to be executed.
$command, $commandArgs
# Execute the command, using & and splatting (note the '#' instead of '$')
& $command #commandArgs
The above echoes the following (excluding any output from the actual execution):
New-AzureRmResourceGroup
Name Value
---- -----
Name full name
Location loc
Tag {two, three, one}
Force True
As you can see:
PowerShell's default output formatting results in a multi-line representation of the hashtable used for splatting.
The $tags entry, a hashtable itself, is unfortunately only represented by its keys - the values are missing.
However, you can customize the output programmatically to create a single-line representation that approximates the command with expanded arguments, including showing hashtables with their values, using helper function convertTo-PseudoCommandLine:
# Helper function that converts a command name and its arguments specified
# via a hashtable or array into a pseudo-command line string that
# *approximates* the command using literal values.
# Main use is for logging, to reflect commands with their expanded arguments.
function convertTo-PseudoCommandLine ($commandName, $commandArgs) {
# Helper script block that transforms a single parameter-name/value pair
# into part of a command line.
$sbToCmdLineArg = { param($paramName, $arg)
$argTransformed = ''; $sep = ' '
if ($arg -is [Collections.IDictionary]) { # hashtable
$argTransformed = '#{{{0}}}' -f ($(foreach ($key in $arg.Keys) { '{0}={1}' -f (& $sbToCmdLineArg '' $key), (& $sbToCmdLineArg '' $arg[$key]) }) -join ';')
} elseif ($arg -is [Collections.ICollection]) { # array / collection
$argTransformed = $(foreach ($el in $arg) { & $sbToCmdLineArg $el }) -join ','
}
elseif ($arg -is [bool]) { # assume it is a switch
$argTransformed = ('$False', '$True')[$arg]
$sep = ':' # passing an argument to a switch requires -switch:<val> format
} elseif ($arg -match '^[$#(]|\s|"') {
$argTransformed = "'{0}'" -f ($arg -replace "'", "''") # single-quote and escape embedded single quotes
} else {
$argTransformed = "$arg" # stringify as is - no quoting needed
}
if ($paramName) { # a parameter-argument pair
'-{0}{1}{2}' -f $paramName, $sep, $argTransformed
} else { # the command name or a hashtable key or value
$argTransformed
}
}
# Synthesize and output the pseudo-command line.
$cmdLine = (& $sbToCmdLineArg '' $commandName)
if ($commandArgs -is [Collections.IDictionary]) { # hashtable
$cmdLine += ' ' +
$(foreach ($param in $commandArgs.Keys) { & $sbToCmdLineArg $param $commandArgs[$param] }) -join ' '
} elseif ($commandArgs) { # array / other collection
$cmdLine += ' ' +
$(foreach ($arg in $commandArgs) { & $sbToCmdLineArg '' $arg }) -join ' '
}
# Output the command line.
# If the comamnd name ended up quoted, we must prepend '& '
if ($cmdLine[0] -eq "'") {
"& $cmdLine"
} else {
$cmdLine
}
}
With convertTo-PseudoCommandLine defined (before or above the code below), you can then use:
# Sample argument values.
$rgFullName = 'full name'
$location = 'loc'
$tags = #{ one = 1; two = 2; three = 3 }
# Define the command to execute:
# * as a string variable that contains the command name / path
# * as a hashtable that defines the arguments to pass via
# splatting (see below.)
$command = 'New-AzureRmResourceGroup'
$commandArgs = [ordered] #{
Name = $rgFullName
Location = $location
Tag = $tags
Force = $True
}
# Echo the command to be executed as a pseud-command line
# created by the helper function.
convertTo-PseudoCommandLine $command $commandArgs
# Execute the command, using & and splatting (note the '#' instead of '$')
& $command #commandArgs
This yields (excluding any output from the actual execution):
New-AzureRmResourceGroup -Name 'full name' -Location loc -Tag #{two=2;three=3;one=1} -Force:$True

Pass parameter to powershell encoded command

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
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.
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!