Qual è il modo migliore per determinare la posizione dello script PowerShell corrente?

Ogni volta che ho bisogno di fare riferimento a un modulo o uno script comune, mi piace utilizzare i percorsi relativi al file di script corrente, in questo modo, il mio script può sempre trovare altri script nella libreria.

Quindi, qual è il modo migliore e standard per determinare la directory dello script corrente? Attualmente, sto facendo:

$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition) 

So che nei moduli (.psm1) è ansible utilizzare $PSScriptRoot per ottenere queste informazioni, ma che non vengono impostate negli script regolari (cioè file .ps1).

Qual è il modo canonico per ottenere la posizione corrente del file di script di PowerShell?

PowerShell 3+

 # This is an automatic variable set to the current file's/module's directory $PSScriptRoot 

PowerShell 2

Prima di PowerShell 3, non c’era un modo migliore di interrogare la proprietà MyInvocation.MyCommand.Definition per gli script generali. Avevo la seguente riga in cima essenzialmente a ogni script PowerShell che avevo:

 $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition 

Se si sta creando un modulo V2, è ansible utilizzare una variabile automatica denominata $PSScriptRoot .

Da PS> Guida variabile_automatica

 $ PSScriptRoot
        Contiene la directory da cui viene eseguito il modulo di script.
        Questa variabile consente agli script di utilizzare il percorso del modulo per accedere ad altri
        risorse.

Per PowerShell 3.0

 $PSCommandPath Contains the full path and file name of the script that is being run. This variable is valid in all scripts. 

La funzione è quindi:

 function Get-ScriptDirectory { Split-Path -Parent $PSCommandPath } 

Forse mi manca qualcosa qui … ma se vuoi la presente directory di lavoro puoi semplicemente usare questo: (Get-Location).Path per una stringa, o Get-Location per un object.

A meno che non ti stia riferendo a qualcosa del genere, che capisco dopo aver letto di nuovo la domanda.

 function Get-Script-Directory { $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value return Split-Path $scriptInvocation.MyCommand.Path } 

Io uso la variabile automatica $ ExecutionContext, funziona da PowerShell 2 e versioni successive.

 $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\') 

$ ExecutionContext Contiene un object EngineIntrinsics che rappresenta il contesto di esecuzione dell’host Windows PowerShell. È ansible utilizzare questa variabile per trovare gli oggetti di esecuzione disponibili per i cmdlet.

Avevo bisogno di conoscere il nome dello script e da dove viene eseguito.

Il prefisso “$ global:” alla struttura MyInvocation restituisce il percorso completo e il nome dello script quando viene chiamato sia dallo script principale che dalla riga principale di un file di libreria .PSM1 importato. Funziona anche da una funzione in una libreria importata.

Dopo molte discussioni, ho deciso di utilizzare $ global: MyInvocation.InvocationName. Funziona in modo affidabile con il lancio di CMD, Run With PowerShell e ISE. Entrambi i lanci locali e UNC restituiscono il percorso corretto.

Mi ci è voluto un po ‘per sviluppare qualcosa che prendesse la risposta accettata e la trasformasse in una funzione solida.

Non sono sicuro degli altri, ma lavoro in un ambiente con macchine sia su PowerShell versione 2 e 3, quindi ho dovuto gestirli entrambi. La seguente funzione offre un comodo ritorno:

 Function Get-PSScriptRoot { $ScriptRoot = "" Try { $ScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop } Catch { $ScriptRoot = Split-Path $script:MyInvocation.MyCommand.Path } Write-Output $ScriptRoot } 

Significa anche che la funzione fa riferimento all’ambito Script piuttosto che all’ambito del genitore come delineato da Michael Sorens nel suo blog

Molto simile alle risposte già pubblicate, ma le piping sembrano più simili a PS.

 $PSCommandPath | Split-Path -Parent 

Per Powershell 3+

 function Get-ScriptDirectory { if ($psise) {Split-Path $psise.CurrentFile.FullPath} else {$global:PSScriptRoot} } 

Ho inserito questa funzione nel mio profilo. Funziona anche in ISE usando F8 / Esegui selezione.

Potresti anche considerare split-path -parent $psISE.CurrentFile.Fullpath se uno degli altri metodi fallisce. In particolare, se si esegue un file per caricare un gruppo di funzioni e quindi si eseguono tali funzioni con-nella shell ISE (o se si esegue l’esecuzione), sembra che la funzione Get-Script-Directory come sopra non funzioni.

 function func1() { $inv = (Get-Variable MyInvocation -Scope 1).Value #$inv.MyCommand | Format-List * $Path1 = Split-Path $inv.scriptname Write-Host $Path1 } function Main() { func1 } Main