可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a variable $Tasks in a PowerShell script that contains an array of strings, and I need to pass the variable along to other PowerShell scripts and do stuff with it, like loop thru the array and do things with each item (string). However, at some point along the way my variable gets converted from an array to a string (usually when it hits script2.ps1), and I'm not able to loop thru it. What do I need to do to keep the variable as an array throughout the entire process?
Here is the workflow of the variable:
Script1.ps1:
$Tasks = @( "Task1 - Name1", "Task2 - Name2", "Task3 - Name3" ) powershell "& {. $pwd\Script2.ps1 -BuildNum $BuildNum; Run-Validation -Tasks $Tasks}"
Script2.ps1:
param( $Tasks=$() ) Function Run-Validation { param($Tasks) If ($Tasks) { Test-Tasks $Tasks } }
Script3.ps1:
Function Test-Tasks ($Tasks) { ForEach ($Task in $Tasks) { do_stuff } }
回答1:
The reason this is happening is that you're expanding an array $Tasks
inside a double quoted string. Before your command line is passed to PowerShell.exe, it is expanded to:
Arg 0 is <& {. C:\Script2.ps1 -BuildNum ; Run-Validation -Tasks Task1 - Name1 Task2 - Name2 Task3 - Name3}>
So the Run-Validaiton -Tasks parameter on sees "Task1". If you were to look at $args inside of the Run-Validation function you would see the rest of the arguments.
BTW why invoke another Powershell.exe session? Why not just invoke likes so:
. $PSScriptRoot\Script2.ps1 -BuildNum $BuildNum Run-Validation -Tasks $Tasks
Note that the above only works if you eliminate the script level $Tasks parameter in Script2.ps1. If not, when you dot source Script2.ps1 to gain access to the Run-Validation function, the $Tasks in Script2.ps1 effectively overwrites the value set in Script1.ps1.
If you really want to invoke this in a separate PowerShell session you can do this:
$OFS="','" powershell "& {. $pwd\Script2.ps1 -BuildNum $BuildNum; Run-Validation -Tasks '$Tasks'}"
回答2:
I find it helpful to structure my PowerShell scripts as functions. Instead of passing the $Tasks all the way through multiple scripts, I recommend pulling in the $Tasks when you are ready to use them.
This would be the equivalent of your Script1.ps1
taskList.ps1
Function Get-Tasks() { $Tasks = @( "Task1 - Name1", "Task2 - Name2", "Task3 - Name3" ) return $Tasks }
This would be the equivalent of your Script2.ps1 and Script3.ps1 combined
#dot source the scripts we will need .$PSScriptRoot\taskList.ps1 #Get the list of tasks $taskList = Get-Tasks if ($taskList -ne $null) { foreach ($task in $taskList) { #Do Stuff Here "Processing task: " + $task } }
Note: $PSScriptRoot will load from the current working directory. If this file is located elsewhere, use the full path
However, if you would still like to keep your current structure, you can simply update Script.1 to the following
#dot source the scripts we will need .$PSScriptRoot\Script3.ps1 $Tasks = @( "Task1 - Name1", "Task2 - Name2", "Task3 - Name3" ) Run-Validation -Tasks $Tasks
回答3:
I am using inside script such definition of paramaters:
[cmdletbinding()] Param( [Parameter(Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName)] [ValidateNotNullorEmpty()] [Alias("cn","name")] [String[]]$var )
In this example you can define: [String]$var
as a single string variable, or [String[]]$var
as a array of string variables.