У меня есть переменная $ Tasks в сценарии PowerShell, который содержит массив строк, и мне нужно передать эту переменную другим сценариям PowerShell и что-то с ней делать, например, перебирать массив и делать что-то с каждым элементом (строка ).

Однако в какой-то момент моя переменная преобразуется из массива в строку (обычно, когда она попадает в script2.ps1), и я не могу ее просмотреть. Что мне нужно сделать, чтобы переменная оставалась массивом на протяжении всего процесса?

Вот рабочий процесс переменной:

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
Keith 10 Май 2014 в 02:30

3 ответа

Лучший ответ

Причина этого в том, что вы расширяете массив $Tasks внутри строки, заключенной в двойные кавычки. Прежде чем ваша командная строка будет передана в PowerShell.exe, она расширяется до:

Arg 0 is <& {. C:\Script2.ps1 -BuildNum ; Run-Validation -Tasks Task1 - Name1 Task2 - Name2 Task3 - Name3}>

Таким образом, параметр Run-Validation -Tasks видит только "Task1". Если вы посмотрите на $ args внутри функции Run-Validation, вы увидите остальные аргументы.

Кстати, зачем вызывать другой сеанс Powershell.exe? Почему бы просто не вызвать так:

. $PSScriptRoot\Script2.ps1 -BuildNum $BuildNum
Run-Validation -Tasks $Tasks

Обратите внимание, что приведенное выше работает только , если исключить параметр $ Tasks уровня сценария в Script2.ps1. В противном случае, когда вы ставите точку в источнике Script2.ps1, чтобы получить доступ к функции Run-Validation, $ Tasks в Script2.ps1 эффективно перезаписывает значение, установленное в Script1.ps1.

Если вы действительно хотите вызвать это в отдельном сеансе PowerShell, вы можете сделать это:

$OFS="','"
powershell "& {. $pwd\Script2.ps1 -BuildNum $BuildNum; Run-Validation -Tasks '$Tasks'}"
2
Keith Hill 17 Фев 2019 в 19:02

Я считаю полезным структурировать сценарии PowerShell как функции. Вместо того, чтобы полностью передавать $ Tasks через несколько сценариев, я рекомендую загрузить $ Tasks, когда вы будете готовы их использовать.

Это будет эквивалент вашего Script1.ps1 .

taskList.ps1

Function Get-Tasks()
{
    $Tasks = @(
        "Task1 - Name1",
        "Task2 - Name2",
        "Task3 - Name3"
    )
    return $Tasks
}

Это будет эквивалент ваших комбинаций Script2.ps1 и Script3.ps1 :

# 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
    }
}

Примечание. $ PSScriptRoot загрузится из текущего рабочего каталога. Если этот файл находится в другом месте, используйте полный путь.

Однако, если вы все же хотите сохранить текущую структуру, вы можете просто обновить Script.1 до следующего

# Dot source the scripts we will need
.$PSScriptRoot\Script3.ps1

$Tasks = @(
    "Task1 - Name1",
    "Task2 - Name2",
    "Task3 - Name3"
)

Run-Validation -Tasks $Tasks
0
Peter Mortensen 16 Фев 2019 в 17:26

Я использую такое определение параметров внутри скрипта:

[cmdletbinding()]
Param(
    [Parameter(Position=0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [ValidateNotNullorEmpty()]
    [Alias("cn", "name")]
    [String[]]$var
)

В этом примере вы можете определить: [String]$var как одну строковую переменную или [String[]]$var как массив строковых переменных.

0
Peter Mortensen 16 Фев 2019 в 17:27