J'ai un script que je peux exécuter à distance via Invoke-Command
Invoke-Command -ComputerName (Get-Content C:\Scripts\Servers.txt) `
-FilePath C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1
Tant que j'utilise les paramètres par défaut, cela fonctionne bien. Cependant, le script a 2 paramètres nommés [switch] (-Debug et -Clear)
Comment puis-je transmettre les paramètres commutés via Invoke-Command? J'ai essayé le -ArgumentList mais je reçois des erreurs, donc la syntaxe doit être incorrecte ou quelque chose du genre. Toute aide est grandement appréciée.
-ArgumentList
est basé sur une utilisation avec scriptblock , comme:
Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True
Quand vous l'appelez avec un -File
il passe toujours les paramètres comme un tableau stupide. J'ai soumis un demande de fonctionnalité pour l'ajouter à la commande (votez pour cela).
Donc, vous avez deux options:
Si vous avez un script qui ressemble à ceci, dans un emplacement réseau accessible à partir de la machine distante (notez que -Debug
est impliqué car lorsque j'utilise l'attribut Parameter
, le script obtient CmdletBinding de manière implicite, et donc tous les paramètres communs):
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."
Sans se raccrocher au sens de $Clear
... si vous voulez invoquer que vous pouvez utiliser l'un des éléments suivants Invoke-Command
syntaxes:
icm -cn (gc Servers.txt) {
param($one,$two,$Debug=$False,$Clear=$False)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 @PSBoundParameters
} -ArgumentList "uno", "dos", $false, $true
Dans celui-ci, je duplique TOUS les paramètres qui me tiennent à cœur dans le scriptblock afin que je puisse passer des valeurs. Si je peux les coder en dur (ce que j'ai fait en réalité), inutile de le faire et d'utiliser PSBoundParameters
, je peux simplement passer celles dont j'ai besoin. Dans le deuxième exemple ci-dessous, je vais passer le $ Clear, juste pour montrer comment passer des paramètres de commutateur:
icm -cn $Env:ComputerName {
param([bool]$Clear)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $(Test-Path $Profile)
Si le script se trouve sur votre ordinateur local et que vous ne souhaitez pas modifier les paramètres pour qu'ils soient positionnels, ou si vous souhaitez spécifier des paramètres qui sont des paramètres communs (afin que vous ne puissiez pas les contrôler), vous souhaiterez obtenir le contenu de ce script et l'intégrer dans votre 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
Si vous devez réellement transmettre une variable pour le nom du script, la procédure dépend de la définition de la variable localement ou à distance. En général, si vous avez une variable $Script
ou une variable d'environnement $Env:Script
avec le nom d’un script, vous pouvez l’exécuter avec l’opérateur d’appel (&): &$Script
ou &$Env:Script
S'il s'agit d'une variable d'environnement déjà définie sur l'ordinateur distant, c'est tout. S'il s'agit d'une variable locale , vous devrez la transmettre au bloc de script distant:
Invoke-Command -cn $Env:ComputerName {
param([String]$Script, [bool]$Clear)
&$Script "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, $(Test-Path $Profile)
Ma solution à cela était d'écrire le bloc de script de manière dynamique avec [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
Passer des arguments était très frustrant, essayer diverses méthodes, par exemple,-arguments
, $using:p1
, etc. et cela a fonctionné comme souhaité sans aucun problème.
Depuis que je contrôle le contenu et le développement variable de la chaîne qui crée le [scriptblock]
(ou un fichier de script) de cette façon, il n’ya pas de réel problème avec l’invantation "invoke-command".
(Cela ne devrait pas être si difficile. :))
Je soupçonne que c’est une nouvelle fonctionnalité depuis la publication de ce message - transmettez les paramètres au bloc de script à l’aide de $ Using: var. Ensuite, c’est un simple moyen de transmettre des paramètres à condition que le script se trouve déjà sur la machine ou dans un emplacement réseau connu par rapport à la machine.
Prenant l'exemple principal, il serait:
icm -cn $Env:ComputerName {
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
J'avais besoin de quelque chose pour appeler des scripts avec des paramètres nommés. Nous avons pour politique de ne pas utiliser le positionnement ordinal des paramètres et d’exiger le nom du paramètre.
Mon approche est similaire à celle ci-dessus, mais récupère le contenu du fichier de script que vous voulez appeler et envoie un bloc de paramètres contenant les paramètres et les valeurs.
L'un des avantages de cette option est que vous pouvez éventuellement choisir les paramètres à envoyer au fichier de script, ce qui permet d'utiliser des paramètres non obligatoires avec des valeurs par défaut.
En supposant qu'il y ait un script appelé "MyScript.ps1" dans le chemin temporaire qui a le bloc de paramètres suivant:
[CmdletBinding(PositionalBinding = $False)]
param
(
[Parameter(Mandatory = $True)] [String] $MyNamedParameter1,
[Parameter(Mandatory = $True)] [String] $MyNamedParameter2,
[Parameter(Mandatory = $False)] [String] $MyNamedParameter3 = "some default value"
)
Voici comment j'appellerais ce script à partir d'un autre 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
Je l'ai utilisé dans de nombreux scénarios et cela fonctionne vraiment bien. Une chose que vous devez parfois faire est de mettre des guillemets autour du bloc d’affectation de valeur de paramètre. C'est toujours le cas lorsqu'il y a des espaces dans la valeur.
par exemple. Ce bloc param est utilisé pour appeler un script qui copie divers modules dans l'emplacement standard utilisé par PowerShell C:\Program Files\WindowsPowerShell\Modules
qui contient un espace.
$params = @{
SourcePath = "$WorkingDirectory\Modules"
DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
}
J'espère que cela t'aides!