Come posso ottenere il file corrente di esecuzione di PowerShell?


92

Nota: PowerShell 1.0
vorrei ottenere il nome del file di PowerShell in esecuzione corrente. Cioè, se inizio la mia sessione in questo modo:

powershell.exe .\myfile.ps1

Vorrei ottenere la stringa ". \ Myfile.ps1" (o qualcosa di simile). EDIT : "myfile.ps1" è preferibile.
Qualche idea?


Grazie, le risposte attuali sono quasi le stesse, ma mi serve solo il nome del file (e non l'intero percorso), quindi la risposta accettata è @ Keith. +1 a entrambe le risposte, però. Ora so della cosa $ MyInvocation :-)
Ron Klein,

Che ne dici di ottenere lo script genitore da uno script incluso?
Florin Sabau

Risposte:


67

Ho provato a riassumere le varie risposte qui, aggiornate per PowerShell 5:

  • Se stai usando solo PowerShell 3 o versioni successive, usa $PSCommandPath

  • Se vuoi la compatibilità con le versioni precedenti, inserisci lo shim:

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

    Questo aggiunge $PSCommandPathse non esiste già.

    Il codice shim può essere eseguito ovunque (di primo livello o all'interno di una funzione), sebbene la $PSCommandPathvariabile sia soggetta alle normali regole di scoping (ad esempio, se si inserisce lo shim in una funzione, la variabile è limitata a quella funzione).

Dettagli

Esistono 4 diversi metodi utilizzati in varie risposte, quindi ho scritto questo script per dimostrare ciascuno (più $PSCommandPath):

function PSCommandPath() { return $PSCommandPath; }
function ScriptName() { return $MyInvocation.ScriptName; }
function MyCommandName() { return $MyInvocation.MyCommand.Name; }
function MyCommandDefinition() {
    # Begin of MyCommandDefinition()
    # Note: ouput of this script shows the contents of this function, not the execution result
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()
}
function MyInvocationPSCommandPath() { 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: $(MyInvocationPSCommandPath)";
Write-Host "";

Produzione:

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

PSVersion: 5.1.19035.1

$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:
    # Begin of MyCommandDefinition()
    # Note this is the contents of the MyCommandDefinition() function, not the execution results
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()


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

Appunti:

  • Eseguito da C:\, ma lo script effettivo lo è C:\Test\test.ps1.
  • Nessun metodo ti dice il percorso di invocazione passato ( .\Test\test.ps1)
  • $PSCommandPath è l'unico modo affidabile, ma è stato introdotto in PowerShell 3
  • Per le versioni precedenti alla 3, nessun metodo singolo funziona sia all'interno che all'esterno di una funzione

7
Chiunque legga oggi (2017), dovrebbe leggere QUESTO post come risposta corretta! +1
Collin Chaffin

2
@CollinChaffin: d'accordo e ora (2017) il meno attualmente supportato è Windows 7, quindi non c'è motivo di non usarlo $PSCommandPathse legacy (WindowsXP) non è richiesto.
tukan

Il primo esempio di codice è difettoso in quanto contiene due definizioni della stessa funzione ( function PSCommandPath) e un riferimento alla funzione sbagliata ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)";- o sto trascurando qualcosa di ovvio?
Mike L'Angelo

@ MikeL'Angelo Hai ragione! Sono passato inosservato per 3 anni. Risolto, grazie. Tuttavia, il risultato e la conclusione sono gli stessi.
gregmac

81

Sebbene la risposta corrente sia corretta nella maggior parte dei casi, ci sono alcune situazioni in cui non ti darà la risposta corretta. Se usi le funzioni all'interno del tuo script, allora:

$MyInvocation.MyCommand.Name 

Restituisce il nome della funzione al posto del nome dello script.

function test {
    $MyInvocation.MyCommand.Name
}

Ti darà un " test " indipendentemente dal nome dello script. Il comando giusto per ottenere il nome dello script è sempre

$MyInvocation.ScriptName

questo restituisce il percorso completo dello script che stai eseguendo. Se hai bisogno solo del nome del file dello script, questo codice dovrebbe aiutarti:

split-path $MyInvocation.PSCommandPath -Leaf

6
Nota che al livello più alto, Scriptname non è definito con posh v4. Mi piace usare al livello più alto, $ MyInvocation.MyCommand.Definition per il percorso completo o il nome come per le altre risposte.
AnneTheAgile

30
$MyInvocation.ScriptNamerestituisci una stringa vuota per me, PS v3.0.
JohnC

4
@JohnC $MyInvocation.ScriptNamefunziona solo dall'interno di una funzione. Vedi la mia risposta di seguito .
gregmac

72

Se vuoi solo il nome del file (non il percorso completo) usa questo:

$ScriptName = $MyInvocation.MyCommand.Name

32

Prova quanto segue

$path =  $MyInvocation.MyCommand.Definition 

Questo potrebbe non darti il ​​percorso effettivo digitato ma ti darà un percorso valido per il file.


1
@ Hamish la domanda dice specificamente se invocata da un file.
JaredPar

FYI: Questo ti dà il percorso completo e il nome del file (Powershell 2.0)
Ralph Willgoss

Stavo cercando esattamente questo comando. Grazie, JaredPar! :)
sqlfool

Utilizzare Split-Path per ottenere la directory? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse

7

Se stai cercando la directory corrente in cui viene eseguito lo script, puoi provare questa:

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

Write-Host $currentExecutingPath

1
Non funzionerebbe correttamente su C:\ilike.ps123\ke.ps1, vero?
fridojet

@fridojet - Non sono sicuro, non vicino a un terminale PS per testarlo. Perché non lo provi e vedi?
Ryk

No, solo una domanda retorica ;-) - Sarebbe logico perché il Replace()metodo sostituisce ogni occorrenza dell'ago (non solo l'ultima) e l'ho anche testata. Tuttavia, è una buona idea fare qualcosa come la sottrazione sulle stringhe.
fridojet

