Требование параметров в PowerShell при наличии другого параметра. Powershell параметры


Windows PowerShell: Определение параметров | Microsoft Docs

  • 08/19/2016
  • Время чтения: 4 мин

В этой статье

В Windows PowerShell есть простые и сложные способы определения параметров, и у каждого вида свои преимущества.

Дон Джонс

Часто создаваемый вами сценарий или функция принимает какие-то входные данные. Это может быть имя компьютера, путь к файлу и т. п. Можно заставить Windows PowerShell ожидать эти параметры, принимать их из командной строки и размещать их значения в переменных в сценарии или функции. Это делает ввод данных простым и эффективным.

Нужно просто знать, как декларировать свои параметры. Простейший способ выполнения этой задачи — указание блока param:

Param( [string]$computerName, [string]$filePath )

Необязательно разбивать его на отдельные строки, как сделал это я, — вполне легитимно размещать все в одну строку. Но я предпочитаю разбивать на отдельные строки — так проще читать. Если такой блок присутствует в сценарии или функции, Windows PowerShell считывает его и даже разделяет знаками табуляции при вызове сценария или функции. Я аккуратно указал имена параметров: –computerName и –filePath. Они похожи на те, что используются в командлетах Windows PowerShell для подобной информации. Таким образом, мои параметры совместимы с тем, что уже используется в оболочке.

Если я размещу этот код в сценарии по имени Get-Something.ps1, использовать параметры нужно будет примерно так:

./Get-Something –computerName SERVER1 –filePath C:\Whatever

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

./Get-Something –comp SERVER1 –file C:\Whatever

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

./Get-Something SERVER1 C:\Whatever

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

./Get-Something –filePath C:\Whatever –computerName SERVER1

Windows PowerShell также предоставляет более сложный способ декларирования параметров. Этот более полный синтаксис позволяет задавать параметры как обязательные, указывать позицию (если этого не сделать, задать параметр можно будет только по его имени) и делать многое другое.  Также такой расширенный синтаксис разрешен как в сценариях, так и в функциях:

[CmdletBinding()] Param( [Parameter(Mandatory=$True,Position=1)] [string]$computerName, [Parameter(Mandatory=$True)] [string]$filePath )

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

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

У использования директивы [CmdletBinding()] есть ряд других преимуществ. Для начала, она гарантирует, что у моего сценария или функции будут все стандартные параметры, в том числе –Verbose и –Debug. Теперь я могу использовать в своем сценарии или функции Write-Verbose и Write-Debug, а результат работы этих командлетов будет автоматически устранен.

Выполните сценарий или функцию с параметром –Verbose или –Debug, и будет магическим образом автоматически активизирован Write-Verbose или Write-Debug (соответственно). Это отличный способ предоставления пошаговой информации о ходе процесса (Write-Verbose) или отладке сценариев (Write-Debug).

В настоящем виде они принимают только одно значение. Если объявить их как [string[]], они смогут принимать целые коллекции значений. Перечислять значения можно в цикле Foreach, работая в каждый момент времени только с одним значением.

Еще один классный тип параметров — [switch]:

Param([switch]$DoSomething)

Теперь я могу выполнять свой сценарий или функцию без параметра –DoSomething, а внутри кода переменной $DoSomething будет присваиваться значение $False. Если я выполню сценарий с параметром –DoSomething, переменной $DoSomething присвоится значение $True. Нет нужды передавать значение параметра. Windows PowerShell присваивает ему значение $True, если параметр просто присутствует в вызове. Так работают параметры-переключатели switch, такие как параметр –recurse в командлете Get-ChildItem.

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

[CmdletBinding()] Param( [Parameter(Mandatory=$True,Position=1)] [string]$computerName, [Parameter(Mandatory=$True)] [string]$filePath )

Весь параметр –computerName, включая его декоратор [Parameter()], размещается до запятой. Запятая означает, что я закончил объявление первого параметра и готов перейти к следующему. Все относящееся к параметру –filePath размещено после запятой. Если мне нужен третий параметр, я добавлю еще одну запятую:

