PowerShell 스코프(Scope) 이해하기
PowerShell 스코프(Scope) 이해하기
PowerShell에서는 변수, 별칭(alias), 함수, 드라이브가 어디서 읽히고 바뀌는지가 정해져 있어요. 이걸 관리하는 규칙이 바로 스코프(scope) 인데요, 스코프를 제대로 이해하면 내가 작성한 코드가 다른 스코프에 있는 값을 실수로 건드리지 않도록 지킬 수 있어요. 오늘은 스코프가 뭔지, 어떻게 만들고 바꾸는지, 그리고 스코프를 다루는 각종 도구를 하나씩 살펴볼게요.
본문
간단한 설명
PowerShell에서 스코프의 개념이 무엇인지 설명하고, 요소의 스코프를 설정하고 변경하는 방법을 보여줌.
자세한 설명
PowerShell은 변수, 별칭, 함수, PowerShell 드라이브(PSDrive)가 어디에서 읽히고 변경되는지를 제한해서 접근을 보호해요. 이렇게 스코프 규칙(scope rules) 을 적용해서, 다른 스코프에 있는 항목을 실수로 변경하는 일을 막아주죠.
스코프 규칙
PowerShell을 시작하면 호스트(pwsh.exe)가 PowerShell 러너스페이스(runspace) 를 만들어요. 호스트 프로세스는 러너스페이스를 여러 개 가질 수 있고, 각 러너스페이스는 고유한 세션 상태(session state)와 스코프 컨테이너를 갖고 있어요. 세션 상태와 스코프는 러너스페이스 인스턴스 사이에서 접근할 수 없어요.
스코프의 기본 규칙은 다음과 같아요.
- 스코프는 중첩될 수 있어요. 바깥쪽 스코프를 부모 스코프(parent scope), 그 안에 중첩된 스코프를 자식 스코프(child scope) 라고 불러요.
- 어떤 항목은 그것이 만들어진 스코프와 모든 자식 스코프에서 보여요. 단, 명시적으로 private으로 만들지 않았을 때만 그렇죠.
- 스코프 한정자(scope modifier)를 쓰면 현재 스코프 밖의 다른 스코프에 변수, 별칭, 함수, PowerShell 드라이브를 선언할 수 있어요.
- 스코프 안에서 만든 항목은 기본적으로 그 항목을 만든 스코프 안에서만 변경돼요. 다른 스코프를 명시적으로 지정하지 않으면 말이죠.
- 러너스페이스에서 실행 중인 코드가 어떤 항목을 참조하면, PowerShell은 현재 스코프에서 시작해 각각의 부모 스코프를 거슬러 올라가며 스코프 계층을 검색해요.
- 항목을 찾지 못하면 현재 스코프에 새 항목을 만들어요.
- 항목을 발견하면 그 값을 찾은 스코프에서 가져와요.
- 값을 변경하면 변경 사항이 현재 스코프에만 영향을 주도록 항목이 현재 스코프로 복사돼요.
- 다른 스코프에 있는 항목과 같은 이름을 가진 항목을 명시적으로 만들면, 원래 항목은 새 항목에 가려질 수는 있어도 덮어쓰여지거나 바뀌지는 않아요.
부모 스코프와 자식 스코프
스크립트나 함수를 호출하면 새 자식 스코프가 만들어져요. 호출한 쪽이 부모 스코프가 되고, 호출된 스크립트나 함수가 자식 스코프가 되는 거죠. 호출한 스크립트나 함수가 다시 다른 함수를 부르면 자식 스코프가 또 생기는데, 이렇게 쌓인 계층의 뿌리 스코프(root scope)가 바로 전역 스코프(global scope)예요.
참고
모듈의 함수는 호출하는 쪽의 자식 스코프에서 실행되지 않아요. 모듈은 모듈이 가져와진 스코프에 연결된 고유한 세션 상태를 갖고 있어요. 모든 모듈 코드는 자체 루트 스코프를 가진 모듈 전용 스코프 계층에서 실행되죠. 자세한 내용은 이 문서의 Modules 섹션을 참고하세요.
자식 스코프가 만들어지면 AllScope 옵션이 있는 모든 별칭과 변수, 그리고 일부 자동 변수가 포함돼요. 이 옵션에 대해서는 이 문서에서 나중에 다시 다룰게요.
항목을 명시적으로 private으로 만들지 않았다면 부모 스코프의 항목은 자식 스코프에서도 사용할 수 있어요. 자식 스코프에서 만들거나 변경한 항목은 명시적으로 스코프를 지정하지 않는 한 부모 스코프에 영향을 주지 않아요.
특정 스코프의 항목을 찾으려면 Get-Variable이나 Get-Alias의 Scope 매개 변수를 사용하면 돼요. 예를 들어 로컬 스코프의 변수를 모두 가져오려면 이렇게 입력하세요.
Get-Variable -Scope Local
전역 스코프의 변수를 모두 가져오려면 이렇게요.
Get-Variable -Scope Global
변수, 별칭, 함수를 참조하면 PowerShell은 현재 스코프부터 검색해요. 항목이 없으면 부모 스코프를 찾고, 전역 스코프에 닿을 때까지 그 검색을 반복해요. 부모 스코프의 변수가 private이어도 검색은 스코프 체인을 따라 계속돼요. Example 4에서 스코프 검색에서 private 변수가 미치는 영향을 확인할 수 있어요.
PowerShell 스코프 이름
PowerShell은 몇몇 스코프에 이름을 붙여서 더 쉽게 접근할 수 있게 해줘요. 정의된 스코프 이름은 다음과 같아요.
- Global: PowerShell이 시작되거나 새 세션·러너스페이스를 만들 때 적용되는 스코프예요. PowerShell이 시작될 때 존재하는 변수·함수(자동 변수, 기본 설정 변수 같은 것들)는 전역 스코프에서 만들어져요. PowerShell 프로필의 변수·별칭·함수도 전역 스코프에서 만들어지고요. 전역 스코프는 러너스페이스 안에서 루트 부모 스코프 역할을 해요.
- Local: 현재 스코프예요. 로컬 스코프는 전역 스코프일 수도 있고 다른 어떤 스코프일 수도 있어요.
- Script: 스크립트 파일이 실행되는 동안 만들어지는 스코프예요. 스크립트의 명령은 스크립트 스코프에서 실행되고, 스크립트의 명령 입장에서 스크립트 스코프가 로컬 스코프죠.
스코프를 지원하는 cmdlet에서는 번호로 스코프를 가리킬 수도 있어요. 번호는 한 스코프에서 다른 스코프까지의 상대적 위치를 나타내요. 스코프 0은 현재(로컬) 스코프, 스코프 1은 현재 스코프의 부모, 스코프 2는 현재 스코프의 조부모처럼, 루트 스코프에 닿을 때까지 이어져요.
스코프 한정자
변수, 별칭, 함수 이름에는 다음 중 하나의 선택적 스코프 한정자(scope modifier)를 붙일 수 있어요.
Global:— 이름이 전역 스코프에 존재한다는 뜻이에요.Local:— 이름이 로컬 스코프에 존재한다는 뜻이에요. 현재 스코프는 항상 로컬 스코프예요.Local:한정자를 쓰면 PowerShell은 부모 스코프를 검색하지 않아요. 항목이 현재 스코프에 있으면 그걸 쓰고, 없으면 PowerShell이 현재 스코프에 새 항목을 만들어요.Private:— 이름이 private이고 현재 스코프에서만 보인다는 뜻이에요.
참고
Private:은 스코프가 아니라, 항목이 정의된 스코프 밖에서 어떻게 보이게 할지를 바꾸는 option이에요.
Script:— 이름이 스크립트 스코프에 존재한다는 뜻이에요. 스크립트 스코프는 가장 가까운 조상 스크립트 파일의 스코프이고, 가까운 조상 스크립트 파일이 없으면 전역 스코프예요.Using:— 원격 세션, 백그라운드 작업, 스레드 작업에서 실행되는 동안 다른 스코프에 정의된 변수에 접근할 때 써요.Workflow:— 이름이 워크플로 안에 존재한다는 뜻이에요. 참고로 워크플로는 PowerShell v6 이상에서는 지원되지 않아요.<variable-namespace>— PowerShell PSDrive 공급자가 만든 한정자예요. 예를 들면 다음과 같아요.
| 네임스페이스 | 설명 |
|---|---|
Alias: |
현재 스코프에 정의된 별칭 |
Env: |
현재 스코프에 정의된 환경 변수 |
Function: |
현재 스코프에 정의된 함수 |
Variable: |
현재 스코프에 정의된 변수 |
스크립트의 기본 스코프는 스크립트 스코프예요. 함수와 별칭의 기본 스코프는 로컬 스코프인데, 스크립트 안에서 정의됐어도 마찬가지예요.
스코프 한정자 사용하기
새 변수, 별칭, 함수의 스코프를 지정하려면 스코프 한정자를 사용하면 돼요.
변수에서 스코프 한정자의 구문은 이렇게 생겼어요.
$[<scope-modifier>:]<name> = <value>
함수에서의 구문은 이렇게요.
function [<scope-modifier>:]<name> {<function-body>}
다음 명령은 스코프 한정자를 쓰지 않아서 현재(로컬) 스코프에 변수를 만들어요.
$a = "one"
같은 변수를 전역 스코프에 만들려면 Global: 스코프 한정자를 써요.
$Global:a = "one"
Get-Variable a | Format-List *
출력에서 Visibility와 Options 속성 값을 주목해 보세요.
Name : a
Description :
Value : one
Visibility : Public
Module :
ModuleName :
Options : None
Attributes : {}
이번엔 private 변수와 비교해 볼게요.
$Private:pVar = 'Private variable'
Get-Variable pVar | Format-List *
Private: 스코프 한정자를 쓰면 Options 속성이 Private로 설정돼요.
Name : pVar
Description :
Value : Private variable
Visibility : Public
Module :
ModuleName :
Options : Private
Attributes : {}
같은 변수를 스크립트 스코프에 만들려면 Script: 한정자를 써요.
$Script:a = "one"
스코프 한정자는 함수에도 쓸 수 있어요. 다음 함수 정의는 전역 스코프에 함수를 만들어요.
function Global:Hello {
Write-Host "Hello, World"
}
스코프 한정자로 다른 스코프에 있는 변수를 참조할 수도 있어요. 다음 명령은 $test 변수를 로컬 스코프에서 먼저, 이어서 전역 스코프에서 참조해요.
$test
$Global:test
Using: 스코프 한정자
Using은 원격 명령 안에서 로컬 변수를 식별하는 특별한 스코프 한정자예요. 이 한정자가 없으면 PowerShell은 원격 명령의 변수가 원격 세션에 정의돼 있을 거라고 기대해요.
Using: 스코프 한정자는 PowerShell 3.0에서 도입됐어요.
세션 밖에서 실행되는 스크립트나 명령은 호출한 세션 스코프의 변수 값을 임베드할 수 있도록 Using: 스코프 한정자가 필요해요. 그래야 세션 밖의 코드가 그 값에 접근할 수 있거든요. Using: 스코프 한정자는 다음 상황에서 지원돼요.
Invoke-Command를 ComputerName, HostName, SSHConnection, Session 매개 변수와 함께 써서 시작한 원격 실행 명령(원격 세션)Start-Job으로 시작한 백그라운드 작업(프로세스 밖 세션)Start-ThreadJob이나ForEach-Object -Parallel로 시작한 스레드 작업(별도 스레드 세션)
상황에 따라 임베드된 변수 값은 호출자 스코프에 있는 데이터의 독립적인 복사본이거나 그 데이터에 대한 참조예요. 원격 세션이나 프로세스 밖 세션에서는 항상 독립적인 복사본이죠. 자세한 내용은 about_Remote_Variables를 참고하세요.
$Using: 참조는 변수의 값으로만 확장돼요. 호출자 스코프에 있는 변수의 값을 바꾸고 싶다면, 변수 자체에 대한 참조가 필요해요. 변수의 PSVariable 인스턴스를 얻으면 참조를 만들 수 있어요. 다음 예제는 스레드 작업에서 참조를 만들고 변경하는 방법을 보여줘요.
$Count = 1
$refOfCount = Get-Variable Count
Start-ThreadJob {
($Using:refOfCount).Value = 2
} | Receive-Job -Wait -AutoRemoveJob
$Count
2
참고
이 작업은 스레드에 안전하지 않아요. 여러 스레드에서 동시에 값을 바꾸려 하면 데이터가 손상될 수 있어요. 공유 데이터를 보호하려면 스레드에 안전한 데이터 형식이나 동기화 기본 요소를 쓰는 게 좋아요. 자세한 내용은 Thread-Safe collections을 참고하세요.
변수 값의 직렬화
원격으로 실행된 명령과 백그라운드 작업은 프로세스 밖에서 실행돼요. 프로세스 밖 세션은 XML 기반 직렬화·역직렬화를 사용해서 변수 값을 프로세스 경계에서 사용할 수 있게 해줘요. 직렬화 과정은 객체를 원래 객체의 속성은 갖지만 메서드는 없는 PSObject로 변환해요.
소수의 형식은 역직렬화할 때 객체가 원래 형식으로 되살아나요(재수화). 되살아난 객체는 원래 객체 인스턴스의 복사본으로, 형식의 속성과 메서드를 갖고 있어요. System.Version 같은 단순 형식은 복사본이 정확해요. 복잡한 형식은 복사본이 완벽하지 않을 수 있는데, 예를 들어 되살아난 인증서 객체에는 개인 키가 포함되지 않아요.
그 외 모든 형식의 인스턴스는 PSObject 인스턴스예요. pstypenames 속성에는 원래 형식 이름에 Deserialized가 붙는데, 예를 들면 Deserialized.System.Data.DataTable처럼 돼요.
AllScope 옵션
변수와 별칭은 AllScope 값을 가질 수 있는 Option 속성이 있어요. AllScope 속성이 있는 항목은 만들어지는 자식 스코프의 일부가 되지만, 부모 스코프에는 소급해서 상속되지는 않아요.
AllScope 속성이 있는 항목은 자식 스코프에서 보이고 그 스코프의 일부가 돼요. 어떤 스코프에서든 그 항목을 변경하면 변수가 정의된 모든 스코프에 영향을 줘요.
스코프 관리
여러 cmdlet에는 특정 스코프의 항목을 가져오거나 설정(만들기·변경)할 수 있는 Scope 매개 변수가 있어요. 세션에서 Scope 매개 변수를 가진 모든 cmdlet을 찾으려면 다음 명령을 사용하세요.
Get-Help * -Parameter Scope
특정 스코프에서 보이는 변수를 찾으려면 Get-Variable의 Scope 매개 변수를 써요. 보이는 변수에는 전역 변수, 부모 스코프의 변수, 현재 스코프의 변수가 포함돼요.
예를 들어 로컬 스코프에서 보이는 변수를 가져오는 명령이에요.
Get-Variable -Scope Local
특정 스코프에 변수를 만들려면 스코프 한정자나 Set-Variable의 Scope 매개 변수를 써요. 다음 명령은 전역 스코프에 변수를 만들어요.
New-Variable -Scope Global -Name a -Value "One"
New-Alias, Set-Alias, Get-Alias cmdlet의 Scope 매개 변수로 스코프를 지정할 수도 있어요. 다음 명령은 전역 스코프에 별칭을 만들어요.
New-Alias -Scope Global -Name np -Value Notepad.exe
특정 스코프의 함수를 가져오려면 그 스코프 안에서 Get-Item cmdlet을 써요. Get-Item에는 Scope 매개 변수가 없어요.
참고
Scope 매개 변수를 쓰는 cmdlet에서는 번호로 스코프를 가리킬 수도 있어요. 번호는 한 스코프에서 다른 스코프까지의 상대적 위치를 나타내요. 스코프 0은 현재(로컬) 스코프, 스코프 1은 바로 위 부모 스코프, 스코프 2는 부모의 부모 스코프를 뜻해요. 재귀 스코프를 많이 만들었다면 번호가 특히 유용해요.
점 소스 표기법과 스코프
스크립트와 함수도 스코프 규칙을 따라요. 스크립트·함수는 특정 스코프에서 만들어지고, cmdlet 매개 변수나 스코프 한정자로 스코프를 바꾸지 않는 한 그 스코프에만 영향을 줘요.
하지만 점 소스 표기법(dot-source notation) 을 쓰면 스크립트나 함수의 내용을 현재 스코프에 추가할 수 있어요. 점 소스 표기법으로 스크립트·함수를 실행하면 현재 스코프에서 실행되고, 스크립트·함수의 함수·별칭·변수가 현재 스코프에 추가돼요.
예를 들어 C:\Scripts 디렉터리의 Sample.ps1 스크립트를 스크립트 스코프(스크립트의 기본값)에서 실행하려면 명령줄에 스크립트 파일의 전체 경로를 입력하면 돼요.
C:\scripts\sample.ps1
실행 가능한 스크립트 파일은 .ps1 확장자를 가져야 해요. 경로에 공백이 있는 파일은 따옴표로 감싸야 하고요. 따옴표로 감싼 경로를 실행하려 하면 PowerShell은 스크립트를 실행하는 대신 따옴표 문자열 내용을 표시해요. 호출 연산자(&)는 파일 이름이 든 문자열의 내용을 실행하게 해줘요.
호출 연산자로 함수나 스크립트를 실행하면 스크립트 스코프에서 실행돼요. 이름으로 스크립트를 실행하는 것과 다를 게 없죠.
& C:\scripts\sample.ps1
호출 연산자에 대해 더 자세히 알고 싶다면 about_Operators를 참고하세요.
Sample.ps1 스크립트를 로컬 스코프에서 실행하려면 스크립트 경로 앞에 점과 공백(. )을 입력해요.
. C:\scripts\sample.ps1
이제 스크립트에 정의된 모든 함수, 별칭, 변수가 현재 스코프에 추가돼요.
스코프 없이 제한하기
PowerShell에는 스코프와 비슷하고 스코프와 상호작용할 수 있는 옵션·기능이 몇 가지 있어요. 이런 기능은 스코프나 스코프의 동작과 혼동될 수 있어요.
세션, 모듈, 중첩 프롬프트는 자체적으로 완결된 환경이지, 세션 안의 전역 스코프의 자식 스코프가 아니에요.
세션
세션은 PowerShell이 실행되는 환경이에요. 원격 컴퓨터에서 세션을 만들면 PowerShell은 원격 컴퓨터에 지속적인 연결을 설정해요. 지속적인 연결 덕분에 여러 관련 명령에 세션을 사용할 수 있어요.
세션은 완결된 환경이기 때문에 고유한 스코프를 갖고 있지만, 세션이 만들어진 세션의 자식 스코프는 아니에요. 세션은 자신의 전역 스코프로 시작하며, 이 스코프는 그 세션의 전역 스코프와 독립적이에요. 세션 안에 자식 스코프를 만들 수도 있는데, 스크립트를 실행해 세션에 자식 스코프를 만드는 식이죠.
모듈
PowerShell 모듈로 PowerShell 도구를 공유하고 배포할 수 있어요. 모듈은 cmdlet, 스크립트, 함수, 변수, 별칭, 그 밖의 유용한 항목을 담을 수 있는 단위예요. 명시적으로 내보내지 않으면(Export-ModuleMember나 모듈 매니페스트로) 모듈의 항목은 모듈 밖에서 접근할 수 없어요. 그래서 모듈을 세션에 추가하고 공개 항목을 써도, 다른 항목이 세션의 cmdlet·스크립트·함수 등을 덮어쓸 걱정을 하지 않아도 돼요.
기본적으로 모듈은 러너스페이스의 루트(전역) 스코프에 로드돼요. 모듈을 가져와도 스코프는 바뀌지 않아요.
세션 안에서 모듈은 고유한 스코프를 가져요. 다음 모듈 C:\temp\mod1.psm1을 생각해 볼게요.
$a = "Hello"
function foo {
"`$a = $a"
"`$Global:a = $Global:a"
}
이제 전역 변수 $a를 만들고 값을 준 다음 함수 foo를 호출해요.
$a = "Goodbye"
foo
모듈은 변수 $a를 모듈 스코프에 선언하고, 함수 foo는 두 스코프의 변수 값을 출력해요.
$a = Hello
$Global:a = Goodbye
모듈은 가져와진 스코프에 연결된 병렬 스코프 컨테이너를 만들어요. 모듈이 내보낸 항목은 가져와진 스코프 수준에서부터 사용할 수 있고, 내보내지 않은 항목은 모듈의 스코프 컨테이너 안에서만 사용할 수 있어요. 모듈 안의 함수는 가져와진 스코프의 항목뿐 아니라 모듈의 스코프 컨테이너 안의 항목에도 접근할 수 있어요.
Module1 안에서 Module2를 로드하면 Module2는 Module1의 스코프 컨테이너에 로드돼요. Module2에서 내보낸 항목은 Module1의 현재 모듈 스코프에 배치되고요. Import-Module -Scope Local을 쓰면 내보낸 항목이 최상위가 아니라 현재 스코프 객체에 배치돼요. 모듈 안에 있다가 Import-Module -Scope Global(또는 Import-Module -Global)로 다른 모듈을 로드하면 그 모듈과 내보낸 항목은 모듈의 로컬 스코프가 아니라 전역 스코프에 로드돼요. WindowsCompatibility 기능이 프록시 모듈을 전역 세션 상태로 가져올 때 이 방식을 써요.
중첩 프롬프트
중첩 프롬프트(nested prompt)는 고유한 스코프를 갖지 않아요. 중첩 프롬프트에 들어가면 그것은 환경의 부분집합이지만, 여전히 로컬 스코프 안에 있어요.
스크립트는 고유한 스코프를 가져요. 스크립트를 디버깅하면서 스크립트 안에서 중단점에 도달하면 스크립트 스코프에 들어가게 돼요.
private 옵션
별칭과 변수는 Private 값을 가질 수 있는 Option 속성이 있어요. Private 옵션이 있는 항목은 만들어진 스코프 안에서만 보고 변경할 수 있고, 그 스코프 밖에서는 보거나 변경할 수 없어요.
예를 들어 전역 스코프에 private 옵션을 가진 변수를 만들고 스크립트를 실행하면, 스크립트 안의 Get-Variable 명령은 그 private 변수를 표시하지 않아요. 이런 경우 Global: 스코프 한정자를 써도 private 변수는 표시되지 않아요.
New-Variable, Set-Variable, New-Alias, Set-Alias cmdlet의 Option 매개 변수로 Option 속성 값을 Private으로 설정할 수 있어요.
Visibility
변수나 별칭의 Visibility 속성은 항목이 만들어진 컨테이너 밖에서 그 항목을 볼 수 있는지 결정해요. 컨테이너는 모듈, 스크립트, 스냅인이 될 수 있어요. Visibility는 Option 속성의 Private 값이 스코프를 위해 설계된 것과 같은 방식으로, 컨테이너를 위해 설계됐어요.
Visibility 속성은 Public과 Private 값을 가져요. private 가시성을 가진 항목은 만들어진 컨테이너 안에서만 볼 수 있고 변경할 수 있어요. 컨테이너가 추가되거나 가져와지면 private 가시성의 항목은 볼 수도 변경할 수도 없어요.
visibility는 컨테이너를 위해 설계됐기 때문에 스코프에서는 다르게 동작해요.
- 전역 스코프에 private 가시성의 항목을 만들면 어떤 스코프에서도 그 항목을 보거나 변경할 수 없어요.
- private 가시성의 변수 값을 보거나 변경하려 하면 PowerShell이 오류 메시지를 반환해요.
New-Variable과 Set-Variable cmdlet으로 private 가시성을 가진 변수를 만들 수 있어요.
예제
예제 1: 스크립트에서만 변수 값을 변경하기
다음 명령은 스크립트에서 $ConfirmPreference 변수의 값을 변경해요. 이 변경은 전역 스코프에 영향을 주지 않아요.
먼저 로컬 스코프에서 $ConfirmPreference 변수 값을 표시하려면 이 명령을 써요.
PS> $ConfirmPreference
High
다음 명령이 포함된 Scope.ps1 스크립트를 만들어요.
$ConfirmPreference = "Low"
"The value of `$ConfirmPreference is $ConfirmPreference."
스크립트를 실행해요. 스크립트는 $ConfirmPreference 변수 값을 바꾸고 스크립트 스코프에서 그 값을 보고해요. 출력은 다음과 비슷할 거예요.
The value of $ConfirmPreference is Low.
이어서 현재 스코프의 $ConfirmPreference 변수 값을 확인해요.
PS> $ConfirmPreference
High
이 예제는 스크립트 스코프에서 변수 값을 변경해도 부모 스코프에서의 변수 값에는 영향이 없다는 걸 보여줘요.
예제 2: 다른 스코프에서 변수 값 보기
스코프 한정자를 사용하면 로컬 스코프와 부모 스코프에서 변수 값을 볼 수 있어요.
먼저 전역 스코프에 $test 변수를 정의해요.
$test = "Global"
이어서 $test 변수를 정의하는 Sample.ps1 스크립트를 만들어요. 스크립트 안에서는 스코프 한정자로 $test 변수의 전역 버전이나 로컬 버전을 가리켜요.
Sample.ps1에서:
$test = "Local"
"The local value of `$test is $test."
"The global value of `$test is $Global:test."
Sample.ps1을 실행하면 출력이 다음과 비슷할 거예요.
The local value of $test is Local.
The global value of $test is Global.
스크립트가 끝나면 세션에는 $test의 전역 값만 정의돼 있어요.
PS> $test
Global
예제 3: 부모 스코프에서 변수 값 변경하기
항목을 Private 옵션이나 다른 방법으로 보호하지 않았다면, 부모 스코프에서 변수 값을 보고 변경할 수 있어요.
먼저 전역 스코프에 $test 변수를 정의해요.
$test = "Global"
이어서 $test 변수를 정의하는 Sample.ps1 스크립트를 만들어요. 스크립트 안에서는 스코프 한정자로 $test 변수의 전역 버전이나 로컬 버전을 가리켜요.
Sample.ps1에서:
$Global:test = "Local"
"The global value of `$test is $Global:test."
스크립트가 끝나면 전역 $test 값이 변경돼 있어요.
PS> $test
Local
예제 4: private 변수 만들기
Private: 스코프 한정자를 쓰거나 Option 속성을 Private로 설정해 변수를 만들면 변수를 private으로 만들 수 있어요. private 변수는 만들어진 스코프에서만 보거나 변경할 수 있어요.
이 예제에서 ScopeExample.ps1 스크립트는 다섯 개의 함수를 만들어요. 첫 함수가 다음 함수를 호출해 자식 스코프를 만들고, 그중 한 함수에는 만들어진 스코프에서만 보이는 private 변수가 있어요.
PS> Get-Content ScopeExample.ps1
# Start of ScopeExample.ps1
function funcA {
"Setting `$funcAVar1 to 'Value set in funcA'"
$funcAVar1 = "Value set in funcA"
funcB
}
function funcB {
"In funcB before set -> '$funcAVar1'"
$Private:funcAVar1 = "Locally overwrite the value - child scopes can't see me!"
"In funcB after set -> '$funcAVar1'"
funcC
}
function funcC {
"In funcC before set -> '$funcAVar1' - should be the value set in funcA"
$funcAVar1 = "Value set in funcC - Child scopes can see this change."
"In funcC after set -> '$funcAVar1'"
funcD
}
function funcD {
"In funcD before set -> '$funcAVar1' - should be the value from funcC."
$funcAVar1 = "Value set in funcD"
"In funcD after set -> '$funcAVar1'"
'-------------------'
ShowScopes
}
function ShowScopes {
$funcAVar1 = "Value set in ShowScopes"
"Scope [0] (local) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 0 -ValueOnly)'"
"Scope [1] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 1 -ValueOnly)'"
"Scope [2] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 2 -ValueOnly)'"
"Scope [3] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 3 -ValueOnly)'"
"Scope [4] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 4 -ValueOnly)'"
}
funcA
# End of ScopeExample.ps1
PS> .\ScopeExample.ps1
출력은 각 스코프에서 변수의 값을 보여줘요. private 변수는 만들어진 스코프인 funcB에서만 보이는 걸 확인할 수 있어요.
Setting $funcAVar1 to 'Value set in funcA'
In funcB before set -> 'Value set in funcA'
In funcB after set -> 'Locally overwrite the value - child scopes can't see me!'
In funcC before set -> 'Value set in funcA' - should be the value set in funcA
In funcC after set -> 'Value set in funcC - Child scopes can see this change.'
In funcD before set -> 'Value set in funcC - Child scopes can see this change.' - should be the value from funcC.
In funcD after set -> 'Value set in funcD'
-------------------
Scope [0] (local) $funcAVar1 = 'Value set in ShowScopes'
Scope [1] (parent) $funcAVar1 = 'Value set in funcD'
Scope [2] (parent) $funcAVar1 = 'Value set in funcC - Child scopes can see this change.'
Scope [3] (parent) $funcAVar1 = 'Locally overwrite the value - child scopes can't see me!'
Scope [4] (parent) $funcAVar1 = 'Value set in funcA'
ShowScopes 출력에서 볼 수 있듯이, Get-Variable에 스코프 번호를 지정하면 다른 스코프의 변수에 접근할 수 있어요.
예제 5: 원격 명령에서 로컬 변수 사용하기
로컬 세션에서 만들어진 원격 명령의 변수에는 Using: 스코프 한정자를 써요. PowerShell은 원격 명령의 변수가 원격 세션에서 만들어졌을 거라고 가정하기 때문이에요.
구문은 이렇게 생겼어요.
$Using:<VariableName>
예를 들어 다음 명령은 로컬 세션에 $Cred 변수를 만들고 원격 명령에서 그 변수를 사용해요.
$Cred = Get-Credential
Invoke-Command $s {Remove-Item .\Test*.ps1 -Credential $Using:Cred}
Using: 스코프 한정자는 PowerShell 3.0에서 도입됐어요.