Как передать несколько параметров в функцию в PowerShell? - PullRequest
375 голосов
/ 14 февраля 2011

Если у меня есть функция, которая принимает более одного строкового параметра, первый параметр, кажется, получает все назначенные ему данные, а остальные параметры передаются как пустые.

Скрипт быстрого теста:

Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC", "DEF")

Сгенерированный вывод:

$arg1 value: ABC DEF
$arg2 value: 

Правильный вывод должен быть:

$arg1 value: ABC
$arg2 value: DEF

Это похоже на согласование между v1 и v2 на нескольких машинах, поэтомуочевидно, я делаю что-то не так.Кто-нибудь может указать, что именно?

Ответы [ 15 ]

504 голосов
/ 14 февраля 2011

Параметры в вызовах функций в PowerShell (все версии) разделяются пробелом, а не через запятую . Кроме того, круглые скобки совершенно не нужны и вызовут ошибку разбора в PowerShell 2.0 (или более поздней версии), если активен Set-StrictMode. Аргументы в скобках используются только в методах .NET.

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}

ps> foo 1 2 3
a: 1; b: 2; c: 3
238 голосов
/ 08 апреля 2013

Правильный ответ уже был предоставлен, но эта проблема кажется достаточно распространенной, чтобы дать некоторые дополнительные сведения для тех, кто хочет понять тонкости. Я бы добавил это просто как комментарий, но я хотел бы включить иллюстрацию - я сорвал это с моей быстрой справочной таблицы по функциям PowerShell. Предполагается, что подпись функции f f($a, $b, $c):

syntax pitfalls of a function call

Таким образом, можно вызывать функцию с разделенными пробелами позиционными параметрами или независимыми от порядка именованными параметрами. Другие подводные камни показывают, что вам необходимо знать запятые, скобки, и пробел.

Подробнее читайте в моей статье Вниз по кроличьей норе: исследование конвейеров, функций и параметров PowerShell , только что опубликованной на Simple-Talk.com Статья содержит ссылку на краткий справочник / настенную диаграмму.

41 голосов
/ 14 февраля 2011

Вы вызываете функции PowerShell без скобок и без использования запятой в качестве разделителя. Попробуйте использовать:

test "ABC" "DEF"

В PowerShell запятая (,) является оператором массива, например

$a = "one", "two", "three"

Устанавливает $a в массив с тремя значениями.

37 голосов
/ 24 июня 2017

Несколько хороших ответов здесь, но я хотел бы отметить пару других вещей. Параметры функций - это место, где светит PowerShell. Например, вы можете иметь именованные или позиционные параметры в расширенных функциях, например:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [int] $Id
    )
}

Тогда вы можете либо вызвать его, указав имя параметра, либо просто использовать позиционные параметры, поскольку вы их явно определили. Так что любой из них будет работать:

Get-Something -Id 34 -Name "Blah" 
Get-Something "Blah" 34

Первый пример работает, хотя имя предоставляется вторым, потому что мы явно использовали имя параметра. Второй пример работает на основе позиции, поэтому имя должно быть первым. Когда это возможно, я всегда стараюсь определить позиции, чтобы были доступны оба варианта.

PowerShell также имеет возможность определять наборы параметров. Это использует это вместо перегрузки метода, и снова довольно полезно:

function Get-Something
{
    [CmdletBinding(DefaultParameterSetName='Name')]
    Param
    (
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
         [int] $Id
    )
}

Теперь функция будет либо принимать имя, либо идентификатор, но не оба. Вы можете использовать их по месту или по имени. Так как они другого типа, PowerShell поймет это. Так что все это будет работать

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23

Вы также можете назначить дополнительные параметры различным наборам параметров. (Это был довольно простой пример, очевидно). Внутри функции вы можете определить, какой набор параметров использовался с помощью свойства $ PsCmdlet.ParameterSetName. Например:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Doing something with name here"
}

Затем, в примечании к теме, в PowerShell также есть проверка параметров. Это одна из моих любимых функций PowerShell, и она делает код внутри ваших функций очень чистым. Есть множество проверок, которые вы можете использовать. Пара примеров:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidatePattern('^Some.*')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [ValidateRange(10,100)]
         [int] $Id
    )
}

