2010-11-19 76 views
63

que tienen una secuencia de comandos que se puede ejecutar de forma remota a través de Invoke-Command¿Cómo paso parámetros nombrados con Invoke-Command?

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

Mientras que utilizo parámetros por defecto, funciona bien. Sin embargo, el script tiene 2 parámetros nombrados [cambiar] (-Debug y -Clear)

¿Cómo puedo pasar los parámetros cambiados a través de Invoke-Command? Probé la -ArgumentList pero recibo errores así que debo tener la sintaxis incorrecta o algo así. Cualquier ayuda es muy apreciada.

Respuesta

70

-ArgumentList se basa en el uso con ScriptBlock comandos, como:

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

Cuando se llama con un -File todavía pasa los parámetros como una matriz Splatted mudo. He enviado un feature request para agregarlo al comando (vote eso).

lo tanto, usted tiene dos opciones:

Si usted tiene un script que se veía así, en una ubicación de red accesible desde la máquina remota (Tenga en cuenta que -Debug está implícito, porque cuando se utiliza el atributo Parameter, el guión CmdletBinding obtiene de forma implícita, y por lo tanto, todos los parámetros comunes):

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

sin quedar atrapado en el significado de $Clear ... si quería invocar que se puede utilizar cualquiera de los siguientes Invoke-Command sintaxis:

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

En ese uno, soy la duplicación de todos los parámetros que me importa en el ScriptBlock para que pueda pasar valores. Si puedo codificarlos (que es lo que realmente hice), no hay necesidad de hacer eso y usar PSBoundParameters, puedo pasar los que necesito. En el segundo ejemplo a continuación voy a pasar el $ Borrar uno, sólo para demostrar cómo pasar los parámetros del conmutador:

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

La otra opción

Si el guión es en su máquina local, y usted no desea cambiar los parámetros para que sean posicionales, o si desea especificar parámetros que son parámetros comunes (para que no pueda controlarlos), querrá obtener el contenido de ese script e incrustarlo en su 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:

Si realmente necesita pasar una variable para el nombre del script, lo que haría dependerá de si la variable se define localmente o de forma remota. En general, si usted tiene una variable $Script o una variable de entorno $Env:Script con el nombre de un guión, puede ejecutarlo con el operador de llamada (&): &$Script o &$Env:Script

Si se trata de una variable de entorno que ya está definido en el computadora remota, eso es todo.Si se trata de una variable locales, entonces tendrá que pasar al bloque de secuencia de comandos remota:

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

ArgumentList está disponible con -FilePath además. Invoke-Command [-FilePath] [[-Sesión] ] [-AsJob] [-HideComputerName] [-JobName ] [-T hrottleLimit ] [-ArgumentList ] [-InputObject ] [ ] – ravikanth

+1

Sí ravikanth, pero parece que ArgumentList está splatting a la secuencia de comandos, por lo que no puede especificar los parámetros * named *? – Jaykul

+6

Es una pena que StackOverflow no comprenda el script de PowerShell ... el resaltado de sintaxis de los nombres del script deja mucho que desear. – Jaykul

1

Mi solución a esto fue para escribir el bloque de script de forma dinámica con [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 

Paso de argumentos fue muy frustrante, tratando diversos métodos, por ejemplo,
-arguments, $using:p1, etc., y esto sólo trabajaron como desee sin ningún problema.

Dado que controlo el contenido y la expansión variable de la cadena que crea el [scriptblock] (o archivo de script) de esta manera, no hay un problema real con el encantamiento "invocar-comando".

(No debería ser tan difícil. :))

1

que necesitaba algo para llamar a los scripts con parámetros con nombre. Tenemos una política de no usar el posicionamiento ordinal de los parámetros y que requiera el nombre del parámetro.

Mi enfoque es similar a los anteriores pero se pone el contenido del archivo de script que desea llamar y envía un bloque de parámetros que contiene los parámetros y valores.

Una de las ventajas de esto es que se puede elegir opcionalmente los parámetros que deben enviar al archivo de script que permite parámetros no obligatorios con los valores predeterminados.

Suponiendo que hay un script llamado "MyScript.ps1" en la ruta temporal que tiene el siguiente bloque 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" 
) 

Esta es la forma en que yo llamaría este script desde otro 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 

he utilizado esto en un montón de escenarios y funciona muy bien. Una cosa que de vez en cuando debes hacer es poner comillas alrededor del bloque de asignación de valores de parámetros. Este es siempre el caso cuando hay espacios en el valor.

p. Ej. Este bloque de parámetros se usa para llamar a un script que copia varios módulos en la ubicación estándar utilizada por PowerShell C:\Program Files\WindowsPowerShell\Modules que contiene un carácter de espacio.

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

Hope this helps!

1

sospecho que es una nueva característica desde la creación de este post - pasar parámetros al bloque de script utilizando $ Uso: var. Entonces es un mater sencilla para pasar parámetros proporcionan la secuencia de comandos ya está en la máquina o en una ubicación de red conocida con relación a la máquina

Tomando el ejemplo principal sería:

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