[CmdletBinding()] Param( [Parameter(Mandatory=$True,Position=1)] [string]$computerName, [Parameter(Mandatory=$True)] [string]$filePath, [switch]$DoSomething )

Все это располагается в блоке Param(). Заметьте, что совершенно не обязательно использовать декоратор [Parameter()] в каждом параметре. Он нужен, когда требуется объявить что-то — обязательность параметра, способность принять входные данные из конвейера, размещение в определенной позиции и т. п. Чтобы узнать подробнее о том, какие другие атрибуты можно таким способом объявлять, выполните в Windows PowerShell команду help about_functions_advanced_parameters.

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

Дон Джонс (Don Jones) — носит звание MVP и является автором «Learn Windows PowerShell in a Month of Lunches» (Manning Publications Co., 2011),  книги, призванной помочь каждому администратору освоить Windows PowerShell. Дон читает общедоступные и интерактивные курсы по Windows PowerShell. Связаться с ним можно через его веб-сайт ConcentratedTech.com.

technet.microsoft.com

Наборы параметров - Get-PowerShell

Недавно стояла задача написать скрипт, в котором были бы разные параметры для разных сценариев применения данного скрипта. Например, если указан параметр Param1 выполнять одно действие, если указан Param2 выполнять другое действие, но вместе Param1 и Param2 указываться не могут. Для решения данной задачи идеально подходят так называемые наборы параметров в PowerShell. Вот о них и пойдет речь в этой статье.

Param1 или Param2

Я уже рассказывал о параметризованных скриптах в своей статье скрипты PowerShell. Рекомендую с ней ознакомиться, если Вы не знакомы с возможностью PowerShell писать скрипты с параметрами.

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

[CmdletBinding()] Param (   [parameter(Mandatory=$true)]   [string]$Folder,   [parameter(ParameterSetName="VirtualMachineByName",ValueFromPipeline=$true)]   [string[]]$VirtualMachines = $null,   [parameter(ParameterSetName="VirtualMachineFromFile")]   [switch]$FromFile,   [string]$Network,   [switch]$Export ) $psCmdlet.ParameterSetName

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

[CmdletBinding()]

Param

(

  [parameter(Mandatory=$true)]

  [string]$Folder,

 

  [parameter(ParameterSetName="VirtualMachineByName",ValueFromPipeline=$true)]

  [string[]]$VirtualMachines = $null,

 

  [parameter(ParameterSetName="VirtualMachineFromFile")]

  [switch]$FromFile,

 

  [string]$Network,

 

  [switch]$Export

)

 

$psCmdlet.ParameterSetName

В этом примере мы видим 5 параметров Folder, VirtualMachines, FromImportFile, Network, Export. Параметр VirtualMachines будет использоваться только в наборе параметров VirtualMachineByName, а параметр FromFile будет использоваться в наборе параметров VirtualMachineFromFile. Таким образом одновременное использование этих параметров будет невозможно. Все остальные параметры можно будет использовать в любом из наборов параметров.

Давайте я сохраню данный скрипт под именем temp.ps1 и запущу справку к нему.

PS C:\> Get-Help .\temp.ps1 temp.ps1 -Folder <string> [-VirtualMachines <string[]>] [-Network <string>] [-Export] [<CommonParameters>] temp.ps1 -Folder <string> [-FromFile] [-Network <string>] [-Export] [<CommonParameters>]

PS C:\> Get-Help .\temp.ps1

temp.ps1 -Folder <string> [-VirtualMachines <string[]>] [-Network <string>] [-Export] [<CommonParameters>]

temp.ps1 -Folder <string> [-FromFile] [-Network <string>] [-Export] [<CommonParameters>]

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

Param1 или Param2 или ни одного из них

К сожалению, вышеприведенный скрипт не реализует еще один из необходимых мне сценариев. Скрипт должен запускаться и без данных параметров. Фактически это означает что необходим третий сценарий, в котором будут отсутствовать оба из этих параметров.

И тут есть два варианта или мы добавляем третий параметр или обходимся без него. Меня добавление еще одного параметра не устраивало. Поэтому в вызов CmdletBinding я добавил DefaultParameterSetName и значение All.

