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?

46
demandé sur wonea 2012-10-12 04:12:35

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!

41
répondu Hoobajoob 2012-10-12 03:25:56

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.

38
répondu Neolisk 2012-10-12 01:04:07

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`"

24
répondu Mrchief 2014-01-23 03:42:03

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.

7
répondu Luke Puplett 2015-11-26 15:32:50

Nous pouvons utiliser splatting pour ceci:

& $command @args

@args (la variable automatique $ args ) est splattée dans un tableau de paramètres.

Sous PS, 5.1

5
répondu Artyom 2017-08-19 14:06:52

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.

2
répondu gigi 2016-11-21 11:17:40

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

0
répondu UniCoder 2017-08-03 10:19:34