Wie kann ich die aktuelle PowerShell-Ausführungsdatei abrufen?

92

Hinweis: PowerShell 1.0
Ich möchte den aktuell ausgeführten PowerShell-Dateinamen erhalten. Das heißt, wenn ich meine Sitzung so beginne:

powershell.exe .\myfile.ps1

Ich möchte die Zeichenfolge ". \ Myfile.ps1" (oder so ähnlich) erhalten. BEARBEITEN : "myfile.ps1" ist vorzuziehen.
Irgendwelche Ideen?

Ron Klein
quelle
Vielen Dank, die aktuellen Antworten sind fast gleich, aber ich brauche nur den Dateinamen (und nicht den gesamten Pfad), daher lautet die akzeptierte Antwort @ Keith's. +1 auf beide Antworten. Jetzt weiß ich über das $ MyInvocation-Ding Bescheid :-)
Ron Klein
Wie wäre es, wenn Sie das übergeordnete Skript aus einem enthaltenen Skript abrufen?
Florin Sabau

Antworten:

65

Ich habe versucht, die verschiedenen Antworten hier zusammenzufassen, die für PowerShell 5 aktualisiert wurden:

  • Wenn Sie nur PowerShell 3 oder höher verwenden, verwenden Sie $PSCommandPath
  • Wenn Sie Kompatibilität mit älteren Versionen wünschen, fügen Sie die Unterlegscheibe ein:

    if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath; }

    Dies fügt hinzu $PSCommandPath wenn es noch nicht existiert.

    Der Shim-Code kann überall ausgeführt werden (auf oberster Ebene oder innerhalb einer Funktion), obwohl die $PSCommandPathVariable normalen Gültigkeitsregeln unterliegt (z. B. wenn Sie den Shim in eine Funktion einfügen, wird die Variable nur für diese Funktion verwendet).

Einzelheiten

Es gibt 4 verschiedene Methoden, die in verschiedenen Antworten verwendet werden. Deshalb habe ich dieses Skript geschrieben, um jedes (Plus $PSCommandPath) zu demonstrieren :

function PSCommandPath() { return $PSCommandPath; }
function ScriptName() { return $MyInvocation.ScriptName; }
function MyCommandName() { return $MyInvocation.MyCommand.Name; }
function MyCommandDefinition() { return $MyInvocation.MyCommand.Definition; # Note this is the contents of the MyCommandDefinition function  
}
function PSCommandPath() { return $MyInvocation.PSCommandPath; }

Write-Host "";
Write-Host "PSVersion: $($PSVersionTable.PSVersion)";
Write-Host "";
Write-Host "`$PSCommandPath:";
Write-Host " *   Direct: $PSCommandPath";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.ScriptName:";
Write-Host " *   Direct: $($MyInvocation.ScriptName)";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Name:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Name)";
Write-Host " * Function: $(MyCommandName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Definition:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Definition)";
Write-Host " * Function: $(MyCommandDefinition)";
Write-Host "";
Write-Host "`$MyInvocation.PSCommandPath:";
Write-Host " *   Direct: $($MyInvocation.PSCommandPath)";
Write-Host " * Function: $(PSCommandPath)";
Write-Host "";

Ausgabe:

PS C:\> .\Test\test.ps1

PSVersion: 5.1.14393.1066

$PSCommandPath:
 *   Direct: C:\Test\test.ps1
 * Function: C:\Test\test.ps1

$MyInvocation.ScriptName:
 *   Direct:
 * Function: C:\Test\test.ps1

$MyInvocation.MyCommand.Name:
 *   Direct: test.ps1
 * Function: MyCommandName

$MyInvocation.MyCommand.Definition:
 *   Direct: C:\Test\test.ps1
 * Function:  return $MyInvocation.MyCommand.Definition; # Note this is the contents of the MyCommandDefinition function


$MyInvocation.PSCommandPath:
 *   Direct:
 * Function: C:\Test\test.ps1

Anmerkungen:

  • Ausgeführt von C:\, aber das eigentliche Skript ist C:\Test\test.ps1.
  • Keine Methode teilt Ihnen den ursprünglichen Aufrufpfad mit ( .\Test\test.ps1)
  • $PSCommandPath ist der einzig zuverlässige Weg, wurde jedoch in PowerShell 3 eingeführt
  • Bei Versionen vor 3 funktioniert keine einzelne Methode sowohl innerhalb als auch außerhalb einer Funktion
