वर्तमान PowerShell स्क्रिप्ट का स्थान निर्धारित करने का सबसे अच्छा तरीका क्या है?


530

जब भी मुझे एक सामान्य मॉड्यूल या स्क्रिप्ट का संदर्भ देने की आवश्यकता होती है, तो मुझे वर्तमान स्क्रिप्ट फ़ाइल के सापेक्ष पथ का उपयोग करना पसंद है। इस तरह, मेरी स्क्रिप्ट हमेशा लाइब्रेरी में अन्य स्क्रिप्ट पा सकती है।

तो, वर्तमान स्क्रिप्ट की निर्देशिका का निर्धारण करने का सबसे अच्छा, मानक तरीका क्या है? वर्तमान में, मैं कर रहा हूँ:

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

मुझे पता है कि मॉड्यूल (.psm1) में आप $PSScriptRootइस जानकारी को प्राप्त करने के लिए उपयोग कर सकते हैं , लेकिन यह नियमित स्क्रिप्ट (यानी .ps1) में सेट नहीं होता है।

वर्तमान PowerShell स्क्रिप्ट फ़ाइल के स्थान को प्राप्त करने के लिए विहित तरीका क्या है?


जवाबों:


865

पॉवरशेल 3+

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

पॉवरशेल 2

PowerShell 3 से पहले, MyInvocation.MyCommand.Definitionसामान्य स्क्रिप्ट के लिए संपत्ति को क्वेरी करने से बेहतर तरीका नहीं था । मेरे पास अनिवार्य रूप से प्रत्येक PowerShell स्क्रिप्ट के शीर्ष पर निम्नलिखित पंक्ति थी:

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

1
Split-Pathयहाँ के लिए क्या उपयोग किया जाता है?
CMCDragonkai

7
Split-Path-Parentवर्तमान में स्क्रिप्ट के नाम को निष्पादित किए बिना वर्तमान निर्देशिका को वापस करने के लिए पैरामीटर के साथ उपयोग किया जाता है ।
होजेलर

5
नोट: Linux / macOS पर PowerShell के साथ, आपकी स्क्रिप्ट में पॉपस्क्रिप्ट / MyInvocation आदि पॉप्युलेट होने के लिए .ps1 एक्सटेंशन होना चाहिए। बग रिपोर्ट यहां देखें: github.com/PowerShell/PowerShell/issues/4217
डेव वुड

3
संभावित रूप से एक तरफ दिलचस्प के साथ वक्रोक्ति: निकट v2- का सन्निकटन $PSScriptRoot(पर Split-Path -Parentलागू होता है) $MyInvocation.MyCommand.Path, $MyInvocation.MyCommand.Definitionहालांकि, एक स्क्रिप्ट के शीर्ष-स्तरीय दायरे में वे एक ही व्यवहार करते हैं (जो इस उद्देश्य के लिए कॉल करने के लिए एकमात्र समझदार जगह है)। जब किसी फ़ंक्शन या स्क्रिप्ट ब्लॉक के अंदर कॉल किया जाता है , तो पूर्व खाली स्ट्रिंग लौटाता है, जबकि बाद वाला फ़ंक्शन बॉडी / स्क्रिप्ट ब्लॉक की परिभाषा को स्ट्रिंग (PowerShell स्रोत कोड का एक टुकड़ा) के रूप में देता है।
mklement0

62

यदि आप V2 मॉड्यूल बना रहे हैं, तो आप नामक एक स्वचालित चर का उपयोग कर सकते हैं $PSScriptRoot

PS से> Automatic_variable मदद करें

$ PSScriptRoot
       वह निर्देशिका शामिल करता है जिसमें से स्क्रिप्ट मॉड्यूल निष्पादित किया जा रहा है।
       यह चर स्क्रिप्ट को दूसरे तक पहुंचने के लिए मॉड्यूल पथ का उपयोग करने की अनुमति देता है
       संसाधनों।

16
यह वही है जो आपको PS 3.0 में चाहिए:$PSCommandPath Contains the full path and file name of the script that is being run. This variable is valid in all scripts.
CodeMonkeyKing