В первом примере ValidatePattern принимает регулярное выражение, которое гарантирует, что предоставленный параметр соответствует ожидаемому. Если это не так, выдается интуитивно понятное исключение, которое говорит вам, что именно не так. Таким образом, в этом примере «Something» будет работать нормально, но «Summer» не пройдет проверку.

ValidateRange гарантирует, что значение параметра находится в диапазоне, который вы ожидаете для целого числа. Таким образом, 10 или 99 сработают, но 101 сгенерирует исключение.

Еще одним полезным является ValidateSet, который позволяет вам явно определять массив допустимых значений. Если будет введено что-то еще, будет сгенерировано исключение. Есть и другие, но, вероятно, наиболее полезным является ValidateScript. Это берет блок скрипта, который должен иметь значение $ true, поэтому пределом является небо. Например:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
         [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
         [string] $Path
    )
}

В этом примере мы уверены, что не только $ Path существует, но и что это файл (в отличие от каталога) и имеет расширение .csv. ($ _ относится к параметру, находящемуся внутри вашего скриптового блока.) Вы также можете передать гораздо большие многострочные скриптовые блоки, если требуется этот уровень, или использовать несколько скриптовых блоков, как я сделал здесь. Это чрезвычайно полезно, и делает для хороших чистых функций и интуитивных исключений.

13 голосов
/ 04 ноября 2011
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test "ABC" "DEF"
10 голосов
/ 27 августа 2015

Если вы разработчик на C # / Java / C ++ / Ruby / Python / Pick-A-Language-From-This-Century и хотите вызывать свою функцию с запятыми, потому что это то, что вы всегда делали, тогдавам нужно что-то вроде этого:

$myModule = new-module -ascustomobject { 
    function test($arg1, $arg2) { 
        echo "arg1 = $arg1, and arg2 = $arg2"
    }
}

Теперь позвоните:

$myModule.test("ABC", "DEF")

и вы увидите

arg1 = ABC, and arg2 = DEF
6 голосов
/ 27 января 2017

Если вы не знаете (или не заботитесь), сколько аргументов вы передадите в функцию, вы также можете использовать очень простой подход, например:

Код :

function FunctionName()
{
    Write-Host $args
}

Это распечатало бы все аргументы.Например:

FunctionName a b c 1 2 3

Вывод

a b c 1 2 3

Я считаю это особенно полезным при создании функций, использующих внешние команды, которые могут иметь много разных (и необязательных) параметров, но полагается на указанную команду для обеспечения обратной связи по поводу синтаксических ошибок и т. д.

Вот еще один пример из реальной жизни (создание функции для команды tracert, которую я ненавижу запоминать усеченное имя);

Код :

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
5 голосов
/ 10 декабря 2012

Если вы попытаетесь:

PS > Test("ABC", "GHI") ("DEF")

, вы получите:

$arg1 value: ABC GHI
$arg2 value: DEF

, и вы увидите, что скобка разделяет параметры

Если вы попытаетесь:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"

вы получите:

$arg1 value: ABC
$arg2 value: DEF

Теперь вы можете найти некоторую непосредственную полезность скобок - пробел не станет разделителем для следующего параметра - вместо этого у вас есть функция eval.

3 голосов
/ 16 февраля 2011

Я не знаю, что вы делаете с функцией, но посмотрите на использование ключевого слова 'param'.Он немного более мощный для передачи параметров в функцию и делает его более удобным для пользователя.Ниже приведена ссылка на слишком сложную статью Microsoft об этом.Это не так сложно, как статья озвучивает. Использование параметра

Кроме того, вот пример из темы на этом сайте:

Проверьте это.

2 голосов
/ 21 апреля 2017

Поскольку это часто просматриваемый вопрос, я хочу упомянуть, что функция PowerShell должна использовать утвержденные глаголы ( Глагол-существительное в качестве имени функции).Также вы можете указать, например, является ли параметр обязательным и положение параметра:

function Test-Script
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$arg1,

        [Parameter(Mandatory=$true, Position=1)]
        [string]$arg2
    )

    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Для передачи параметра в функцию, которую выВы можете использовать положение :

Test-Script "Hello" "World"

Или вы укажите параметр имя :

Test-Script -arg1 "Hello" -arg2 "World"

Вы не используйте скобки , как вы делаете, когда вызываете функцию в C #.


Я бы рекомендовал всегда передавать имена параметров при использовании болееодин параметр, так как он более читаемый .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...