Come posso trovare il percorso di origine di uno script in esecuzione? [duplicare]
-
03-07-2019 - |
Domanda
Questa domanda ha già una risposta qui:
Voglio essere in grado di dire da quale percorso è stato eseguito il mio script di esecuzione.
Questo spesso non sarà $ pwd.
Ho bisogno di chiamare altri script che si trovano in una struttura di cartelle relativa al mio script e mentre potrei codificare i percorsi, è al tempo stesso sgradevole e un po 'doloroso nel collo quando provo a promuovere da " dev " per "testare" a "produzione".
Soluzione
Lo script onnipresente originariamente pubblicato da Jeffrey Snover del team di PowerShell (indicato in risposta di Skyler ) e le variazioni pubblicate da Keith Cedirc ed EBGreen, soffrono tutti un grave inconveniente: se il codice segnala ciò che ti aspetti dipende da dove lo chiami!
Il mio codice seguente risolve questo problema semplicemente facendo riferimento all'ambito script anziché padre :
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
Per illustrare il problema, ho creato un veicolo di prova che valuta l'espressione target in quattro modi diversi. (I termini tra parentesi sono le chiavi della seguente tabella dei risultati.)
- codice inline [inline]
- funzione inline, ovvero funzione nel programma principale [funzione inline]
- Funzione di origine punti, ovvero la stessa funzione spostata in un file .ps1 separato [punto sorgente]
- Funzione del modulo, ovvero la stessa funzione spostata in un file .psm1 separato [modulo]
Le ultime due colonne mostrano il risultato dell'utilizzo dell'ambito script (ovvero $ script :) o con ambito padre (con -scope 1). Un risultato di " script " significa che l'invocazione ha segnalato correttamente la posizione dello script. Il "modulo" risultato indica che l'invocazione ha segnalato la posizione del modulo contenente la funzione anziché lo script che ha chiamato la funzione; questo indica uno svantaggio di entrambe le funzioni che non è possibile inserire la funzione in un modulo.
Mettendo da parte il problema del modulo, la notevole osservazione della tabella è che l'uso dell'approccio dell'ambito genitore fallisce la maggior parte del tempo (in effetti, due volte più spesso che riesce).
Infine, ecco il veicolo di prova:
function DoubleNested()
{
"=== DOUBLE NESTED ==="
NestCall
}
function NestCall()
{
"=== NESTED ==="
"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path
"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3
}
function Get-ScriptDirectory1
{
Split-Path $script:MyInvocation.MyCommand.Path
# $Invocation = (Get-Variable MyInvocation -Scope 1).Value
# Split-Path $Invocation.MyCommand.Path
}
. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force
"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path
"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3
NestCall
DoubleNested
Contenuti di ScriptDirFinder.ps1:
function Get-ScriptDirectory2
{
Split-Path $script:MyInvocation.MyCommand.Path
# $Invocation = (Get-Variable MyInvocation -Scope 1).Value
# Split-Path $Invocation.MyCommand.Path
}
Contenuti di ScriptDirFinder.psm1:
function Get-ScriptDirectory3
{
Split-Path $script:MyInvocation.MyCommand.Path
# $Invocation = (Get-Variable MyInvocation -Scope 1).Value
# Split-Path $Invocation.MyCommand.Path
}
Non ho familiarità con ciò che è stato introdotto in PowerShell 2, ma potrebbe benissimo essere che l'ambito degli script non esistesse in PowerShell 1, quando Jeffrey Snover pubblicò il suo esempio.
Sono rimasto sorpreso quando, sebbene abbia trovato il suo esempio di codice proliferare in lungo e in largo sul web, non è riuscito immediatamente quando l'ho provato! Questo perché l'ho usato in modo diverso dall'esempio di Snover (l'ho chiamato non in cima allo script ma dall'interno di un'altra funzione (il mio "nidificato due volte" esempio).)
Aggiornamento 2011.09.12
Puoi leggere questo con altri suggerimenti e trucchi sui moduli nel mio articolo appena pubblicato su Simple-Talk.com: Ulteriori Down the Rabbit Hole: moduli PowerShell e incapsulamento .
Altri suggerimenti
Hai taggato la tua domanda per Powershell versione 1.0, tuttavia, se hai accesso a Powershell versione 3.0 sai che hai $ PSCommandPath
e $ PSScriptRoot
che rende il percorso dello script un po 'più facile. Fare riferimento alle " ALTRE FUNZIONI DI SCRIPT " sezione in questa pagina per ulteriori informazioni.
Usiamo il codice in questo modo nella maggior parte dei nostri script da diversi anni senza problemi:
#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1
Di recente ho riscontrato lo stesso problema. Il seguente articolo mi ha aiutato a risolvere il problema: http: // blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx
Se non sei interessato a come funziona, ecco tutto il codice di cui hai bisogno per l'articolo:
function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}
E poi ottieni il percorso semplicemente facendo:
$path = Get-ScriptDirectory
Penso che puoi trovare il percorso del tuo script in esecuzione usando
$MyInvocation.MyCommand.Path
Spero che sia d'aiuto!
Cédric
Questa è una di quelle stranezze (almeno secondo me) in PS. Sono sicuro che ci sia una ragione perfettamente valida, ma mi sembra ancora strano. Quindi:
Se sei in uno script ma non in una funzione, $ myInvocation.InvocationName ti darà il percorso completo incluso il nome dello script. Se sei in uno script e all'interno di una funzione, $ myInvocation.ScriptName ti darà la stessa cosa.
Grazie msorens! Questo mi ha davvero aiutato con il mio modulo personalizzato. Nel caso in cui qualcuno sia interessato a crearne uno proprio, ecco come è strutturata la mia.
MyModule (folder)
- MyModule.psd1 (help New-ModuleManifest)
- MyScriptFile.ps1 (ps1 files are easy to test)
Quindi fai riferimento a MyScriptFile.ps1 in MyModule.psd1. Facendo riferimento a .ps1 nell'array NestedModules le funzioni verranno posizionate nello stato di sessione del modulo anziché nello stato di sessione globale. ( Come scrivere un modulo manifest )
NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')
Contenuto di MyScriptFile.ps1
function Get-ScriptDirectory {
Split-Path $script:MyInvocation.MyCommand.Path
}
try {
Export-ModuleMember -Function "*-*"
}
catch{}
Il try / catch nasconde l'errore da Export-ModuleMember durante l'esecuzione di MyScriptFile.ps1
Copia la MyModule in uno dei percorsi trovati qui $env:PSModulePath
PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule
CommandType Name ModuleName
----------- ---- ----------
Function Get-ScriptDirectory MyModule