Gregmac
quelle
7
Für jeden, der heute (2017) liest, sollte er DIESEN Beitrag als die richtige Antwort lesen! +1
Collin Chaffin
2
@CollinChaffin: vereinbart und jetzt (2017) wird Windows 7 am wenigsten unterstützt, sodass es keinen Grund gibt, es nicht zu verwenden, $PSCommandPathwenn Legacy (WindowsXP) nicht erforderlich ist.
Tukan
81

Obwohl die aktuelle Antwort in den meisten Fällen richtig ist, gibt es bestimmte Situationen, in denen Sie nicht die richtige Antwort erhalten. Wenn Sie in Ihrem Skript Funktionen verwenden, dann:

$MyInvocation.MyCommand.Name 

Gibt den Namen der Funktion anstelle des Namens des Skripts zurück.

function test {
    $MyInvocation.MyCommand.Name
}

Gibt Ihnen " Test ", egal wie Ihr Skript benannt ist. Der richtige Befehl zum Abrufen des Skriptnamens lautet immer

$MyInvocation.ScriptName

Dies gibt den vollständigen Pfad des Skripts zurück, das Sie ausführen. Wenn Sie nur den Skriptdateinamen benötigen, sollte Ihnen dieser Code helfen:

split-path $MyInvocation.PSCommandPath -Leaf
Lukas Kucera
quelle
6
Beachten Sie, dass auf der obersten Ebene der Skriptname mit posh v4 nicht definiert ist. Ich verwende auf der obersten Ebene $ MyInvocation.MyCommand.Definition für den vollständigen Pfad oder Namen gemäß den anderen Antworten.
AnneTheAgile
30
$MyInvocation.ScriptNameRückgabe einer leeren Zeichenfolge für mich, PS v3.0.
JohnC
4
@JohnC $MyInvocation.ScriptNamefunktioniert nur innerhalb einer Funktion. Siehe meine Antwort unten .
Gregmac
72

Wenn Sie nur den Dateinamen (nicht den vollständigen Pfad) möchten, verwenden Sie Folgendes:

$ScriptName = $MyInvocation.MyCommand.Name
Keith Hill
quelle
32

Versuche Folgendes

$path =  $MyInvocation.MyCommand.Definition 

Dadurch erhalten Sie möglicherweise nicht den tatsächlich eingegebenen Pfad, aber einen gültigen Pfad zur Datei.

JaredPar
quelle
1
@Hamish die Frage sagt speziell, wenn aus einer Datei aufgerufen.
JaredPar
Zu
Ihrer Information
Ich habe genau nach diesem Befehl gesucht. Vielen Dank, JaredPar! :)
sqlfool
Split-Path verwenden, um das Verzeichnis zu erhalten? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse
7

Wenn Sie nach dem aktuellen Verzeichnis suchen, in dem das Skript ausgeführt wird, können Sie Folgendes ausprobieren:

$fullPathIncFileName = $MyInvocation.MyCommand.Definition
$currentScriptName = $MyInvocation.MyCommand.Name
$currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "")

Write-Host $currentExecutingPath
Ryk
quelle
1
Das würde nicht richtig funktionieren C:\ilike.ps123\ke.ps1, oder?
Fridojet
@fridojet - Nicht sicher, nicht in der Nähe eines PS-Terminals, um es zu testen. Warum versuchst du es nicht und siehst es?
Ryk
Nein, nur eine rhetorische Frage ;-) - Es wäre nur logisch, weil die Replace()Methode jedes Vorkommen der Nadel (nicht nur das letzte Vorkommen) ersetzt und ich es auch getestet habe. Es ist jedoch eine gute Idee, so etwas wie Subtraktion auf Strings durchzuführen.
Fridojet
... Was ist mit String.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName))? - Es funktioniert richtig: "Ich bin Hamster".TrimEnd("ster")kehrt zurück Ich bin Hamund "Ich bin Hamsterchen".TrimEnd("ster")kehrt zurück Ich bin Hamsterchen(statt Ich bin Hamchen) - Gut!
Fridojet
$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
YP
7

