Как передать именованные параметры с помощью Invoke-Command?

У меня есть сценарий, который я могу запустить удаленно с помощью команды Invoke-Command

Invoke-Command -ComputerName (Get-Content C:\Scripts\Servers.txt) ` -FilePath C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 

Пока я использую параметры по умолчанию, он работает нормально. Тем не менее, сценарий имеет 2 параметра [switch] (-Debug и -Clear)

Как передать параметры переключения через Invoke-Command? Я пробовал -ArgumentList, но я получаю ошибки, поэтому я должен иметь синтаксис неправильно или что-то в этом роде. Любая помощь приветствуется.

-ArgumentList основан на использовании команд scriptblock , таких как:

 Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True 

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

Итак, у вас есть два варианта:

Если у вас есть сценарий, похожий на этот, в сетевом местоположении, доступном с удаленной машины (обратите внимание, что -Debug подразумевается, потому что, когда я использую атрибут Parameter , скрипт получает CmdletBinding неявно и, следовательно, все общие параметры):

 param( [Parameter(Position=0)] $one , [Parameter(Position=1)] $two , [Parameter()] [Switch]$Clear ) "The test is for '$one' and '$two' ... and we $(if($DebugPreference -ne 'SilentlyContinue'){"will"}else{"won't"}) run in debug mode, and we $(if($Clear){"will"}else{"won't"}) clear the logs after." 

Не зацикливаясь на значении $Clear …, если вы хотите вызвать, что вы можете использовать любой из следующих синтаксисов Invoke-Command :

 icm -cn (gc Servers.txt) { param($one,$two,$Debug=$False,$Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 @PSBoundParameters } -ArgumentList "uno", "dos", $false, $true 

В этом я дублирую ВСЕ параметры, которые меня волнуют в скриптблоке, поэтому я могу передавать значения. Если я могу их жестко закодировать (это то, что я на самом деле сделал), нет необходимости делать это и использовать PSBoundParameters , я могу просто передать те, которые мне нужны. Во втором примере ниже я собираюсь передать $ Clear, просто чтобы продемонстрировать, как передавать параметры переключателя:

 icm -cn $Env:ComputerName { param([bool]$Clear) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear } -ArgumentList $(Test-Path $Profile) 

Другой вариант

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

 $script = [scriptblock]::create( @" param(`$one,`$two,`$Debug=`$False,`$Clear=`$False) &{ $(Get-Content C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -delimiter ([char]0)) } @PSBoundParameters "@ ) Invoke-Command -Script $script -Args "uno", "dos", $false, $true 

PostScript:

Если вам действительно нужно передать переменную для имени сценария, то что вы будете делать, будет зависеть от того, определена ли переменная локально или удаленно. В общем случае, если у вас есть переменная $Script или переменная среды $Env:Script с именем скрипта, вы можете выполнить ее с помощью оператора вызова (&): &$Script или &$Env:Script

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

 Invoke-Command -cn $Env:ComputerName { param([String]$Script, [bool]$Clear) &$Script "uno" "dos" -Debug -Clear:$Clear } -ArgumentList $ScriptPath, $(Test-Path $Profile) 

Моим решением было написать динамический блок сценария с помощью [scriptblock]:Create :

 # Or build a complex local script with MARKERS here, and do substitutions # I was sending install scripts to the remote along with MSI packages # ...for things like Backup and AV protection etc. $p1 = "good stuff"; $p2 = "better stuff"; $p3 = "best stuff"; $etc = "!" $script = [scriptblock]::Create("MyScriptOnRemoteServer.ps1 $p1 $p2 $etc") #strings get interpolated/expanded while a direct scriptblock does not # the $parms are now expanded in the script block itself # ...so just call it: $result = invoke-command $computer -script $script 

Передача аргументов была очень расстраивающей, пытаясь использовать различные методы, например,
-arguments , $using:p1 и т. д., и это просто работало по желанию без проблем.

Поскольку я контролирую содержимое и расширение переменной строки, которая создает [scriptblock] (или файл сценария) таким образом, нет реальной проблемы с заклинанием «invoke-command».

(Это не должно быть так сложно 🙂 🙂

Мне нужно было что-то, чтобы вызвать скрипты с именованными параметрами. У нас есть политика не использовать порядковое позиционирование параметров и требование имени параметра.

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

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

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

 [CmdletBinding(PositionalBinding = $False)] param ( [Parameter(Mandatory = $True)] [String] $MyNamedParameter1, [Parameter(Mandatory = $True)] [String] $MyNamedParameter2, [Parameter(Mandatory = $False)] [String] $MyNamedParameter3 = "some default value" ) 

Так я бы назвал этот скрипт из другого сценария:

 $params = @{ MyNamedParameter1 = $SomeValue MyNamedParameter2 = $SomeOtherValue } If ($SomeCondition) { $params['MyNamedParameter3'] = $YetAnotherValue } $pathToScript = Join-Path -Path $env:Temp -ChildPath MyScript.ps1 $sb = [scriptblock]::create(".{$(Get-Content -Path $pathToScript -Raw)} $(&{ $args } @params)") Invoke-Command -ScriptBlock $sb 

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

Например, этот блок параметров используется для вызова сценария, который копирует различные модули в стандартное местоположение, используемое PowerShell C:\Program Files\WindowsPowerShell\Modules которое содержит пробельный символ.

 $params = @{ SourcePath = "$WorkingDirectory\Modules" DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'" } 

Надеюсь это поможет!

Я подозреваю, что это новая функция, поскольку этот пост был создан – передать параметры блоку скрипта, используя $ Using: var. Затем его простой способ передать параметры, если скрипт уже находится на машине или в известном сетевом местоположении относительно машины

В качестве основного примера можно привести:

 icm -cn $Env:ComputerName { C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear } 
Давайте будем гением компьютера.