2012-07-06 13 views
21

Mi sento come se mi mancasse qualcosa che dovrebbe essere ovvio, ma non riesco proprio a capire come farlo.Come includere una funzione definita localmente quando si utilizza Invoke-Command di PowerShell per la comunicazione remota?

Ho uno script ps1 che ha una funzione definita in esso. Chiama la funzione e prova a utilizzarla da remoto:

function foo 
{ 
    Param([string]$x) 

    Write-Output $x 
} 

foo "Hi!" 

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

Questo breve script di esempio stampa "Ciao!" e poi si blocca dicendo "Il termine 'pippo' non è riconosciuto come il nome di un cmdlet, una funzione, un file di script o un programma eseguibile."

Capisco che la funzione non è definita sul server remoto perché non è in ScriptBlock. Potrei ridefinirlo lì, ma preferirei di no. Mi piacerebbe definire la funzione una volta e usarla localmente o in remoto. C'è un buon modo per farlo?

risposta

25

È necessario passare la funzione stessa (non una chiamata alla funzione nello ScriptBlock).

ho avuto la stessa necessità proprio la scorsa settimana e abbiamo trovato this SO discussion

Quindi il codice diventerà:

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

Si noti che utilizzando questo metodo, è possibile passare solo i parametri nel tuo funzione posizionale; non è possibile utilizzare parametri denominati come è possibile quando si esegue la funzione localmente.

+0

Ok, sembra simile a qualcosa che avrei letto. Quindi facendo un passo in più: c'è un buon modo per includere la funzione e alcune linee aggiuntive di script che usano la funzione? –

+0

Non ho ancora provato questo, ma se vuoi formattare l'output della funzione (per esempio), questo dovrebbe funzionare: '-ScriptBlock {$ function: foo | format-table -auto}'. Fondamentalmente ogni 'ScriptBlock' può essere un qualsiasi" pezzo "di codice PowerShell valido, quindi se lo si formatta correttamente (o si usa il punto e virgola alla fine di ogni" linea "), si dovrebbe essere buoni. All'inizio di oggi stavo girando con 'measure-command {$ x = [xml] (get-content file.xml); $ x.selectsinglenode (" // thing ");}, per esempio. – alroc

20

È possibile passare alla definizione della funzione come parametro, e quindi ridefinire la funzione sul server remoto creando uno scriptblock e poi dot-sourcing è:

$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!" 
} 

Questo elimina la necessità di avere un copia duplicata della tua funzione. È inoltre possibile passare più di una funzione in questo modo, se siete così inclinato:

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

Esattamente quello che stavo cercando! La tua soluzione in combinazione con '$ Using: Var' ha fatto il trucco :) Grazie mille! – DarkLite1

+0

Molto bello, esattamente quello che stavo cercando. Grazie per aver condiviso – vdubgeek

4

si può anche mettere la funzione (s), così come lo script in un file (foo.ps1) e pass che a Invoke-Command mediante il parametro FilePath:

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

il file verrà copiato sul computer remoti e giustiziati.

+0

Questa è l'opzione migliore. Riduce l'ingombro ed è facile. Scrivi la sceneggiatura proprio come vuoi che venga eseguita e voilà! –

Problemi correlati