Rufen Sie das PowerShell-Skript PS1 von einem anderen PS1-Skript in Powershell ISE aus auf

137

Ich möchte die Aufrufausführung für ein myScript1.ps1-Skript in einem zweiten myScript2.ps1-Skript in Powershell ISE.

Der folgende Code in MyScript2.ps1 funktioniert in der Powershell-Verwaltung einwandfrei, in PowerShell ISE jedoch nicht:

#Call myScript1 from myScript2
invoke-expression -Command .\myScript1.ps1

Beim Ausführen von MyScript2.ps1 über PowerShell ISE wird der folgende Fehler angezeigt:

Der Begriff '. \ MyScript1.ps1' wird nicht als Name eines Cmdlets, einer Funktion, einer Skriptdatei oder eines ausführbaren Programms erkannt. Überprüfen Sie die Schreibweise des Namens. Wenn ein Pfad enthalten war, überprüfen Sie, ob der Pfad korrekt ist, und versuchen Sie es erneut.

Nicola Celiento
quelle

Antworten:

83

Um den Speicherort eines Skripts zu ermitteln, verwenden Sie Split-Path $MyInvocation.MyCommand.Path(stellen Sie sicher, dass Sie dies im Skriptkontext verwenden).

Der Grund, warum Sie das verwenden sollten und nichts anderes, kann mit diesem Beispielskript veranschaulicht werden.

## ScriptTest.ps1
Write-Host "InvocationName:" $MyInvocation.InvocationName
Write-Host "Path:" $MyInvocation.MyCommand.Path

Hier sind einige Ergebnisse.

PS C: \ Users \ JasonAr>. \ ScriptTest.ps1
InvocationName :. \ ScriptTest.ps1
Pfad: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Users \ JasonAr>. . \ ScriptTest.ps1
InvocationName :.
Pfad: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Users \ JasonAr> & ". \ ScriptTest.ps1"
InvocationName: &
Pfad: C: \ Users \ JasonAr \ ScriptTest.ps1

In PowerShell 3.0 und höher können Sie die automatische Variable verwenden $PSScriptRoot:

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C: \ Users \ jarcher>. \ ScriptTest.ps1
Skript: C: \ Users \ jarcher \ ScriptTest.ps1
Pfad: C: \ Users \ jarcher
JasonMArcher
quelle
Ein später Zusatz: Wenn Sie sich Sorgen über Varianz machen (oder eigentlich nur "soliden" Code wollen), möchten Sie wahrscheinlich "Write-Output" anstelle von "Write-Host" verwenden.
KlaymenDK
20
Es wäre gut, ein Beispiel für die Verwendung von Split-Path in der Antwort zu sehen. Sie müssen auch zeigen, wie ein Skript wirklich in einem anderen Skript aufgerufen wird.
Jeremy
37

Der aktuelle Pfad von MyScript1.ps1 ist nicht der gleiche wie der von myScript2.ps1. Sie können den Ordnerpfad von MyScript2.ps1 abrufen, mit MyScript1.ps1 verknüpfen und dann ausführen. Beide Skripte müssen sich am selben Speicherort befinden.

## MyScript2.ps1 ##
$ScriptPath = Split-Path $MyInvocation.InvocationName
& "$ScriptPath\MyScript1.ps1"
Shay Levy
quelle
Wie muss ich die Variable $ MyInvocation initialisieren?
Nicola Celiento
Sie tun es nicht, es ist eine automatische Variable.
Shay Levy
Es funktioniert, aber vor der tatsächlichen Ausführung des aufgerufenen Skripts wird der folgende Fehler angezeigt: Split-Path: Das Argument kann nicht an den Parameter 'Path' gebunden werden, da es sich um eine leere Zeichenfolge handelt. In Zeile: 4 Zeichen: 25 + $ ScriptPath = Split-Path <<<< $ MyInvocation.InvocationName + CategoryInfo: invalidData: (:) [Split-Path], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed, Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento
Erstellen Sie ein neues Skript, setzen Sie: $ MyInvocation.InvocationName ein und führen Sie das Skript aus. Erhalten Sie den Pfad des Skripts?
Shay Levy
@ JasonMArcher - Warum stattdessen? Soweit ich weiß geben beide die gleiche Ausgabe?
Manojlds
35

