2012-07-06 15 views
21

Siento que me falta algo que debería ser obvio, pero no puedo entender cómo hacerlo.¿Cómo incluyo una función definida localmente cuando uso el Invoke-Command de PowerShell para la comunicación remota?

Tengo un script ps1 que tiene una función definida en él. Llama a la función y luego intenta usarla de forma remota:

function foo 
{ 
    Param([string]$x) 

    Write-Output $x 
} 

foo "Hi!" 

Invoke-Command -ScriptBlock { foo "Bye!" } -ComputerName someserver.example.com -Credential [email protected] 

Este breve script de ejemplo imprime "¡Hola!" y luego se cuelga diciendo "El término 'foo' no se reconoce como el nombre de un cmdlet, función, archivo de script o programa operable".

Entiendo que la función no está definida en el servidor remoto porque no está en ScriptBlock. Podría redefinirlo allí, pero preferiría no hacerlo. Me gustaría definir la función una vez y usarla local o remotamente. ¿Existe una forma correcta de hacer esto?

Respuesta

25

Debe pasar la función en sí (no una llamada a la función en el ScriptBlock).

que tenían la misma necesidad de la semana pasada y se encontró this SO discussion

Así que el código será:

Invoke-Command -ScriptBlock ${function:foo} -argumentlist "Bye!" -ComputerName someserver.example.com -Credential [email protected] 

Tenga en cuenta que mediante el uso de este método, sólo se puede pasar parámetros en su función posicionalmente; no puede hacer uso de parámetros con nombre como podría hacerlo al ejecutar la función localmente.

+0

Bueno, eso suena similar a algo que hubiera leído. Así que, yendo un paso más allá: ¿hay una buena manera de incluir la función y algunas líneas adicionales de script que usan la función? –

+0

No he probado esto todavía, pero si desea formatear la salida de la función (por ejemplo), esto debería funcionar: '-ScriptBlock {$ función: foo | formato-tabla -auto}'. Básicamente, cualquier 'ScriptBlock' puede ser cualquier" porción "de código válido de PowerShell, por lo que siempre que lo formatee adecuadamente (o use puntos y comas al final de cada" línea "), debería estar bien. El día de hoy estaba haciendo el tonto con 'measure-command {$ x = [xml] (get-content file.xml); $ x.selectsinglenode (" // thing ");}, por ejemplo. – alroc

20

Puede pasar la definición de la función como un parámetro, y luego redefinir la función en el servidor remoto mediante la creación de un ScriptBlock y luego dot-sourcing que:

$fooDef = "function foo { ${function:foo} }" 

Invoke-Command -ArgumentList $fooDef -ComputerName someserver.example.com -ScriptBlock { 
    Param($fooDef) 

    . ([ScriptBlock]::Create($fooDef)) 

    Write-Host "You can call the function as often as you like:" 
    foo "Bye" 
    foo "Adieu!" 
} 

Esto elimina la necesidad de tener una copia duplicada de tu función También se puede pasar más de una función de esta manera, si usted está tan inclinado:

$allFunctionDefs = "function foo { ${function:foo} }; function bar { ${function:bar} }" 
+0

¡Exactamente lo que estaba buscando! Su solución en combinación con '$ Using: Var' hizo el truco :) ¡Muchas gracias! – DarkLite1

+0

Muy bueno, exactamente lo que estaba buscando. Gracias por compartir – vdubgeek

4

También se puede poner la función (s), así como la secuencia de comandos en un archivo (foo.ps1) y que pase a Invoke-Command con el parámetro FilePath:

Invoke-Command –ComputerName server –FilePath .\foo.ps1 

el archivo se copiará en los equipos remotos y ejecutados.

+0

Esta es la mejor opción. Reduce el desorden y es fácil. Escriba el guión tal como lo quiere ejecutar y ¡listo! –

Cuestiones relacionadas