Pergunta

Eu tenho um script que posso correr remotamente via invocar-command

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

Enquanto eu usar parâmetros padrão, ele funciona bem. No entanto, o script possui 2 parâmetros nomeados [switch] (-debug e -clear)

Como posso passar os parâmetros comutados via Invoke-Command? Eu tentei o -AgumentList, mas estou recebendo erros, então devo ter a sintaxe errada ou algo assim. Qualquer ajuda é muito apreciada.

Foi útil?

Solução

-ArgumentList é baseado no uso com Scriptblock comandos, 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 uma matriz splatted idiota. Eu enviei um solicitação de recurso Para ter isso adicionado ao comando (por favor, vote isso).

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

Se você tem um script que parecia assim, em um local de rede acessível da máquina remota (observe que -Debug está implícito porque quando eu uso o Parameter atributo, o script fica implicitamente em cmdletbinding 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 pendurado no significado de $Clear ... se você quisesse invocar, poderia usar qualquer um dos seguintes Invoke-Command Sintaxe:

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 caso, estou duplicando todos os parâmetros que me preocupo no Scriptblock para que eu possa passar valores. Se eu posso codificá-los (que é o que eu realmente fiz), não há necessidade de fazer isso e usar PSBoundParameters, Eu posso simplesmente passar os que eu preciso. No segundo exemplo abaixo, vou passar o $ CLEAR ONE, apenas para demonstrar como passar os parâmetros do interruptor:

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 na sua máquina local e você não quiser alterar os parâmetros para serem posicionais, ou você deseja especificar parâmetros que são parâmetros comuns (para que você não possa controlá -los), você desejará obter o conteúdo de aquele script e incorporá -lo 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 em uma variável para o nome do script, o que você fará dependerá se a variável é 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á -lo com o operador de chamada (&): &$Script ou &$Env:Script

Se é uma variável de ambiente que já está definida no computador remoto, isso é tudo o que existe. Se for um local Variável, então você terá que passar 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)

Outras dicas

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

Argumentos passantes foram muito frustrantes, tentando vários métodos, por exemplo,
-arguments, $using:p1, etc. e isso funcionou como desejado sem problemas.

Desde que eu controlo o conteúdo e a expansão variável da string que cria o [scriptblock] (ou arquivo de script) Dessa forma, não há problema real com o encantamento "Invoke-Command".

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

Suspeito que seja um novo recurso desde que este post foi criado - PASS parâmetros para o bloco de script usando $ usando: var. Então é um simples Mater 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
}

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 aos acima, mas obtém o conteúdo do arquivo de script que você deseja ligar e envia um bloco de parâmetros que contém os parâmetros e valores.

Uma das vantagens disso é que você pode opcionalmente 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 cotações em torno do bloco de atribuição de valor do parâmetro. Este é sempre o caso quando há espaços no valor.

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

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

Espero que isto ajude!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top