trustedhosts remoto remote enable computer powershell powershell-v2.0 powershell-remoting

remoto - ¿Cómo incluyo una función definida localmente cuando uso el Invoke-Command de PowerShell para la comunicación remota?



windows 10 remote powershell (4)

Siento que me estoy perdiendo algo que debería ser obvio, pero simplemente no puedo entender cómo hacer esto.

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?


Aunque esa es una vieja pregunta, me gustaría agregar mi solución.

Bastante gracioso es la lista de parámetros del scriptblock dentro de la prueba de función, no toma un argumento de tipo [scriptblock] y por lo tanto necesita conversión.

Function Write-Log { param( [string]$Message ) Write-Host -ForegroundColor Yellow "$($env:computername): $Message" } Function Test { $sb = { param( [String]$FunctionCall ) [Scriptblock]$WriteLog = [Scriptblock]::Create($FunctionCall) $WriteLog.Invoke("There goes my message...") } # Get function stack and convert to type scriptblock [scriptblock]$writelog = (Get-Item "Function:Write-Log").ScriptBlock # Invoke command and pass function in scriptblock form as argument Invoke-Command -ComputerName SomeHost -ScriptBlock $sb -ArgumentList $writelog } Test

Otra posibilidad es pasar una tabla hash a nuestro scriptblock que contiene todos los métodos que le gustaría tener disponibles en la sesión remota:

Function Build-FunctionStack { param([ref]$dict, [string]$FunctionName) ($dict.Value).Add((Get-Item "Function:${FunctionName}").Name, (Get-Item "Function:${FunctionName}").Scriptblock) } Function MyFunctionA { param([string]$SomeValue) Write-Host $SomeValue } Function MyFunctionB { param([int]$Foo) Write-Host $Foo } $functionStack = @{} Build-FunctionStack -dict ([ref]$functionStack) -FunctionName "MyFunctionA" Build-FunctionStack -dict ([ref]$functionStack) -FunctionName "MyFunctionB" Function ExecuteSomethingRemote { $sb = { param([Hashtable]$FunctionStack) ([Scriptblock]::Create($functionStack["MyFunctionA"])).Invoke("Here goes my message"); ([Scriptblock]::Create($functionStack["MyFunctionB"])).Invoke(1234); } Invoke-Command -ComputerName SomeHost -ScriptBlock $sb -ArgumentList $functionStack } ExecuteSomethingRemote


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

Tuve la misma necesidad la semana pasada y encontré esta discusión SO

Entonces tu código se convertirá en:

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

Tenga en cuenta que al usar este método, solo 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.


Puede pasar la definición de la función como parámetro y luego redefinir la función en el servidor remoto creando un scriptblock y luego 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!" }

Esto elimina la necesidad de tener una copia duplicada de su función. También puede pasar más de una función de esta manera, si así lo desea:

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


También puede colocar la función (s) y el script en un archivo (foo.ps1) y pasarlo a Invoke-Command usando el parámetro FilePath:

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

El archivo se copiará en las computadoras remotas y se ejecutará.