Ich rufe myScript1.ps1 von myScript2.ps1 aus auf.

Angenommen, beide Skripte befinden sich am selben Speicherort, ermitteln Sie zuerst den Speicherort des Skripts mit diesem Befehl:

$PSScriptRoot

Fügen Sie dann den Skriptnamen, den Sie aufrufen möchten, wie folgt hinzu:

& "$PSScriptRoot\myScript1.ps1"

Das sollte funktionieren.

Srijani Ghosh
quelle
3
& "$PSScriptRoot\myScript1.ps1"ist genug
Weihui Guo
19

Einzeilige Lösung:

& ((Split-Path $MyInvocation.InvocationName) + "\MyScript1.ps1")
Noelicus
quelle
Das ist schön, aber warum nicht einfach, & '.\MyScript1.ps'wenn sich das Skript im selben Verzeichnis befindet?
JoePC
3
Das verwendet das aktuelle Verzeichnis, nicht das Skriptverzeichnis. Sicher, sie sind oft gleich ... aber nicht immer!
Noelicus
9

Dies sind nur zusätzliche Informationen zu Antworten, um Argumente in eine andere Datei zu übergeben

Wo Sie Argumente erwarten

PrintName.ps1

Param(
    [Parameter( Mandatory = $true)]
    $printName = "Joe"    
)


Write-Host $printName

So rufen Sie die Datei auf

Param(
    [Parameter( Mandatory = $false)]
    $name = "Joe"    
)


& ((Split-Path $MyInvocation.InvocationName) + "\PrintName.ps1") -printName $name

Wenn Sie keine Eingabe machen, wird standardmäßig "Joe" verwendet. Dies wird als Argument an das Argument "printName" in der Datei " PrintName.ps1" übergeben , wodurch wiederum die Zeichenfolge "Joe" ausgedruckt wird

cpoDesign
quelle
4

Sie haben vielleicht schon die Antwort darauf gefunden, aber hier ist, was ich tue.

Normalerweise setze ich diese Zeile am Anfang meiner Installationsskripte:

if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } #In case if $PSScriptRoot is empty (version of powershell V.2).  

Dann kann ich die Variable $ PSScriptRoot als Speicherort des aktuellen Skripts (Pfads) verwenden, wie im folgenden Beispiel:

if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } #In case if $PSScriptRoot is empty (version of powershell V.2).  

Try {
If (Test-Path 'C:\Program Files (x86)') {
    $ChromeInstallArgs= "/i", "$PSScriptRoot\googlechromestandaloneenterprise64_v.57.0.2987.110.msi", "/q", "/norestart", "/L*v `"C:\Windows\Logs\Google_Chrome_57.0.2987.110_Install_x64.log`""
    Start-Process -FilePath msiexec -ArgumentList $ChromeInstallArgs -Wait -ErrorAction Stop
    $Result= [System.Environment]::ExitCode
} Else {
    $ChromeInstallArgs= "/i", "$PSScriptRoot\googlechromestandaloneenterprise_v.57.0.2987.110.msi", "/q", "/norestart", "/L*v `"C:\Windows\Logs\Google_Chrome_57.0.2987.110_Install_x86.log`""
    Start-Process -FilePath msiexec -ArgumentList $ChromeInstallArgs -Wait -ErrorAction Stop
    $Result= [System.Environment]::ExitCode
    }

} ### End Try block


Catch  {
    $Result = [System.Environment]::Exitcode
    [System.Environment]::Exit($Result)
   }
[System.Environment]::Exit($Result)

In Ihrem Fall können Sie ersetzen

Start-Prozess ... Linie mit

Aufrufausdruck $ PSScriptRoot \ ScriptName.ps1

