Как расширить массив PowerShell при передаче его функции - PullRequest
7 голосов
/ 16 января 2009

У меня есть две функции PowerShell, первая из которых вызывает вторую. Оба они принимают N аргументов, и один из них определяется просто для добавления флага и вызова другого. Вот примеры определений:

function inner
{
  foreach( $arg in $args )
    {
      # do some stuff
    }
}

function outer
{
  inner --flag $args
}

Использование будет выглядеть примерно так:

inner foo bar baz

или это

outer wibble wobble wubble

Цель состоит в том, чтобы последний пример был эквивалентен

inner --flag wibble wobble wubble

Проблема: Как определено здесь, последний фактически приводит к передаче inner двух аргументов: первый - «--flag», а второй - массив, содержащий «wibble», «колебание» и «колебание». Я хочу, чтобы inner получил четыре аргумента: флаг и три исходных аргумента.

Поэтому меня интересует, как убедить powershell расширить массив $ args перед передачей его в inner, передавая его как N элементов, а не как один массив. Я полагаю, что вы можете сделать это в Ruby с помощью оператора splatting (символ *), и я почти уверен, что PowerShell может это сделать, но я не помню, как.

Ответы [ 4 ]

11 голосов
/ 24 января 2009

Нет хорошего решения этой проблемы в PowerSHell V1. В V2 мы добавили сплаттинг (хотя по разным причинам мы используем @ вместо * для этой цели). Вот как это выглядит:

PS (STA-ISS) (2)> функция foo ($ x, $ y, $ z) {"x: $ x y: $ y z: $ z"}

PS (STA-ISS) (3)> $ a = 1,2,3

PS (STA-ISS) (4)> foo $ a # передается как один аргумент

x: 1 2 3 года: z:

PS (STA-ISS) (5)> foo @a # splatted

x: 1 y: 2 z: 3

0 голосов
/ 01 июня 2018

Если вы хотите быстрое готовое решение, вы можете скопировать вставить мой:

<#
    .SYNOPSIS
    Asks a question and waits for user's answer

    .EXAMPLE
    Usage with shortcuts and without ReturnValue
    Invoke-Question -Question "What would you like" -Answers "&Eggs", "&Toasts", "&Steak"

    Shows the quesiton and waits for input. Let's assume user input is 'S', the return value would be 2 (index of "&Steak")

    .EXAMPLE
    Usage without shortcuts and with ReturnValue
    Invoke-Question -Question "What would you like" -Answers "Eggs", "Toasts", "Steak" -ReturnValue

    Shows the quesiton and waits for input. The answers are prefixed with numbers 1, 2 and 3 as shortcuts.
    Let's assume user input is 2, the return value would be "Toasts" (prefixed numbers are "index + 1")

    .EXAMPLE
    Usage from pipeline with default value
    @("Eggs", "Toasts", "Steak") | Invoke-Question -Question "What would you like" -ReturnValue -Default 2

    Shows the quesiton and waits for input. The answers are taken from pipeline and prefixed with numbers 1, 2 and 3 as shortcuts.
    Steak is marked as default. If user simply continues without a choice, Steak is chosen for her.
    However, let's assume user input is 1, the return value would be "Eggs" (prefixed numbers are "index + 1")
#>
function Invoke-Question {
    [CmdletBinding()]
    param(
        # Main question text
        [Parameter(Mandatory = $true)]
        [string] $Question,

        # Question description, e.g. explanation or more information
        [Parameter(Mandatory = $false)]
        [string] $Description = "",

        # Default answer as index in the array, no answer is selected by default (value -1)
        [Parameter(Mandatory = $false)]
        [int] $Default = -1,

        # Set of answers, if the label is given with & sign, the prefixed letter is used as shortcut, e.g. "&Yes" -> Y,
        # otherwise the answer is prefixed with "index + 1" number as a shortcut
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string[]] $Answers,

        # If set, returns a value of selected answer, otherwise returns its index in the Answer array
        [switch] $ReturnValue
    )

    begin {
        # init choices
        $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
        $answerNumber = 1
        $rememberAnswers = @()
    }

    process {
        #init answers
        foreach ($answer in $answers) {
            $rememberAnswers += $answer
            if ($answer -notmatch "&") {
                # add number if shortcut not specified
                $answer = "&$answerNumber $answer"
            }

            $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList $answer))
            $answerNumber++
        }
    }

    end {
        # ask question and return either value or index
        $index = $Host.UI.PromptForChoice($Question, $Description, $choices, $Default)
        if ($ReturnValue) {
            $rememberAnswers[$index]
        } else {
            $index
        }
    }
}
0 голосов
/ 16 января 2009

Опираясь на идею @ EBGreen и связанный с этим вопрос, который я заметил на боковой панели, возможное решение заключается в следующем:

function outer
{
    invoke-expression "inner --flag $($args -join ' ')"
}

Примечание. В этом примере используется новый оператор -join CTP-сервера Powershell 2.0.

Тем не менее, я все же хотел бы найти лучший метод, так как это похоже на взлом и ужасно в плане безопасности.

0 голосов
/ 16 января 2009

Ну, может быть, есть лучший способ, но посмотрите, работает ли он:

inner --flag [string]::Join(" ", $args)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...