[CmdletBinding(DefaultParameterSetName="All")] Param ( [parameter(Mandatory=$true)] [string]$Folder, [parameter(ParameterSetName="VirtualMachineByName",ValueFromPipeline=$true)] [string[]]$VirtualMachines = $null, [parameter(ParameterSetName="VirtualMachineFromFile")] [switch]$FromFile, [string]$Network, [switch]$Export ) $psCmdlet.ParameterSetName

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

[CmdletBinding(DefaultParameterSetName="All")]

Param

(

  [parameter(Mandatory=$true)]

  [string]$Folder,

 

  [parameter(ParameterSetName="VirtualMachineByName",ValueFromPipeline=$true)]

  [string[]]$VirtualMachines = $null,

 

  [parameter(ParameterSetName="VirtualMachineFromFile")]

  [switch]$FromFile,

 

  [string]$Network,

 

  [switch]$Export

)

 

$psCmdlet.ParameterSetName

Данный подход указал, что по умолчанию будет использоваться набор параметров All. У меня он не используется, поэтому все те параметры, у которых не указан явно набор параметров будут относится к набору параметров All. Справка это подтверждает.

PS C:\> Get-Help .\temp.ps1 temp.ps1 -Folder <string> [-Network <string>] [-Export] [<CommonParameters>] temp.ps1 -Folder <string> [-VirtualMachines <string[]>] [-Network <string>] [-Export] [<CommonParameters>] temp.ps1 -Folder <string> [-FromFile] [-Network <string>] [-Export] [<CommonParameters>]

PS C:\> Get-Help .\temp.ps1

temp.ps1 -Folder <string> [-Network <string>] [-Export] [<CommonParameters>]

temp.ps1 -Folder <string> [-VirtualMachines <string[]>] [-Network <string>] [-Export] [<CommonParameters>]

temp.ps1 -Folder <string> [-FromFile] [-Network <string>] [-Export] [<CommonParameters>]

Напоследок

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

[CmdletBinding(DefaultParameterSetName="All")] Param ( [parameter(Mandatory=$true)] [string]$Folder, [parameter(ParameterSetName="VirtualMachineByName",ValueFromPipeline=$true)] [string[]]$VirtualMachines = $null, [parameter(ParameterSetName="VirtualMachineFromFile")] [switch]$FromFile, [parameter(ParameterSetName="VirtualMachineByName")] [parameter(ParameterSetName="VirtualMachineFromFile")] [string]$Network, [switch]$Export ) $psCmdlet.ParameterSetName

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

[CmdletBinding(DefaultParameterSetName="All")]

Param

(

  [parameter(Mandatory=$true)]

  [string]$Folder,

 

  [parameter(ParameterSetName="VirtualMachineByName",ValueFromPipeline=$true)]

  [string[]]$VirtualMachines = $null,

 

  [parameter(ParameterSetName="VirtualMachineFromFile")]

  [switch]$FromFile,

 

  [parameter(ParameterSetName="VirtualMachineByName")]

  [parameter(ParameterSetName="VirtualMachineFromFile")]

  [string]$Network,

 

  [switch]$Export

)

 

$psCmdlet.ParameterSetName

В данном примере параметр Network используется только для наборов параметров VirtualMachineByName и VirtualMachineFromFile. О чем говорит справка:

PS C:\> Get-Help .\temp.ps1 temp.ps1 -Folder <string> [-Export] [<CommonParameters>] temp.ps1 -Folder <string> [-VirtualMachines <string[]>] [-Network <string>] [-Export] [<CommonParameters>] temp.ps1 -Folder <string> [-FromFile] [-Network <string>] [-Export] [<CommonParameters>]

PS C:\> Get-Help .\temp.ps1

temp.ps1 -Folder <string> [-Export] [<CommonParameters>]

temp.ps1 -Folder <string> [-VirtualMachines <string[]>] [-Network <string>] [-Export] [<CommonParameters>]

temp.ps1 -Folder <string> [-FromFile] [-Network <string>] [-Export] [<CommonParameters>]

Почитать напоследок

Блог MSDN — Fun With Parameter Binding: The Fake Parameter Set Trick

