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


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

Invoke-Command -ComputerName (Get-Content C:ScriptsServers.txt) `
               -FilePath C:ScriptsArchiveEventLogsver5ArchiveEventLogs.ps1

пока я использую параметры по умолчанию, все прекрасно работает. Однако скрипт имеет 2 именованных параметра [switch] (- Debug и-Clear)

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

4 66

4 ответа:

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

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

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

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

если у вас есть сценарий, который выглядел так, в сетевом расположении, доступном с удаленного компьютера (обратите внимание, что -Debug подразумевается, потому что, когда я использую скрипт получает 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

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

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

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

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

$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

Постскриптум:

если вам действительно нужно передать переменную для имени скрипта, то что вы будете делать, будет зависеть от того, определена ли переменная локально или удаленно. В общем, если у вас есть переменная $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

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

например, этот блок param используется для вызова скрипта, который копирует различные модули в стандартное расположение, используемое 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
}