Comment passer des paramètres nommés avec Invoke-Command?

j'ai un script que je peux exécuter à distance via Invoke-Command

Invoke-Command -ComputerName (Get-Content C:ScriptsServers.txt) `
               -FilePath C:ScriptsArchiveEventLogsver5ArchiveEventLogs.ps1

tant que j'utilise les paramètres par défaut, ça marche très bien. Cependant, le script a 2 paramètres nommés [switch] (- Debug et-Clear)

Comment passer les paramètres commutés via la commande Invoke-Command? J'ai essayé la-ArgumentList mais j'ai des erreurs donc je dois avoir la mauvaise syntaxe ou quelque chose. Toute aide est grandement appréciée.

66
demandé sur SteveC 2010-11-19 17:08:31

4 réponses

-ArgumentList est basé sur une utilisation avec scriptlock commandes, 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 encore les paramètres comme un stupide tableau éclaboussé. J'ai soumis une demande de fonctionnalité pour que cela soit ajouté à la commande (veuillez voter 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 implicite parce que lorsque j'utilise l'attribut Parameter , le script obtient CmdletBinding implicitement, 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 à la signification de $Clear ... si vous souhaitez invoquer que vous pouvez utiliser l'un des 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-là, je duplique tout les paramètres que je me soucie dans le scriptlock donc je peux passer des valeurs. Si je peux les coder en dur (ce qui est ce que j'ai fait), il n'y a pas besoin de le faire et utiliser PSBoundParameters , je peux juste passer ceux que j'ai besoin de. Dans le deuxième exemple ci-dessous, je vais passer le $Clear, juste pour montrer comment passer les 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)

l'autre option

si le script est sur votre machine locale, et vous ne vous voulez modifier les paramètres pour être positionnel, ou vous voulez spécifier des paramètres qui sont des paramètres communs (de sorte que vous ne pouvez pas les contrôler) vous voulez 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

post-scriptum:

si vous avez vraiment besoin de passer dans une variable pour le nom du script, ce que vous feriez dépendra de si la variable est définie localement ou à distance. En général, si vous avoir 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

Si c'est une variable d'environnement qui est déjà défini sur l'ordinateur distant, c'est tout là est à lui. Si c'est une variable locale , alors vous devrez la Passer 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)
83
répondu Jaykul 2015-09-23 14:13:57

ma solution à cela a été d'écrire le bloc de script dynamiquement 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, en essayant diverses méthodes, par exemple,

-arguments , $using:p1 , etc. et cela a fonctionné comme souhaité sans aucun problème.

puisque je contrôle le contenu et l'expansion variable de la chaîne qui crée le [scriptblock] (ou fichier script) de cette façon, il n'y a pas de problème réel avec l'incantation "invoke-command".

(ça ne devrait pas être si dur. :))

2
répondu HerbM 2016-08-28 20:56:32

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 à celles ci-dessus, mais obtient le contenu du fichier de script que vous souhaitez appeler et envoie un bloc de paramètres contenant les paramètres et les valeurs.

l'Un des avantages de ceci est que vous pouvez éventuellement choisir les paramètres à envoyer au script fichier permettant 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"
)

C'est comme ça que 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

j'ai utilisé ceci dans beaucoup de scénarios et cela fonctionne vraiment bien. Une chose que vous avez parfois besoin de faire est de mettre des guillemets autour de l'assignation de valeur du paramètre bloc. C'est toujours le cas quand il y a des espaces dans la valeur.

p.ex. 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 caractère d'espace.

$params = @{
        SourcePath      = "$WorkingDirectory\Modules"
        DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
    }

Espérons que cette aide!

2
répondu CarlR 2016-10-27 14:19:31

j'imagine que c'est une nouvelle fonctionnalité puisque ce post a été créé - passer les paramètres au bloc script en utilisant $Using:var. Puis c'est un simple mater pour passer les paramètres à condition que le script soit déjà sur la machine ou dans un emplacement réseau connu par rapport à la machine

en prenant l'exemple principal, il serait:

icm -cn $Env:ComputerName { 
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
1
répondu RobG 2017-04-20 09:02:16