Справка MSDN — Наборы параметров

 

 

get-powershell.ru

powershell - Как передать необходимые параметры скрипту в PowerShell ISE?

Есть и другой способ. Вы можете использовать автоматическую переменную $PSDefaultParameterValues , которая существует (начиная с версии v3) для предоставления новых аргументов по умолчанию для командлетов и расширенных функций (не работает с обычными функциями). Однако он работает для скриптов, даже при отладке в ISE. Вы должны объявить [CmdletBinding()] или [Parameter()] как и для расширенной функции.

Итак, для вашего примера,

[CmdletBinding()] param ($G_ARCHIVE = $(throw "Need file to upload!"), $G_LOGFILE = $(throw "Need logfile!"))

вы выполнили бы что-то вроде этого в запросе ISE:

$PSDefaultParameterValues.add("ExampleScript.ps1:G_ARCHIVE","File-to-upload.txt") $PSDefaultParameterValues.add("ExampleScript.ps1:G_LOGFILE","Example.log")

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

$PSDefaultParameterValues["ExampleScript.ps1:G_LOGFILE"]={ "Example-{0:yyMMddHHmm}.log" -f [datetime]::Now }

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

Делая это таким образом, вы можете просто нажать F5, чтобы запустить ваш скрипт, как обычно. Параметры будут взяты из переменной, поэтому вам не нужно вводить что-либо.

Другими вариантами использования для $PSDefaultParameterValues могут быть настройки, например, если Get-History получает только последние 10 записей, если вы не укажете параметр -Count в команде. Поскольку записи сохраняются только для текущего сеанса, вы хотели бы добавить настройки в свой profile . Вы можете прочитать больше, набрав в Get-Help about_Parameters_Default_Values строке Get-Help about_Parameters_Default_Values или просмотрите ту же информацию о TechNet .

code-examples.net

powershell - Требование параметров в PowerShell при наличии другого параметра

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

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

Param( [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [string]$Username, [switch]$RetainGroups, [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)] [switch]$TransferHomeDrive, [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)] [string]$OldServer, [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)] [string]$NewServer )

Итак, если он работает, вы можете запустить

Move-AccountOut -Username JohnSmith -RetainGroups

И он не будет планировать передачу домашнего диска. Однако, если вы должны были запустить

Move-AccountOut -Username JohnSmith -RetainGroups -TransferHomeDrive

Он будет запрашивать для OldServer и NewServer.

Я нашел похожие вопросы, в том числе, но он все еще не работает:

Обязательный параметр PowerShell зависит от другого параметра

Наличие необязательного параметра, который требует наличия другого параметра

Я считаю, что это сработает, если я RetainGroups второй набор параметров, включающий ВСЕ параметры, включая Username и RetainGroups, но, похоже, согласно другим сообщениям, которые я должен иметь, чтобы он работал так, как я его написал, где Username и RetainGroups являются "глобальными" параметрами, а OldServer и NewServer требуются только при установке TransferHomeDrive

qaru.site

powershell - PowerShell Новые позиции Параметрические параметры

Пример на этой странице просто неверен. Кажется, они имели в виду ссылку на C:\Scripts\WindowsPowerShell или они забыли указать каталог с пробелами в нем.

Таким образом, это должно было быть одно из следующих:

New-Item c:\scripts\WindowsPowerShell -type directory New-Item 'c:\scripts\Windows PowerShell' -type directory New-Item "c:\scripts\Windows PowerShell" -type directory

Спросите себя, что будет PowerShell только PowerShell? Каким параметром он бы соответствовал?

Изменение: как указывали комментаторы, в примере должны отображаться параметры nameSet, где -Path отдельные -Path и -Name, и, предположительно, PowerShell должен был быть значением параметра -Name. Это выглядит правильно. Причина, по которой этот пример не работал (и ваш, а также), заключается в том, что параметр -Name не может быть указан позиционно, что вы можете увидеть в статье MSDN I, связанной с ниже, и во встроенной справке:

Type: String Parameter Sets: nameSet Aliases: Required: True Position: Named Default value: None Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False

В этом случае их пример должен был быть примерно таким:

