Invoquer un second script avec des arguments d'un script
Je suis relativement nouveau sur PowerShell et j'ai un script qui lit un fichier de configuration qui se traduit par un ensemble de paires nom-valeur que je voudrais passer comme arguments à une fonction dans un second script PowerShell.
Je ne sais pas quels paramètres seront placés dans ce fichier de configuration au moment de la conception, donc au moment où j'ai besoin d'appeler ce deuxième script PowerShell, j'ai fondamentalement juste une variable qui a le chemin vers ce deuxième script, et une deuxième variable qui est un tableau d'arguments à transmettre au script identifié dans la variable path.
Ainsi, la variable contenant le chemin d'accès au second script ($scriptPath), peut avoir une valeur comme:
"c:thepathtothesecondscript.ps1"
La variable contenant les arguments ($argumentList) peut ressembler à quelque chose comme:
-ConfigFilename "doohickey.txt" -RootDirectory "c:somekindofpath" -Max 11
Comment puis-je passer de cet état de choses à l'exécution de script. ps1 avec tous les arguments de $argumentList?
J'aimerais que toutes les commandes write-host de ce deuxième script soient visible à la console à partir de laquelle ce premier script est invoqué.
J'ai essayé dot-sourcing, Invoke-Command, Invoke-Expression et Start-Job, mais je n'ai pas trouvé d'approche qui ne produise pas d'erreurs.
Par exemple, je pensais que le premier itinéraire le plus simple était d'essayer Start-Job appelé comme suit:
Start-Job -FilePath $scriptPath -ArgumentList $argumentList
...mais cela échoue avec cette erreur:
System.Management.Automation.ValidationMetadataException:
Attribute cannot be added because it would cause the variable
ConfigFilename with value -ConfigFilename to become invalid.
...dans ce cas," ConfigFilename " est le premier paramètre de la liste de paramètres définie par le second script, et mon l'invocation essaie apparemment de définir sa valeur sur "- ConfigFilename", qui est évidemment destiné à identifier le paramètre par son nom, pas à définir sa valeur.
Qu'est-ce que je manque?
Modifier:
Ok, voici une maquette du script à appeler, dans un fichier nommé invokee. ps1
Param(
[parameter(Mandatory=$true)]
[alias("rc")]
[string]
[ValidateScript( {Test-Path $_ -PathType Leaf} )]
$ConfigurationFilename,
[alias("e")]
[switch]
$Evaluate,
[array]
[Parameter(ValueFromRemainingArguments=$true)]
$remaining)
function sayHelloWorld()
{
Write-Host "Hello, everybody, the config file is <$ConfigurationFilename>."
if ($ExitOnErrors)
{
Write-Host "I should mention that I was told to evaluate things."
}
Write-Host "I currently live here: $gScriptDirectory"
Write-Host "My remaining arguments are: $remaining"
Set-Content .hello.world.txt "It worked"
}
$gScriptPath = $MyInvocation.MyCommand.Path
$gScriptDirectory = (Split-Path $gScriptPath -Parent)
sayHelloWorld
...et voici une maquette du script appelant, dans un fichier nommé invokee. ps1:
function pokeTheInvokee()
{
$scriptPath = (Join-Path -Path "." -ChildPath "invokee.ps1")
$scriptPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($scriptPath)
$configPath = (Join-Path -Path "." -ChildPath "invoker.ps1")
$configPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($configPath)
$argumentList = @()
$argumentList += ("-ConfigurationFilename", "`"$configPath`"")
$argumentList += , "-Evaluate"
Write-Host "Attempting to invoke-expression with: `"$scriptPath`" $argumentList"
Invoke-Expression "`"$scriptPath`" $argumentList"
Invoke-Expression ".invokee.ps1 -ConfigurationFilename `".invoker.ps1`" -Evaluate
Write-Host "Invokee invoked."
}
pokeTheInvokee
Lorsque je lance invoker. ps1, c'est l'erreur que je reçois actuellement lors du premier appel Invoquer-Expression:
Invoke-Expression : You must provide a value expression on
the right-hand side of the '-' operator.
Le deuxième appel fonctionne très bien, mais une différence significative est que la première version utilise des arguments dont les chemins ont des espaces, et la seconde Non. Est-ce que je malmene la présence d'Espaces Dans ces chemins?
7 réponses
Aha. Cela s'est avéré être un problème simple d'avoir des espaces dans le chemin d'accès au script.
Changer la ligne Invoke-Expression en:
Invoke-Expression "& `"$scriptPath`" $argumentList"
...a été suffisant pour obtenir ce coup d'envoi. Merci à Neolisk pour votre aide et vos commentaires!
Invoke-Expression
devrait fonctionner parfaitement, assurez-vous juste que vous l'utilisez correctement. Pour votre cas, cela devrait ressembler à ceci:
Invoke-Expression "$scriptPath $argumentList"
J'ai testé cette approche avec Get-Service et semble fonctionner comme prévu.
Beaucoup plus simple réellement:
Méthode 1:
Invoke-Expression $scriptPath $argumentList
Méthode 2:
& $scriptPath $argumentList
Méthode 3:
$scriptPath $argumentList
Si vous avez des espaces dans votre scriptPath
, n'oubliez pas de Les échapper `"$scriptPath`"
Voici une réponse couvrant la question plus générale d'appeler un autre script PS à partir D'un script PS, comme vous pouvez le faire si vous composez vos scripts de nombreux petits scripts à usage étroit.
J'ai trouvé que c'était simplement un cas d'utilisation de dot-sourcing. C'est-à-dire, vous faites juste:
# This is Script-A.ps1
. ./Script-B.ps1 -SomeObject $variableFromScriptA -SomeOtherParam 1234;
J'ai trouvé tous les Q / A très confus et compliqué et finalement atterri sur la méthode simple ci-dessus, qui est vraiment comme appeler un autre script comme si c'était une fonction dans le script original, ce qui me semble à trouver plus intuitive.
Dot-sourcing peut "importer" l'autre script dans son intégralité, en utilisant:
. ./Script-B.ps1
C'est maintenant comme si les deux fichiers étaient fusionnés.
En fin de Compte, ce qui me manquait vraiment, c'est la notion que je devrais construire un module de fonctions réutilisables.
Nous pouvons utiliser splatting pour ceci:
& $command @args
Où @args
(la variable automatique $ args ) est splattée dans un tableau de paramètres.
Sous PS, 5.1
J'ai essayé la solution acceptée d'utiliser L'applet de commande Invoke-Expression mais cela n'a pas fonctionné pour moi parce que mes arguments avaient des espaces sur eux. J'ai essayé d'analyser les arguments et d'échapper aux espaces mais je ne pouvais pas le faire fonctionner correctement et c'était vraiment un sale travail à mon avis. Donc, après quelques expériences, mon point de vue sur le problème est le suivant:
function Invoke-Script
{
param
(
[Parameter(Mandatory = $true)]
[string]
$Script,
[Parameter(Mandatory = $false)]
[object[]]
$ArgumentList
)
$ScriptBlock = [Scriptblock]::Create((Get-Content $Script -Raw))
Invoke-Command -NoNewScope -ArgumentList $ArgumentList -ScriptBlock $ScriptBlock -Verbose
}
# example usage
Invoke-Script $scriptPath $argumentList
Le seul inconvénient de cette solution est que vous devez vous assurer que votre script n'a pas un "Script" ou "ArgumentList" paramètre.
Vous pouvez l'exécuter de la même manière que la requête SQL. tout d'abord, construisez votre commande/Expression et stockez-la dans une variable et exécutez/invoke.
$command = ".\yourExternalScriptFile.ps1" + " -param1 '$paramValue'"
C'est assez avancé, Je ne pense pas qu'il ait besoin d'explications. Donc, tout est prêt à exécuter votre commande maintenant,
Invoke-Expression $command
Je recommande d'attraper l'exception ici