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

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

Что касается того, где, или я, что в W98 реальный вопрос был «когда» (я не видел, чтобы сообщение подчеркивало это). Небольшая программа шаблонов (для входа MIDI SysEx, используя различные пространства malloc'd) освободила бы память в бит WM_DESTROY от WndProc, но когда я пересадил это в большую программу, он разбился при выходе. Я предположил, что это означает, что я пытался освободить то, что ОС уже освободило во время большей очистки. Если я сделал это в WM_CLOSE, а затем вызвал DestroyWindow (), все это работало нормально, мгновенный чистый выход.

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

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

376
задан George Stocker 26 June 2014 в 16:33
поделиться

15 ответов

Параметры в вызовах функций в 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
507
ответ дан Dave F 26 June 2014 в 16:33
поделиться

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

syntax pitfalls of a function call

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

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

239
ответ дан Michael Sorens 26 June 2014 в 16:33
поделиться

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

test "ABC" "DEF"

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

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

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

41
ответ дан wjandrea 26 June 2014 в 16:33
поделиться
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test "ABC" "DEF"
13
ответ дан Rob W 26 June 2014 в 16:33
поделиться

Если вы разработчик на 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
10
ответ дан Cœur 26 June 2014 в 16:33
поделиться
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC") ("DEF")
2
ответ дан kleopatra 26 June 2014 в 16:33
поделиться

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

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}
0
ответ дан Kaushal Khamar 26 June 2014 в 16:33
поделиться
Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

Это правильная декларация параметров https://technet.microsoft.com/en-us/library/dd347600.aspx

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

1
ответ дан Serhii Kimlyk 26 June 2014 в 16:33
поделиться

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

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.

5
ответ дан Cœur 26 June 2014 в 16:33
поделиться

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

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

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

3
ответ дан Community 26 June 2014 в 16:33
поделиться

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

Код :

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
}
6
ответ дан Draino 26 June 2014 в 16:33
поделиться

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

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


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

2
ответ дан Martin Brandl 26 June 2014 в 16:33
поделиться

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

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

[110]

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

[111]

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

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

[112]

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

[113]

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

[114]

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

[115]

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

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

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

[116]

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

-PathType 'Leaf' })] [ValidateScript({ (Get-Item

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

[110]

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

[111]

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

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

[112]

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

[113]

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

[114]

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

[115]

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

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

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

[116]

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

| select -Expand Extension) -eq ".csv" })] [string] $Path ) }

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

38
ответ дан wonea 26 June 2014 в 16:33
поделиться

Я заявляю следующее:

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

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

Код:

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

Тест «ABC» «DEF»

Вывод:

Значение $ var1: значение ABC $ var2: DEF

1
ответ дан Sébastien 26 June 2014 в 16:33
поделиться

Я не вижу здесь упомянутого, но разделение ваших аргументов является полезной альтернативой и становится особенно полезным, если вы строите аргументы для команды динамически (в отличие от использования Invoke-Expression ). Вы можете использовать массивы для позиционных аргументов и хеш-таблицы для именованных аргументов. Вот несколько примеров:

Splat с массивами (позиционные аргументы)

Тест-соединение с позиционными аргументами

Test-Connection www.google.com localhost

с разбрызгиванием массива

$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentArray

Обратите внимание, что при сплаттинге мы ссылаемся на сплаттинговую переменную как @ вместо $. То же самое и при использовании Hashtable для сплата.

Splat с хэш-таблицей (именованные аргументы)

Тест-соединение с именованными аргументами

Test-Connection -ComputerName www.google.com -Source localhost

с хэш-таблицей Splatting

$argumentHash = @{
  ComputerName = 'www.google.com'
  Source = 'localhost'
}
Test-Connection @argumentHash

Splat Позиционные и именованные Аргументы одновременно

Тест-соединение с позиционными и именованными аргументами

Test-Connection www.google.com localhost -Count 1

Splatting Array и Hashtables вместе

$argumentHash = @{
  Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentHash @argumentArray
0
ответ дан Bender the Greatest 26 June 2014 в 16:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: