現在のPowerShellスクリプトの場所を特定する最良の方法は何ですか?


530

共通のモジュールまたはスクリプトを参照する必要があるときはいつでも、現在のスクリプトファイルからの相対パスを使用します。このようにして、私のスクリプトは常にライブラリ内の他のスクリプトを見つけることができます。

では、現在のスクリプトのディレクトリを特定するための最良の標準的な方法は何でしょうか。現在、私はやっています:

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

私は$PSScriptRootこの情報を取得するために使用できるモジュール(.psm1)を知っていますが、それは通常のスクリプト(つまり.ps1ファイル)では設定されません。

現在のPowerShellスクリプトファイルの場所を取得する正規の方法は何ですか?


回答:


865

PowerShell 3以降

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

PowerShell 2

PowerShell 3以前は、MyInvocation.MyCommand.Definition一般的なスクリプトのプロパティをクエリするよりも優れた方法はありませんでした 。基本的に、私が持っていたすべてのPowerShellスクリプトの先頭に次の行がありました。

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

1
Split-Pathここでは何を使用していますか?
CMCDragonkai 2016

7
Split-Path-Parent現在実行中のスクリプトの名前なしで現在のディレクトリを返すために、パラメーターと共に使用されます。
hjoelr 16

5
注:Linux / macOS上のPowerShellでは、PSScriptRoot / MyInvocationなどを入力するために、スクリプトに.ps1拡張子が必要です。こちらのバグレポートをご覧ください:github.com/PowerShell/PowerShell/issues/4217
Dave Wood

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をテストし、期待どおりに動作しました。ただし、コマンドラインで実行すると、空の文字列が返されます。スクリプトで使用され、スクリプトが実行された場合にのみ結果が得られます。それそれがために何を意味するかの.....
Farrukh Waheed

4
よくわかりません。この答えは、V2にPSScriptRootを使用することです。別の答えは、PSScriptRootはV3 +用であり、v2では別のものを使用することです。

6
v2の@user $ PSScriptRootはモジュール専用です。モジュールにない「通常の」スクリプトを作成している場合は、$ MyInvocation.MyCommand.Definitionが必要です。上の回答を参照してください。
yzorg 2015年

1
@Lofful私は「v2」でそれがモジュールに対してのみ定義されていると述べました。あなたはそれがv3のモジュールの外で定義されていると言っています。私たちは同じことを言っていると思います。:)
yzorg 2016

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には、ファイル名は含まれていません(他の回答とは異なります)。
YetAnotherRandomUser 2017年

$ PSScriptRootは、通常のPS1スクリプトからは空です。ただし、$ PSCommandPathは機能します。両方の動作は、他の投稿に記載されている説明に従って予想されます。[IO.Path] :: GetDirectoryName($ PSCommandPath)を使用して、ファイル名なしでスクリプトディレクトリを取得することもできます。
立ち消えに

19

PowerShell 3以降の場合

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

この関数をプロファイルに配置しました。F8/ Run Selection を使用してISE でも機能します。


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 それを保存して、別のディレクトリから実行します。スクリプトへのパスを表示します。
ショーンC.

これは優れた機能であり、私が必要としていることを行いますが、それをどのように共有し、すべてのスクリプトで使用するのですか?これは鶏と卵の問題です。現在の場所を見つけるために関数を使用したいのですが、関数をロードするには自分の場所が必要です。
アーロン・ジェンセン

2
注:この関数の呼び出しは、スクリプトの最上位にある必要があります。別の関数内にネストされている場合は、「-Scope」パラメーターを変更して、コールスタックの深さを指定する必要があります。
ケニー

11

既に投稿された回答と非常に似ていますが、パイプラインはPowerShellのように見えます。

$PSCommandPath | Split-Path -Parent

11

自動変数 を使用しています$ExecutionContext。PowerShell 2以降で動作します。

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

$ ExecutionContext Windows PowerShellホストの実行コンテキストを表すEngineIntrinsicsオブジェクトが含まれています。この変数を使用して、コマンドレットで使用できる実行オブジェクトを見つけることができます。


1
STDINからpowershellをフィードしようとして、これは私にとってそれだけで動作しました。
セバスチャン

このソリューションは、UNCパスコンテキストを使用している場合にも正しく機能します。
user2030503 2018

1
これは明らかにスクリプトが置かれている場所ではなく、作業ディレクトリを取得していますか?
monojohnny

@monojohnnyはい、これは基本的に現在の作業ディレクトリであり、別の場所からスクリプトを呼び出すと機能しません。
marsze

9

受け入れられた答えを取り入れて、それを堅牢な機能に変える何かを開発するのにしばらく時間がかかりました。

他についてはわかりませんが、PowerShellバージョン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
}

また、Michael Sorens が彼のブログ投稿の1つで概説したように、関数が親のスコープではなくスクリプトスコープを参照することも意味します。


ありがとう!「$ script:」は、これをWindows PowerShell ISEで機能させるために必要なものです。
カークLiemohn 2017年

これをありがとう。これが私に有効な唯一のものでした。通常、Get-locationなどが機能する前に、スクリプトがあるディレクトリにCDを挿入する必要があります。PowerShellがディレクトリを自動的に更新しない理由を知りたいです。
Zain

7

スクリプト名とそれがどこから実行されているかを知る必要がありました。

MyInvocation構造の前に "$ global:"を付けると、メインスクリプトと、インポートされた.PSM1ライブラリファイルのメイン行の両方から呼び出されると、フルパスとスクリプト名が返されます。また、インポートされたライブラリの関数内からも機能します。

いじくり回した後、$ global:MyInvocation.InvocationNameを使用することにしました。CMDの起動、Run With Powershell、およびISEで確実に動作します。ローカル起動とUNC起動の両方で正しいパスが返されます。


4
Split-Path -Path $($ global:MyInvocation.MyCommand.Path)は完璧に機能しました。他のソリューションは、呼び出しアプリケーションのパスを返しました。
dynamiclynk

1
些細な注意:ISEでF8 /実行選択を使用してこの関数を呼び出すと、ParameterArgumentValidationErrorNullNotAllowed例外がトリガーされます。
2015年

5

PowerShellとISEで同じように機能するこの小さなスニペットを常に使用します。

# 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シェル内で実行した場合(またはrun-selectedを選択した場合)、Get-Script-Directory上記の関数は機能しないようです。


3
$PSCommandPath最初にスクリプトを保存してファイル全体を実行する限り、ISEで機能します。それ以外の場合は、実際にはスクリプトを実行していません。シェルにコマンドを「貼り付け」ているだけです。
Zenexer 2013

@Zenexerそれは当時の私の目標だったと思います。私の目標が元の目標と一致しなかったとしても、たまにあるGoogle社員を除いて、これはあまり役に立ちません...

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.