Je sens que je manque quelque chose qui devrait être évident, mais je ne peux pas comprendre comment faire cela.
J'ai un script ps1 qui a une fonction définie dans celui-ci. Il appelle la fonction et essaie de l'utiliser à distance:
function foo
{
Param([string]$x)
Write-Output $x
}
foo "Hi!"
Invoke-Command -ScriptBlock { foo "Bye!" } -ComputerName someserver.example.com -Credential [email protected]
Ce court exemple de script affiche "Bonjour!" puis se bloque en disant "Le terme 'foo' n'est pas reconnu comme le nom d'une applet de commande, d'une fonction, d'un fichier de script ou d'un programme utilisable."
Je comprends que la fonction n'est pas définie sur le serveur distant, car ce n'est pas dans le ScriptBlock. Je pourrais le redéfinir ici, mais je préférerais ne pas le faire. Je voudrais définir la fonction une fois et l'utiliser soit localement ou à distance. Y at-il un bon moyen de le faire?
Vous devez transmettre la fonction elle-même (pas un appel à la fonction dans la variable ScriptBlock
).
J'avais le même besoin la semaine dernière et j'ai trouvé cette SO discussion
Donc, votre code deviendra:
Invoke-Command -ScriptBlock ${function:foo} -argumentlist "Bye!" -ComputerName someserver.example.com -Credential [email protected]
Notez qu'en utilisant cette méthode, vous ne pouvez transmettre des paramètres à votre fonction que par position; vous ne pouvez pas utiliser les paramètres nommés comme vous le pouvez lorsque vous exécutez la fonction localement.
Vous pouvez passer la définition de la fonction en tant que paramètre, puis redéfinir la fonction sur le serveur distant en créant un scriptblock puis en le dotant de source:
$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!"
}
Cela élimine le besoin d'avoir une copie en double de votre fonction. Vous pouvez également transmettre plus d’une fonction de cette façon, si vous le souhaitez:
$allFunctionDefs = "function foo { ${function:foo} }; function bar { ${function:bar} }"
Vous pouvez également placer les fonctions ainsi que le script dans un fichier (foo.ps1) et le transmettre à Invoke-Command à l'aide du paramètre FilePath:
Invoke-Command –ComputerName server –FilePath .\foo.ps1
Le fichier sera copié sur les ordinateurs distants et exécuté.
Bien que ce soit une vieille question, je voudrais ajouter ma solution.
Assez drôle, la liste de paramètres du scriptblock dans la fonction test ne prend pas d'argument de type [scriptblock] et nécessite par conséquent une conversion.
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
Une autre possibilité est de passer une table de hachage à notre script qui contient toutes les méthodes que vous aimeriez avoir disponibles dans la session distante:
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