Weitere Informationen zu den automatischen Variablen $ MYINVOCATION und $ PSScriptRoot finden Sie auf der Microsoft-Website: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables

Emil Bogopolskiy
quelle
4

Um eine Skriptdatei einfach im selben Ordner (oder Unterordner von) wie der Aufrufer auszuführen, können Sie Folgendes verwenden:

# Get full path to the script:
$ScriptRoute = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, "Scriptname.ps1"))

# Execute script at location:
&"$ScriptRoute"
Rrr
quelle
3

Ich hatte ein Problem damit. Ich habe aber keine cleveren $MyInvocationSachen benutzt, um das Problem zu beheben. Wenn Sie die ISE öffnen, indem Sie mit der rechten Maustaste auf eine Skriptdatei klicken und editdann das zweite Skript innerhalb der ISE öffnen, können Sie eines unter Verwendung der normalen . \ Script.ps1- Syntax voneinander aufrufen . Ich vermute, dass die ISE den Begriff eines aktuellen Ordners hat und beim Öffnen auf diese Weise den aktuellen Ordner auf den Ordner setzt, der die Skripte enthält. Wenn ich bei normaler Verwendung ein Skript von einem anderen aufrufe , verwende ich einfach . \ Script.ps1 , IMO. Es ist falsch, das Skript zu ändern, damit es in der ISE ordnungsgemäß funktioniert.

Sabroni
quelle
2

Ich hatte ein ähnliches Problem und löste es auf diese Weise.

Mein Arbeitsverzeichnis ist ein allgemeiner Skriptordner und mehrere bestimmte Skriptordner im selben Stammverzeichnis. Ich muss einen bestimmten Skriptordner aufrufen (der das allgemeine Skript mit dem Parameter des jeweiligen Problems aufruft). Das Arbeitsverzeichnis ist also so

\Nico\Scripts\Script1.ps1
             \Script2.ps1
      \Problem1\Solution1.ps1
               \ParameterForSolution1.config
      \Problem2\Solution2.ps1
               \ParameterForSolution2.config

Solutions1 und Solutions2 rufen die PS1 im Ordner Scripts auf und laden den in ParameterForSolution gespeicherten Parameter. In Powershell ISE führe ich diesen Befehl aus

.\Nico\Problem1\Solution1.PS1

Und der Code in Solution1.PS1 lautet:

# This is the path where my script is running
$path = split-path -parent $MyInvocation.MyCommand.Definition

# Change to root dir
cd "$path\..\.."

$script = ".\Script\Script1.PS1"

$parametro = "Problem1\ParameterForSolution1.config"
# Another set of parameter Script1.PS1 can receive for debuggin porpuose
$parametro +=' -verbose'

Invoke-Expression "$script $parametro"
Nico Osorio
quelle
2

Ich reiche mein Beispiel zur Prüfung ein. So rufe ich in den von mir erstellten Tools Code aus einem Controller-Skript auf. Die Skripte, die die Arbeit erledigen, müssen auch Parameter akzeptieren, daher zeigt dieses Beispiel, wie sie übergeben werden. Es wird davon ausgegangen, dass sich das aufgerufene Skript im selben Verzeichnis befindet wie das Controller-Skript (Skript, das den Aufruf ausführt).

[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]
$Computername,

[Parameter(Mandatory = $true)]
[DateTime]
$StartTime,

[Parameter(Mandatory = $true)]
[DateTime]
$EndTime
)

$ZAEventLogDataSplat = @{
    "Computername" = $Computername
    "StartTime"    = $StartTime
    "EndTime"      = $EndTime
}

& "$PSScriptRoot\Get-ZAEventLogData.ps1" @ZAEventLogDataSplat

Das obige ist ein Controller-Skript, das 3 Parameter akzeptiert. Diese werden im Parameterblock definiert. Das Controller-Skript ruft dann das Skript Get-ZAEventLogData.ps1 auf. Zum Beispiel akzeptiert dieses Skript auch die gleichen 3 Parameter. Wenn das Controller-Skript das Skript aufruft, das die Arbeit erledigt, muss es es aufrufen und die Parameter übergeben. Das Obige zeigt, wie ich es durch Splattern mache.

