현재 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.