2
बस $ PSScriptRoot का परीक्षण किया और उम्मीद के मुताबिक काम किया। हालाँकि, यदि आप इसे कमांड लाइन पर चलाते हैं, तो यह आपको एक खाली स्ट्रिंग देगा। यह केवल आपको परिणाम देगा यदि स्क्रिप्ट और स्क्रिप्ट में उपयोग किया जाता है। यही इसका मतलब है .....
फारुख वहीद

4
मैं उलझन में हूं। यह उत्तर V2 के लिए PSScriptRoot का उपयोग करने के लिए कहता है। एक अन्य उत्तर कहता है कि PSScriptRoot V3 + के लिए है, और v2 के लिए कुछ अलग उपयोग करने के लिए है।

5
v2 में @user $ PSScriptRoot केवल मॉड्यूल के लिए है , यदि आप 'सामान्य' स्क्रिप्ट लिख रहे हैं, तो आपको किसी मॉड्यूल में $ MyInvocation.MyCommand.Definition की आवश्यकता नहीं है, शीर्ष उत्तर देखें।
यजॉर्ग

1
@ Lofful मैंने "v2" में कहा था कि यह केवल मॉड्यूल के लिए परिभाषित किया गया था। आप कह रहे हैं कि यह v3 में बाहरी मॉड्यूल से परिभाषित है। मुझे लगता है कि हम एक ही बात कह रहे हैं। :)
yzorg

35

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.

फ़ंक्शन तब है:

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

20
और भी बेहतर, $ PSScriptRoot का उपयोग करें। यह वर्तमान फ़ाइल / मॉड्यूल की निर्देशिका है।
आरोन जेनसेन

2
इस कमांड में स्क्रिप्ट का फ़ाइल नाम शामिल है, जिसने मुझे एहसास होने तक फेंक दिया। जब आप रास्ता चाहते हैं, तो आप शायद स्क्रिप्ट का नाम भी नहीं चाहते हैं। कम से कम, मैं ऐसा कारण नहीं सोच सकता जो आप चाहते हैं। $ PSScriptRoot में फ़ाइल नाम (अन्य उत्तरों से प्राप्त) शामिल नहीं है।
येटनऑनरेमग्राउंटर

$ PSScriptRoot एक नियमित PS1 स्क्रिप्ट से खाली है। $ PSCommandPath काम करता है, हालांकि। अन्य पदों में दिए गए विवरण के अनुसार दोनों का व्यवहार अपेक्षित है। फ़ाइल नाम के बिना स्क्रिप्ट निर्देशिका प्राप्त करने के लिए बस [IO.Path] :: GetDirectoryName ($ PSCommandPath) का उपयोग कर सकते हैं।
सकी

19

PowerShell 3+ के लिए

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

मैंने इस फ़ंक्शन को अपनी प्रोफ़ाइल में रखा है। यह ISE F8/ Run Selection का भी उपयोग करता है।


16

शायद मुझे यहाँ कुछ याद आ रहा है ... लेकिन यदि आप वर्तमान कार्यशील निर्देशिका चाहते हैं तो आप इसका उपयोग कर सकते हैं: (Get-Location).Pathस्ट्रिंग के लिए, या Get-Locationकिसी वस्तु के लिए।

जब तक आप इस तरह की किसी बात का उल्लेख नहीं कर रहे हैं, जिसे मैं प्रश्न को दोबारा पढ़ने के बाद समझ रहा हूं।

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

16
यह वर्तमान स्थान प्राप्त करता है जहां उपयोगकर्ता स्क्रिप्ट चला रहा है । स्क्रिप्ट फ़ाइल का स्थान ही नहीं
एरोन जेन्सेन

2
function Get-Script-Directory { $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value return Split-Path $scriptInvocation.MyCommand.Path } $hello = "hello" Write-Host (Get-Script-Directory) Write-Host $hello इसे सहेजें और इसे किसी भिन्न निर्देशिका से चलाएँ। आप स्क्रिप्ट को रास्ता दिखाएंगे।
सीन सी।