Zack A.
quelle
1

Wie führen Sie integrierte PowerShell-Skripts in Ihren Skripten aus?

Wie benutzt man eingebaute Skripte wie

Get-Location
pwd
ls
dir
split-path
::etc...

Diese werden von Ihrem Computer ausgeführt und überprüfen automatisch den Pfad des Skripts.

Ebenso kann ich meine benutzerdefinierten Skripte ausführen, indem ich einfach den Namen des Skripts in den Skriptblock schreibe

::sid.ps1 is a PS script I made to find the SID of any user
::it takes one argument, that argument would be the username
echo $(sid.ps1 jowers)


(returns something like)> S-X-X-XXXXXXXX-XXXXXXXXXX-XXX-XXXX


$(sid.ps1 jowers).Replace("S","X")

(returns same as above but with X instead of S)

Gehen Sie zur Powershell-Befehlszeile und geben Sie ein

> $profile

Dadurch wird der Pfad zu einer Datei zurückgegeben, die unsere PowerShell-Befehlszeile bei jedem Öffnen der App ausführt.

Es wird so aussehen

C:\Users\jowers\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1

Gehen Sie zu Dokumente und prüfen Sie, ob Sie bereits ein WindowsPowerShell-Verzeichnis haben. Ich habe es nicht getan

> cd \Users\jowers\Documents
> mkdir WindowsPowerShell
> cd WindowsPowerShell
> type file > Microsoft.PowerShellISE_profile.ps1

Wir haben jetzt das Skript erstellt, das jedes Mal gestartet wird, wenn wir die PowerShell-App öffnen.

Der Grund dafür war, dass wir unseren eigenen Ordner hinzufügen konnten, der alle unsere benutzerdefinierten Skripte enthält. Lassen Sie uns diesen Ordner erstellen und ich werde ihn "Bin" nach den Verzeichnissen nennen, in denen Mac / Linux seine Skripte aufbewahrt.

> mkdir \Users\jowers\Bin

Jetzt möchten wir, dass dieses Verzeichnis bei $env:pathjedem Öffnen der App zu unserer Variablen hinzugefügt wird. Gehen Sie also zurück zum WindowsPowerShellVerzeichnis und

> start Microsoft.PowerShellISE_profile.ps1

Dann füge dies hinzu

$env:path += ";\Users\jowers\Bin"

Jetzt findet die Shell Ihre Befehle automatisch, solange Sie Ihre Skripte in diesem "Bin" -Verzeichnis speichern.

Starten Sie die Powershell neu und es sollte eines der ersten Skripte sein, die ausgeführt werden.

Führen Sie dies nach dem erneuten Laden in der Befehlszeile aus, um Ihr neues Verzeichnis in Ihrer Pfadvariablen anzuzeigen:

> $env:Path

Jetzt können wir unsere Skripte einfach über die Befehlszeile oder aus einem anderen Skript heraus aufrufen:

$(customScript.ps1 arg1 arg2 ...)

Wie Sie sehen, müssen wir sie mit der .ps1Nebenstelle aufrufen, bis wir Aliase für sie erstellen. Wenn wir Lust haben wollen.

Tyler Curtis Jowers
quelle
Wow, danke dafür, hier gibt es viel. Aber es gibt bereits 9 andere Antworten hier. Wie unterscheidet sich das? Welche zusätzlichen Informationen werden bereitgestellt?
Stephen Rauch
Auf diese Weise können wir unsere benutzerdefinierten Skripte in anderen Skripten verwenden - genauso wie integrierte Skripte in unseren Skripten verwendet werden. Tun Sie dies und solange Sie Ihre Skripte in dem Verzeichnis speichern, das Sie in Ihren Pfad eingegeben haben, findet der Computer automatisch den Pfad des benutzerdefinierten Skripts, wenn Sie es in der Befehlszeile oder in einem anderen Skript verwenden
Tyler Curtis Jowers,