Como faço para passar parâmetros nomeados com Invoke-Command?

Eu tenho um script que eu posso executar remotamente via Invoke-Command

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

Desde que eu use os parâmetros padrão, ele funciona bem. No entanto, o script tem 2 parâmetros [switch] nomeados (-Debug e -Clear)

Como posso passar os parâmetros comutados através do comando Invoke-Command? Eu tentei o -ArgumentList mas estou recebendo erros, então devo ter a syntax errada ou algo assim. Qualquer ajuda é muito apreciada.

-ArgumentList é baseado no uso com comandos scriptblock , como:

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

Quando você o chama com um -File ele ainda passa os parâmetros como um array splatted mudo. Eu enviei uma solicitação de recurso para ter isso adicionado ao comando (por favor, vote em cima).

Então você tem duas opções:

Se você tiver um script semelhante a este, em um local de rede acessível a partir da máquina remota (observe que -Debug está implícito porque quando eu uso o atributo Parameter , o script obtém CmdletBinding implicitamente e, portanto, todos os parâmetros comuns):

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

Sem ficar preso no significado de $Clear … se você quisesse invocar que você poderia usar uma das seguintes syntaxs 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 

Nesse, estou duplicando TODOS os parâmetros que me interessam no scriptblock para que eu possa passar valores. Se eu puder codificá-los (que é o que eu realmente fiz), não há necessidade de fazer isso e usar PSBoundParameters , posso apenas passar os que eu preciso. No segundo exemplo abaixo, vou passar o $ Clear, apenas para demonstrar como passar os parâmetros do switch:

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

A outra opção

Se o script estiver em sua máquina local e você não quiser alterar os parâmetros para serem posicionados, ou se quiser especificar parâmetros que são parâmetros comuns (para não poder controlá-los), será necessário obter o conteúdo de esse script e incorpore-o em seu 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 

PostScript:

Se você realmente precisar passar uma variável para o nome do script, o que você faria dependeria se a variável fosse definida local ou remotamente. Em geral, se você tiver uma variável $Script ou uma variável de ambiente $Env:Script com o nome de um script, você pode executá-la com o operador de chamada (&): &$Script ou &$Env:Script

Se for uma variável de ambiente já definida no computador remoto, isso é tudo. Se for uma variável local , você terá que passá-lo para o bloco de script remoto:

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

Minha solução para isso foi escrever o bloco de script dinamicamente com [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 

Passar argumentos foi muito frustrante, tentando vários methods, por exemplo,
-arguments , $using:p1 , etc e isso só funcionou como desejado sem problemas.

Como eu controlo o conteúdo e a expansão de variables ​​da string que cria o [scriptblock] (ou arquivo de script) dessa forma, não há nenhum problema real com o encantamento “invoke-command”.

(Não deve ser tão difícil. :))

Eu precisava de algo para chamar scripts com parâmetros nomeados. Temos uma política de não usar o posicionamento ordinal de parâmetros e exigir o nome do parâmetro.

Minha abordagem é semelhante àquelas acima, mas obtém o conteúdo do arquivo de script que você deseja chamar e envia um bloco de parâmetros contendo os parâmetros e valores.

Uma das vantagens disso é que você pode optar por escolher quais parâmetros enviar para o arquivo de script, permitindo parâmetros não obrigatórios com padrões.

Supondo que haja um script chamado “MyScript.ps1” no caminho temporário que possui o seguinte bloco de parâmetros:

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

É assim que eu chamaria esse script de outro script:

 $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 

Eu usei isso em muitos cenários e funciona muito bem. Uma coisa que você ocasionalmente precisa fazer é colocar aspas ao redor do bloco de atribuição de valor de parâmetro. Esse é sempre o caso quando há espaços no valor.

Por exemplo, esse bloco de parâmetros é usado para chamar um script que copia vários módulos para o local padrão usado pelo PowerShell C:\Program Files\WindowsPowerShell\Modules que contém um caractere de espaço.

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

Espero que isto ajude!

Eu suspeito que é um novo recurso desde que este post foi criado – passe parâmetros para o bloco de script usando $ Using: var. Então é uma mater simples para passar parâmetros desde que o script já esteja na máquina ou em um local de rede conhecido em relação à máquina

Tomando o exemplo principal, seria:

 icm -cn $Env:ComputerName { C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear }