Как передать несколько параметров в функцию в PowerShell?



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



быстрый тестовый скрипт:



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 на нескольких машинах, так что, очевидно, я делаю что-то неправильно. Может ли кто-нибудь указать что именно?

758   14  

14 ответов:

параметры в вызовы функций в 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

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

syntax pitfalls of a function call

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

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

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

   test "ABC" "DEF"

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

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

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

некоторые хорошие ответы здесь, но я хотел бы указать на пару других вещей. Параметры функции-это фактически место, где светит 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 принимает регулярное выражение, которое гарантирует, что предоставленный параметр соответствует тому, что вы ожидаете. Если это не так, интуитивное исключение бросается, говоря вам точно, что не так. Так что в этом примере "что-то" будет работать нормально, но "лето" не прошел бы проверку.

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 существует, но и в том, что это файл (в отличие от каталога) и имеет a .расширение csv. ($_ относится к параметру, когда внутри вашего скриптового блока.) Вы также можете передать в гораздо больших, многострочных блоков скриптов, если этот уровень требуется, или использовать несколько scriptblocks, как я сделал здесь. Это очень полезно, и делает для хороших чистых функций и интуитивные исключения.

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

Test "ABC" "DEF"

Если вы разработчик 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

если вы попробуете:

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.

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

код:

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
}

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

кроме того, вот пример thread на этом сайте:

проверить.

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

Test("ABC") ("DEF")

I заявляет следующее ранее:

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

проблема не в этом.
На самом деле,$arg может быть что-нибудь еще. Проблема заключалась в использовании запятой и парантезов.
Я запускаю следующий код, который работал и вывод следующий:

код:

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

тест " ABC "" DEF"

выход:

$ var1 значение: ABC $переменная2 значение: деф

Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

это правильное объявление params https://technet.microsoft.com/en-us/library/dd347600.aspx

и это действительно работает

поскольку это часто просматриваемый вопрос, я хочу упомянуть, что функция 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#.


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

вы можете передать параметры на функции такой же.

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}

Comments

    Ничего не найдено.