... Che mi dici di String.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName))? - Funziona correttamente: "Ich bin Hamster".TrimEnd("ster")resi Ich bin Hame "Ich bin Hamsterchen".TrimEnd("ster")resi Ich bin Hamsterchen(invece di Ich bin Hamchen) - Bene!
fridojet

$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
YP

7

attenzione: a differenza delle variabili automatiche $PSScriptRoote $PSCommandPath, le proprietà PSScriptRoote PSCommandPathdella $MyInvocationvariabile automatica contengono informazioni sull'invocatore o sullo script chiamante, non sullo script corrente.

per esempio

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

... dove DPM.ps1contiene

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

4

Direi che esiste un metodo migliore, impostando l'ambito della variabile $ MyInvocation.MyCommand.Path:

ex> $ script : MyInvocation.MyCommand.Name

Questo metodo funziona in tutte le circostanze di invocazione:

ES: 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

PRODUZIONE:

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

Si noti come la risposta accettata sopra NON restituisca un valore quando viene chiamata da Main. Inoltre, si noti che la risposta accettata sopra restituisce il percorso completo quando la domanda ha richiesto solo il nome dello script. La variabile con ambito funziona in tutti i posti.

Inoltre, se volessi il percorso completo, dovresti semplicemente chiamare:

$script:MyInvocation.MyCommand.Path

3

Come indicato nelle risposte precedenti, l'utilizzo di "$ MyInvocation" è soggetto a problemi di ambito e non fornisce necessariamente dati coerenti (valore restituito rispetto al valore di accesso diretto). Ho scoperto che il metodo "più pulito" (più coerente) per ottenere informazioni sullo script come percorso dello script, nome, parametri, riga di comando, ecc. Indipendentemente dall'ambito (nelle chiamate di funzione principale o successive / nidificate) è utilizzare "Get- Variabile "su" 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

Quindi, puoi ottenere le stesse informazioni di $ PSCommandPath, ma molto di più nell'affare. Non sono sicuro, ma sembra che "Get-Variable" non fosse disponibile fino a PS3, quindi non è stato molto utile per sistemi molto vecchi (non aggiornati).

Ci sono anche alcuni aspetti interessanti quando si usa "-Scope" in quanto è possibile tornare indietro per ottenere i nomi, ecc. Delle funzioni chiamanti. 0 = corrente, 1 = genitore, ecc.

Spero che questo sia in qualche modo utile.

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


1

Ho eseguito alcuni test con il seguente script, sia su PS 2 che su PS 4 e hanno ottenuto lo stesso risultato. Spero che questo aiuti le persone.

$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

Risultati -

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

1

Questo può funzionare sulla maggior parte delle versioni di PowerShell:

(& { $MyInvocation.ScriptName; })

Questo può funzionare per il lavoro pianificato

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.