Как обрабатывать аргументы командной строки в PowerShell

494

Каков «лучший» способ обработки аргументов командной строки?

Кажется, что есть несколько ответов о том, что такое «лучший» путь, и в результате я застрял на том, как справиться с чем-то простым:

script.ps1 /n name /d domain

А ТАКЖЕ

script.ps1 /d domain /n name.

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

Очевидно, что то, что у меня уже есть, не очень красиво и, конечно, не самое «лучшее», но оно работает… и это ужасно.

for ( $i = 0; $i -lt $args.count; $i++ ) {
    if ($args[ $i ] -eq "/n"){ $strName=$args[ $i+1 ]}
    if ($args[ $i ] -eq "-n"){ $strName=$args[ $i+1 ]}
    if ($args[ $i ] -eq "/d"){ $strDomain=$args[ $i+1 ]}
    if ($args[ $i ] -eq "-d"){ $strDomain=$args[ $i+1 ]}
}
Write-Host $strName
Write-Host $strDomain
Аарон Вюртманн
источник

Ответы:

917

Вы заново изобретаете колесо. Обычные сценарии PowerShell имеют параметры, начинающиеся с -:script.ps1 -server http://devserver

Затем вы обрабатываете их в paramразделе в начале файла.

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

 param (
    [string]$server = "http://defaultserver",
    [Parameter(Mandatory=$true)][string]$username,
    [string]$password = $( Read-Host "Input password, please" )
 )

Внутри скрипта вы можете просто

write-output $server

поскольку все параметры становятся переменными, доступными в области действия скрипта.

В этом примере, $serverполучает значение по умолчанию, если сценарий вызывается без него, сценарий останавливается, если вы пропустите -usernameпараметр, и запрашивает ввод с терминала, если -passwordон пропущен.

Обновление: Вы также можете передать «флаг» (логический параметр true / false) сценарию PowerShell. Например, ваш скрипт может принять «силу», когда скрипт выполняется в более осторожном режиме, когда сила не используется.

Ключевым словом для этого является [switch]тип параметра:

 param (
    [string]$server = "http://defaultserver",
    [string]$password = $( Read-Host "Input password, please" ),
    [switch]$force = $false
 )

Внутри скрипта вы будете работать с ним так:

if ($force) {
  //deletes a file or does something "bad"
}

Теперь при вызове скрипта вы должны установить параметр switch / flag следующим образом:

.\yourscript.ps1 -server "http://otherserver" -force

Если вы явно хотите заявить, что флаг не установлен, для этого существует специальный синтаксис

.\yourscript.ps1 -server "http://otherserver" -force:$false

Ссылки на соответствующую документацию Microsoft (для PowerShell 5.0; версии 3.0 и 4.0 также доступны по ссылкам):

naivists
источник
58
Действительно, одним из больших преимуществ PowerShell является то, что он обеспечивает стандартную инфраструктуру анализа параметров, которая проста в использовании.
Кит Хилл
14
@naivists из PowerShell 2.0 вместо [string]$username = $(throw "-username is required.")есть синтаксис обязательных параметров: [Parameter(Mandatory=$true)][string]$username. Вот более подробную информацию о разнице между этими методами: blogs.technet.com/b/heyscriptingguy/archive/2011/05/22/...
v.karbovnichy
7
Будьте осторожны с ошибкой, когда аргумент не указан; powershell просто получит любой дополнительный текст из командной строки:. \ yourscript.ps1 -server " serv " -password "mypass" typo Это магическим образом назначит 'typo' для $ username.
Sheamus
4
Использование блока параметров может иметь и другие непредвиденные последствия: stackoverflow.com/questions/40940819/…
Logan
1
@ Sheamus: это не ошибка! Powershell обработает и назначит аргументы в указанном порядке, если только они не будут переопределены с использованием правильного имени параметра, например, если в вашем списке блоков параметров: $ user $ pass $ server и вы выполните yourscript.ps1 abc, a будет установите в $ user, b в $ pass и c в $ server, ЕСЛИ вы их специально не назначите! Итак, если вы скажете: yourscript.ps1 -pass abc, $ pass будет установлен в a, а оставшиеся (безымянные) параметры будут использованы для заполнения пропущенных, в порядке, указанном в блоке параметров, поэтому $ user = b, $ server = c.
Фернандо Мадруга