Achtung: Im Gegensatz zu den $PSScriptRootund $PSCommandPathautomatischen Variablen enthalten die PSScriptRootund PSCommandPath-Eigenschaften der $MyInvocationautomatischen Variablen Informationen zum Aufrufer oder zum aufrufenden Skript, nicht zum aktuellen Skript.

z.B

PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ...
=!C:\Users\S_ms\OneDrive\Documents\DPM.ps1

... wo DPM.ps1enthält

Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath)
MWR
quelle
4

Ich würde argumentieren, dass es eine bessere Methode gibt, indem der Bereich der Variablen $ MyInvocation.MyCommand.Path festgelegt wird:

ex> $ script : MyInvocation.MyCommand.Name

Diese Methode funktioniert unter allen Umständen des Aufrufs:

EX: Somescript.ps1

function printme () {
    "In function:"
    ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
    ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
    ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
}
"Main:"
( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
" "
printme
exit

AUSGABE:

PS> powershell C:\temp\test.ps1
Main:
MyInvocation.ScriptName:
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: test.ps1

In function:
MyInvocation.ScriptName: C:\temp\test.ps1
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: printme

Beachten Sie, dass die oben akzeptierte Antwort beim Aufruf von Main KEINEN Wert zurückgibt. Beachten Sie außerdem, dass die oben akzeptierte Antwort den vollständigen Pfad zurückgibt, wenn die Frage nur den Skriptnamen anfordert. Die Gültigkeitsbereichsvariable funktioniert an allen Stellen.

Wenn Sie den vollständigen Pfad möchten, rufen Sie einfach an:

$script:MyInvocation.MyCommand.Path
Daddio
quelle
3

Wie in früheren Antworten erwähnt, unterliegt die Verwendung von "$ MyInvocation" Umfangsproblemen und liefert nicht unbedingt konsistente Daten (Rückgabewert vs. direkter Zugriffswert). Ich habe festgestellt, dass die "sauberste" (konsistenteste) Methode zum Abrufen von Skriptinformationen wie Skriptpfad, Name, Parameter, Befehlszeile usw. unabhängig vom Umfang (in Haupt- oder nachfolgenden / verschachtelten Funktionsaufrufen) die Verwendung von "Get-" ist. Variable "on" MyInvocation "...

# Get the MyInvocation variable at script level
# Can be done anywhere within a script
$ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value

# Get the full path to the script
$ScriptPath = $ScriptInvocation.MyCommand.Path

# Get the directory of the script
$ScriptDirectory = Split-Path $ScriptPath

# Get the script name
# Yes, could get via Split-Path, but this is "simpler" since this is the default return value
$ScriptName = $ScriptInvocation.MyCommand.Name

# Get the invocation path (relative to $PWD)
# @GregMac, this addresses your second point
$InvocationPath = ScriptInvocation.InvocationName

Sie können also die gleichen Informationen wie $ PSCommandPath erhalten, aber noch viel mehr. Ich bin mir nicht sicher, aber es sieht so aus, als ob "Get-Variable" erst auf PS3 verfügbar war, also nicht viel Hilfe für wirklich alte (nicht aktualisierte) Systeme.

Es gibt auch einige interessante Aspekte bei der Verwendung von "-Scope", da Sie zurückverfolgen können, um die Namen usw. der aufrufenden Funktion (en) abzurufen. 0 = aktuell, 1 = übergeordnet usw.

Hoffe das ist etwas hilfreich.

Ref, https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable

AntGut
quelle
1

Habe einige Tests mit dem folgenden Skript sowohl auf PS 2 als auch auf PS 4 durchgeführt und hatte das gleiche Ergebnis. Ich hoffe das hilft den Leuten.

$PSVersionTable.PSVersion
function PSscript {
  $PSscript = Get-Item $MyInvocation.ScriptName
  Return $PSscript
}
""
$PSscript = PSscript
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

""
$PSscript = Get-Item $MyInvocation.InvocationName
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

Ergebnisse -

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1      

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts
Mark Crashley
quelle
1

Dies kann bei den meisten Powershell-Versionen funktionieren:

(& { $MyInvocation.ScriptName; })

Dies kann für geplante Jobs funktionieren

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
unwahrscheinlich
quelle