New-Item c:\scripts\Windows -Name PowerShell -type directory New-Item -Path c:\scripts\Windows -Name PowerShell -type directory

Повторяя, названные параметры работали бы здесь и избежали бы путаницы.

Как правило, вы не должны использовать позиционные параметры в сценариях, если они не очень понятны (и даже тогда я бы рекомендовал избегать).

Использование названных параметров упростило бы это. И завершение табуляции помогает с заполнением имен параметров и при завершении путей (обычно также с правильным цитированием).

Я думаю, вы должны изменить свое:

New-Item -Path $backupPath -Type Directory -Force

И, глядя на эту техническую статью, это действительно не так хорошо. Статья MSDN в New-Item лучше, и это информация, которую вы должны увидеть при запуске Get-Help New-Item.

Боковой вопрос:

Опять же, PowerShell может выйти из строя, если скрипт слишком длинный.

Какие?

qaru.site

parameter-passing - Как передать необходимые параметры в script в PowerShell ISE?

Есть и другой способ. Вы можете использовать автоматическую переменную $PSDefaultParameterValues, которая существует (начиная с версии v3) для предоставления новых аргументов по умолчанию для командлетов и расширенных функций (не работает с обычными функциями). Однако он работает для скриптов, даже при отладке в ISE.

Итак, для вашего примера

param ($G_ARCHIVE = $(throw "Need file to upload!"), $G_LOGFILE = $(throw "Need logfile!"))

вы выполнили бы что-то подобное в запросе ISE:

$PSDefaultParameterValues.add("ExampleScript.ps1:G_ARCHIVE","File-to-upload.txt") $PSDefaultParameterValues.add("ExampleScript.ps1:G_LOGFILE","Example.log")

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

$PSDefaultParameterValues["ExampleScript.ps1:G_LOGFILE"]={ "Example-{0:yyMMddHHmm}.log" -f [datetime]::Now }

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

Сделав это, вы можете просто нажать F5, чтобы запустить свой script как обычно. Параметры будут взяты из переменной, поэтому вам нечего вводить.

Другими вариантами использования для $PSDefaultParameterValues могут быть настройки, например, если Get-History получает только последние 10 записей, если вы не укажете параметр -Count в команде. Поскольку записи сохраняются только для текущего сеанса, вы хотели бы добавить настройки в профиль. Вы можете прочитать больше, набрав Get-Help about_Parameters_Default_Values в приглашении или просмотрите ту же информацию на TechNet.

qaru.site

parameters - Параметры PowerShell не распознаются

У меня есть командлет powershell, и я не могу заставить набор параметров работать. Этот командлет имеет 31 возможный параметр, и он может опускать два возможных пути обработки. Все 31 параметры являются необязательными, 18 являются общими для обоих путей, 9 уникальны для "правильного" пути, а 4 уникальны для "левого" пути. То, что я пытаюсь выполнить, - использовать атрибуты параметра powershell ParameterSet, чтобы указать, какой параметр можно использовать, когда. Но это не работает.

Ниже приведен макет моей попытки. Имена изменены для защиты невинных.

[Parameter] public string SomeString1 { get; set; } [Parameter] public string SomeString2 { get; set; } [Parameter(ParameterSetName = "left")] public string LeftName { get; set; } [Parameter(ParameterSetName = "left")] public string LeftDomain { get; set; } [Parameter(ParameterSetName = "right")] public string RightID { get; set; } [Parameter(ParameterSetName = "right")] public string RightIP { get; set; }

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

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

Я попытался изменить некоторые/все параметры на Mandatory, я попытался использовать DefaultParameterSetName в заголовке. Я пробовал удваивать наборы, например, включать набор с именем "both" и составлять каждую часть параметра этого набора. Я прочитал статью MSDN о наборах параметров, я прочитал первые 40 статей, которые google возвращает, но я не могу заставить их работать. Половина моей команды стояла за моим столом, наблюдая за тем, как я это делаю, и все они тоже в тупике.

Что я могу сделать для:

  • выяснить, почему он не распознает мои наборы параметров
  • сделайте так, чтобы он
  • предотвратить это в будущем

qaru.site