it-swarm.com.de

Rufen Sie ein zweites Skript mit Argumenten aus einem Skript auf

Ich bin relativ neu bei PowerShell und habe ein Skript, das eine Konfigurationsdatei liest, die zu einer Gruppe von Namen-Wert-Paaren führt, die ich als Argumente an eine Funktion in einem zweiten PowerShell-Skript übergeben möchte.

Ich weiß nicht, welche Parameter zur Entwurfszeit in diese Konfigurationsdatei eingefügt werden, also genau an dem Punkt, an dem ich dieses zweite PowerShell-Skript aufrufen muss, habe ich im Grunde nur eine Variable, die den Pfad zu diesem zweiten Skript hat, und eine zweite Variable, bei der es sich um ein Array von Argumenten handelt, die an das in der Pfadvariable angegebene Skript übergeben werden.

Die Variable, die den Pfad zum zweiten Skript ($ scriptPath) enthält, kann einen Wert wie folgt haben:

"c:\the\path\to\the\second\script.ps1"

Die Variable, die die Argumente ($ argumentList) enthält, könnte wie folgt aussehen:

-ConfigFilename "doohickey.txt" -RootDirectory "c:\some\kind\of\path" -Max 11

Wie komme ich von diesem Zustand zur Ausführung von script.ps1 mit allen Argumenten aus $ argumentList?

Ich möchte, dass alle Write-Host-Befehle aus diesem zweiten Skript für die Konsole sichtbar sind, von der aus dieses erste Skript aufgerufen wird.

Ich habe Dot-Sourcing, Invoke-Command, Invoke-Expression und Start-Job ausprobiert, aber ich habe keinen Ansatz gefunden, der keine Fehler erzeugt.

Zum Beispiel dachte ich, der einfachste erste Weg wäre, Start-Job wie folgt zu versuchen:

Start-Job -FilePath $scriptPath -ArgumentList $argumentList

... aber das schlägt mit diesem Fehler fehl:

System.Management.Automation.ValidationMetadataException:
Attribute cannot be added because it would cause the variable
ConfigFilename with value -ConfigFilename to become invalid.

... In diesem Fall ist "ConfigFilename" der erste Parameter in der durch das zweite Skript definierten param-Liste, und mein Aufruf versucht offenbar, den Wert auf "-ConfigFilename" zu setzen, der den Parameter offensichtlich anhand des Namens identifizieren soll , nicht seinen Wert einstellen.

Was vermisse ich?

BEARBEITEN:

Ok, hier ist ein Modell des anzurufenden Skripts in einer Datei namens 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

... und hier ist ein Modell des aufrufenden Skripts in einer Datei namens 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

Beim Ausführen von invoker.ps1 ist dies der Fehler, den ich derzeit beim ersten Aufruf von Invoke-Expression erhalte:

Invoke-Expression : You must provide a value expression on
the right-hand side of the '-' operator.

Der zweite Aufruf funktioniert gut, aber ein wesentlicher Unterschied besteht darin, dass die erste Version Argumente verwendet, deren Pfade Leerzeichen enthalten, und die zweite nicht. Misshandle ich die Präsenz von Räumen auf diesen Wegen?

50
Hoobajoob

Aha. Dies stellte sich als einfaches Problem heraus, da der Pfad zum Skript Leerzeichen enthält.

Ändern der Invoke-Expression-Zeile in:

Invoke-Expression "& `"$scriptPath`" $argumentList"

... war genug, um loszulegen. Danke an Neolisk für Ihre Hilfe und Ihr Feedback!

45
Hoobajoob

Invoke-Expression sollte einwandfrei funktionieren, stellen Sie nur sicher, dass Sie es richtig verwenden. Für Ihren Fall sollte es so aussehen:

Invoke-Expression "$scriptPath $argumentList"

Ich habe diesen Ansatz mit Get-Service getestet und scheint wie erwartet zu funktionieren.

41
Neolisk

Viel einfacher eigentlich:

Methode 1:

Invoke-Expression $scriptPath $argumentList

Methode 2: 

& $scriptPath $argumentList

Methode 3:

$scriptPath $argumentList

Wenn Sie Leerzeichen in Ihrer scriptPath haben, vergessen Sie nicht, sie zu umgehen `"$scriptPath`"

26
Mrchief

Hier finden Sie eine Antwort auf die allgemeinere Frage des Aufrufs eines anderen PS-Skripts aus einem PS-Skript, wie Sie dies tun könnten, wenn Sie Ihre Skripts aus vielen kleinen, eng definierten Skripten zusammenstellen.

Ich habe festgestellt, dass es sich nur um die Verwendung von Punktbeschaffung handelte. Das heißt, Sie machen einfach:

# This is Script-A.ps1

. ./Script-B.ps1 -SomeObject $variableFromScriptA -SomeOtherParam 1234;

Ich fand alle Fragen und Antworten sehr verwirrend und kompliziert und landeten schließlich auf der oben beschriebenen einfachen Methode, die eigentlich so ist, als würde man ein anderes Skript aufrufen, als wäre es eine Funktion im Originalskript, die ich scheinbar intuitiver finde.

Dot-Sourcing kann das andere Skript vollständig importieren, indem es verwendet:

. ./Script-B.ps1

Es ist jetzt so, als würden die beiden Dateien zusammengeführt.

Letztendlich fehlte mir wirklich die Vorstellung, dass ich ein Modul aus wiederverwendbaren Funktionen erstellen sollte.

8
Luke Puplett

Wir können splatting dafür verwenden:

& $command @args

dabei ist @args ( automatische Variable $ args ) in ein Array von Parametern aufgeteilt. 

Unter PS, 5.1

5
Artyom

Ich habe die akzeptierte Lösung der Verwendung des Cmdlets "Invoke-Expression" ausprobiert. Dies funktionierte jedoch nicht für mich, da meine Argumente Leerzeichen enthielten. Ich habe versucht, die Argumente zu analysieren und den Leerzeichen zu entkommen, aber ich konnte es nicht richtig machen, und es war meiner Meinung nach wirklich eine schmutzige Arbeit.

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

Der einzige Nachteil dieser Lösung besteht darin, dass Sie sicherstellen müssen, dass Ihr Skript keinen Parameter "Skript" oder "ArgumentList" hat.

2
gigi

Sie können es genauso wie SQL-Abfrage ausführen Zuerst müssen Sie Ihren Befehl/Ausdruck erstellen und in einer Variablen speichern und ausführen/aufrufen.

$command =  ".\yourExternalScriptFile.ps1" + " -param1 '$paramValue'"

Es ist ziemlich vorwärts, ich glaube nicht, dass es Erklärungen braucht ... So alles bereit, Ihren Befehl jetzt auszuführen,

Invoke-Expression $command

Ich würde die Ausnahme hier empfehlen

0
UniCoder