यह एक अच्छा कार्य है, और मुझे इसकी आवश्यकता है, लेकिन मैं इसे कैसे साझा करूं और इसका उपयोग मेरी सभी लिपियों में करूं? यह एक चिकन और अंडे की समस्या है: मैं अपने वर्तमान स्थान का पता लगाने के लिए एक फ़ंक्शन का उपयोग करना चाहता हूं, लेकिन मुझे फ़ंक्शन को लोड करने के लिए मेरे स्थान की आवश्यकता है।
एरोन जेन्सेन

2
नोट: इस फ़ंक्शन का इनवोकेशन आपकी स्क्रिप्ट के शीर्ष स्तर पर होना चाहिए, अगर यह किसी अन्य फ़ंक्शन के भीतर नेस्टेड है, तो आपको कॉल स्टैक में कितना गहरा है, यह निर्दिष्ट करने के लिए "-Scope" पैरामीटर को बदलना होगा।
केनी

11

पहले से ही पोस्ट किए गए उत्तर के समान, लेकिन पाइपिंग अधिक PowerShell की तरह लगता है:

$PSCommandPath | Split-Path -Parent

11

मैं स्वचालित चर का उपयोग करता हूं $ExecutionContext। यह PowerShell 2 और बाद में से काम करेगा।

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

$ ExecutionContext में एक EngineIntrinsics ऑब्जेक्ट है जो Windows PowerShell होस्ट के निष्पादन संदर्भ का प्रतिनिधित्व करता है। आप cmdlets के लिए उपलब्ध निष्पादन ऑब्जेक्ट्स को खोजने के लिए इस चर का उपयोग कर सकते हैं।


1
यह मेरे लिए एकमात्र ऐसा काम है, जो एसटीडीआईएन से शक्तियां खिलाने की कोशिश कर रहा है।
सेबस्टियन

जब आप UNC पथ संदर्भ में होते हैं तो यह समाधान भी ठीक से काम करता है।
user2030503

1
यह स्पष्ट रूप से कामकाजी निर्देशिका को उठा रहा है - इसके बजाय जहां स्क्रिप्ट स्थित है?
मोनोजोहनी

@monojohnny हां यह मूल रूप से वर्तमान कार्यशील निर्देशिका है और किसी अन्य स्थान से स्क्रिप्ट को कॉल करते समय काम नहीं करेगा।
1919 का मंगल

9

मुझे कुछ विकसित करने में कुछ समय लगा जो स्वीकृत उत्तर को ले कर एक मजबूत कार्य में बदल गया।

मैं दूसरों के बारे में निश्चित नहीं हूं, लेकिन मैं पॉवरशेल संस्करण 2 और 3 दोनों पर मशीनों के साथ एक वातावरण में काम करता हूं, इसलिए मुझे दोनों को संभालने की जरूरत है। निम्नलिखित समारोह एक सुंदर वापसी प्रदान करता है:

Function Get-PSScriptRoot
{
    $ScriptRoot = ""

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

    Write-Output $ScriptRoot
}

इसका अर्थ यह भी है कि यह फ़ंक्शन अपने एक ब्लॉग पोस्ट में माइकल सोरेंस द्वारा उल्लिखित माता-पिता के दायरे के बजाय स्क्रिप्ट के दायरे को संदर्भित करता है ।


धन्यवाद! विंडोज पॉवरशेल ISE ​​में काम करने के लिए मुझे "$ स्क्रिप्ट:" की आवश्यकता थी।
कर्क लीमोहन

इसके लिए धन्यवाद। मेरे लिए यही एक काम था। मुझे आमतौर पर निर्देशिका में सीडी करनी होती है, स्क्रिप्ट मेरे लिए गेट-लोकेशन जैसे काम से पहले होती है। मुझे यह जानने में दिलचस्पी होगी कि PowerShell स्वचालित रूप से निर्देशिका को अपडेट क्यों नहीं करता है।
ज़ेन

7

मुझे स्क्रिप्ट का नाम पता होना चाहिए और यह कहां से क्रियान्वित हो रहा है।

