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".

È stato utile?

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.)

  1. codice inline [inline]
  2. funzione inline, ovvero funzione nel programma principale [funzione inline]
  3. Funzione di origine punti, ovvero la stessa funzione spostata in un file .ps1 separato [punto sorgente]
  4. 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).

tabella delle combinazioni di input

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  
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top