현재 PowerShell 스크립트의 위치를 ​​확인하는 가장 좋은 방법은 무엇입니까?


530

공통 모듈이나 스크립트를 참조해야 할 때마다 현재 스크립트 파일에 상대적인 경로를 사용하고 싶습니다. 이런 식으로 내 스크립트는 항상 라이브러리에서 다른 스크립트를 찾을 수 있습니다.

그렇다면 현재 스크립트의 디렉토리를 결정하는 가장 좋은 표준 방법은 무엇입니까? 현재, 나는하고있다 :

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

모듈 (.psm1) $PSScriptRoot에서이 정보를 얻는 데 사용할 수 있지만 일반 스크립트 (예 : .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

7
Split-Path-Parent매개 변수 와 함께 사용되어 현재 실행중인 스크립트 이름없이 현재 디렉토리를 리턴합니다.
hjoelr

5
참고 : Linux / macOS에서 PowerShell을 사용하면 스크립트에 PSScriptRoot / MyInvocation 등의 .ps1 확장자가 있어야합니다. 여기에서 버그 리포트를보십시오 : github.com/PowerShell/PowerShell/issues/4217
Dave Wood

3
잠재적 옆 흥미와 애매한 :의 가까이 V2- 근사 $PSScriptRoot(IS Split-Path -Parent에 적용) $MyInvocation.MyCommand.Path,하지 $MyInvocation.MyCommand.Definition, 스크립트의 최상위 범위가 (이 목적에서 호출에 유일하게 분별있는 곳입니다) 동일하게 동작하지만. 함수 또는 스크립트 블록 내에서 호출 하면 전자가 빈 문자열을 반환하고 후자는 함수 본문의 / 스크립트 블록 정의 를 문자열 (PowerShell 소스 코드의 일부)로 반환합니다 .
mklement0

62

V2 모듈을 작성하는 경우라는 자동 변수를 사용할 수 있습니다 $PSScriptRoot.

PS> Help 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

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를 사용하는 것입니다. 현재 파일 / 모듈의 디렉토리입니다.
Aaron Jensen

2
이 명령에는 스크립트의 파일 이름이 포함되어 있습니다. 경로를 원할 때 스크립트 이름도 원하지 않을 것입니다. 적어도 당신이 원하는 이유는 생각할 수 없습니다. $ PSScriptRoot에는 파일 이름이 포함되어 있지 않습니다 (다른 답변에서 수집).
YetAnotherRandomUser

$ 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
사용자가 스크립트를 실행 하는 현재 위치를 가져옵니다 . 스크립트 파일 자체 의 위치가 아닙니다 .
Aaron Jensen

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 저장하고 다른 디렉토리에서 실행하십시오. 스크립트 경로를 보여줍니다.
Sean C.

그것은 좋은 기능이며 필요한 것이지만 모든 스크립트에서 어떻게 공유하고 사용합니까? 닭고기와 계란 문제입니다. 현재 위치를 찾기 위해 함수를 사용하고 싶지만 함수를로드하려면 내 위치가 필요합니다.
Aaron Jensen

2
참고 :이 함수의 호출은 스크립트의 최상위 레벨에 있어야합니다. 다른 함수 내에 중첩 된 경우 "-Scope"매개 변수를 변경하여 호출 스택의 깊이를 지정해야합니다.
kenny

11

이미 게시 된 답변과 매우 유사하지만 파이핑은 PowerShell과 같은 것으로 보입니다.

$PSCommandPath | Split-Path -Parent

11

자동 변수를 사용합니다 $ExecutionContext. PowerShell 2 이상에서 작동합니다.

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

$ ExecutionContext Windows PowerShell 호스트의 실행 컨텍스트를 나타내는 EngineIntrinsics 개체가 포함되어 있습니다. 이 변수를 사용하여 cmdlet에 사용할 수있는 실행 개체를 찾을 수 있습니다.


1
이것이 STDIN에서 powershell을 공급하려고 노력한 유일한 사람입니다.
Sebastian

이 솔루션은 UNC 경로 컨텍스트에있을 때도 올바르게 작동합니다.
user2030503

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 의 블로그 게시물 중 하나에서 설명한대로 부모의 범위가 아니라 스크립트 범위를 나타냅니다 .


감사! "$ script :"는 이것을 Windows PowerShell ISE에서 작동시키는 데 필요한 것입니다.
Kirk Liemohn

고마워 이것은 나를 위해 일하는 유일한 사람이었습니다. 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 / Run Selection을 사용하여이 함수를 호출하면 ParameterArgumentValidationErrorNullNotAllowed예외 가 발생합니다 .
weir

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 셸에서 해당 함수를 실행하면 (또는 선택한 경우) Get-Script-Directory위와 같은 기능이 작동하지 않는 것 같습니다 .


3
$PSCommandPath스크립트를 먼저 저장하고 전체 파일을 실행하는 한 ISE에서 작동합니다. 그렇지 않으면 실제로 스크립트를 실행하지 않는 것입니다. 쉘에 명령을 "붙여 넣기"만하면됩니다.
Zenexer

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