MyInvocation संरचना में "$ Global:" को उपसर्ग करते हुए मुख्य स्क्रिप्ट और आयातित आयातित .PSM1 लाइब्रेरी फ़ाइल की मुख्य लाइन दोनों से पुकारने पर पूरा रास्ता और स्क्रिप्ट नाम वापस आ जाता है। यह एक आयातित पुस्तकालय में एक समारोह के भीतर से भी काम करता है।

चारों ओर बहुत फ़िदा होने के बाद, मैं $ ग्लोबल का उपयोग करने पर बस गया: MyInvocation.InvocationName। यह CMD लॉन्च, रन विद पॉवरशेल और ISE के साथ मज़बूती से काम करता है। स्थानीय और UNC दोनों लॉन्च सही रास्ते पर लौटते हैं।


4
स्प्लिट-पाथ-$ $ ($ वैश्विक: MyInvocation.MyCommand.Path) ने एकदम सही काम किया। अन्य समाधानों ने कॉलिंग एप्लिकेशन का पथ लौटा दिया।
डायनामलिनकिन

1
तुच्छ नोट: ISE में F8 / Run Selection का उपयोग करके इस फ़ंक्शन को कॉल करना एक ParameterArgumentValidationErrorNullNotAllowedअपवाद को ट्रिगर करेगा ।
वीर

5

मैं हमेशा इस छोटे स्निपेट का उपयोग करता हूं जो पावरशेल और आईएसई के लिए काम करता है :

# Set active path to script-location:
$path = $MyInvocation.MyCommand.Path
if (!$path) {
    $path = $psISE.CurrentFile.Fullpath
}
if ($path) {
    $path = Split-Path $path -Parent
}
Set-Location $path

3

मैंने पाया कि मेरे यहाँ पोस्ट किए गए पुराने समाधान PowerShell V5 पर मेरे काम नहीं आए। मैं इसके साथ आया:

try {
    $scriptPath = $PSScriptRoot
    if (!$scriptPath)
    {
        if ($psISE)
        {
            $scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
        }
        else {
            Write-Host -ForegroundColor Red "Cannot resolve script file's path"
            exit 1
        }
    }
}
catch {
    Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
    exit 2
}

Write-Host "Path: $scriptPath"

2

split-path -parent $psISE.CurrentFile.Fullpathयदि अन्य विधियों में से कोई भी विफल हो, तो आप इस पर भी विचार कर सकते हैं। विशेष रूप से, यदि आप फ़ंक्शंस का एक समूह लोड करने के लिए फ़ाइल चलाते हैं और फिर उन फ़ंक्शंस को ISE शेल के साथ निष्पादित करते हैं (या यदि आप रन-सेलेक्टेड हैं), तो ऐसा लगता है Get-Script-Directoryकि ऊपर का फ़ंक्शन काम नहीं करता है।


3
$PSCommandPathISE में तब तक काम करेगा जब तक आप पहले स्क्रिप्ट को सेव करते हैं और पूरी फाइल को निष्पादित करते हैं। अन्यथा, आप वास्तव में एक स्क्रिप्ट निष्पादित नहीं कर रहे हैं; आप केवल शेल में "चिपकाने" का आदेश दे रहे हैं।
Zenexer

@Zenexer मुझे लगता है कि उस समय मेरा लक्ष्य था। हालांकि अगर मेरा लक्ष्य मूल के साथ मेल नहीं खाता, तो यह कभी-कभार के Googlers को छोड़कर बहुत उपयोगी नहीं हो सकता है ...

2

इन सभी उत्तरों और टिप्पणियों से टुकड़ों का उपयोग करते हुए, मैंने भविष्य में इस प्रश्न को देखने वाले किसी भी व्यक्ति के लिए इसे एक साथ रखा। यह अन्य उत्तरों में सूचीबद्ध सभी स्थितियों को कवर करता है

    # If using ISE
    if ($psISE) {
        $ScriptPath = Split-Path -Parent $psISE.CurrentFile.FullPath
    # If Using PowerShell 3 or greater
    } elseif($PSVersionTable.PSVersion.Major -gt 3) {
        $ScriptPath = $PSScriptRoot
    # If using PowerShell 2 or lower
    } else {
        $ScriptPath = split-path -parent $MyInvocation.MyCommand.Path
    }

-4
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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.