about_Scripts
about_Scripts
PowerShell에서 스크립트를 실행하고 작성하는 방법을 알아봐요. 명령을 하나만 담은 간단한 파일부터 복잡한 프로그램까지, 스크립트가 어떤 도구인지 하나씩 설명드릴게요.
본문
스크립트가 뭘까요?
스크립트는 PowerShell 명령이 하나 이상 담긴 평범한 텍스트 파일이에요. 파일 확장자는 .ps1이에요.
스크립트 실행은 cmdlet 실행과 매우 비슷해요. 스크립트의 경로와 파일 이름을 입력하고, 매개변수로 데이터를 넘기고 옵션을 설정하면 되죠. 내 컴퓨터에서도 실행할 수 있고, 원격 세션의 다른 컴퓨터에서도 실행할 수 있어요.
스크립트를 작성하면 명령을 나중에 다시 쓰지 않아도 되고, 다른 사람과 공유하기도 쉬워요. 무엇보다 스크립트 경로와 파일 이름만 입력하면 명령을 그대로 실행할 수 있다는 점이 가장 큰 장점이에요. 스크립트는 파일 하나에 명령 한 줄짜리로도 만들 수 있고, 복잡한 프로그램 수준으로도 만들 수 있어요.
스크립트는 여기에 더해 몇 가지 기능을 더 쓸 수 있어요. #Requires 특수 주석, 매개변수 사용, 데이터 섹션 지원, 보안을 위한 디지털 서명 같은 것들이요. 스크립트 자체는 물론 스크립트 안의 함수에도 Help 항목을 작성할 수 있답니다.
스크립트 실행하기
Windows에서 스크립트를 실행하려면 먼저 기본 PowerShell 실행 정책(execution policy)을 바꿔야 해요. 실행 정책은 Windows가 아닌 플랫폼에서 돌아가는 PowerShell에는 적용되지 않아요.
기본 실행 정책인 Restricted는 로컬 컴퓨터에서 직접 작성한 스크립트까지 포함해 모든 스크립트 실행을 막아요. 자세한 내용은 about_Execution_Policies를 참고하세요.
실행 정책은 레지스트리에 저장되기 때문에 컴퓨터마다 한 번만 바꾸면 돼요.
실행 정책을 바꾸려면 명령 프롬프트에 다음과 같이 입력하세요.
Set-ExecutionPolicy AllSigned
또는
Set-ExecutionPolicy RemoteSigned
이 변경은 즉시 적용돼요.
스크립트를 실행하려면 스크립트 파일의 전체 이름과 전체 경로를 입력해요. 예를 들어 C:\Scripts 디렉터리의 Get-ServiceLog.ps1 스크립트를 실행하려면 이렇게 입력하세요.
C:\Scripts\Get-ServiceLog.ps1
현재 디렉터리의 스크립트를 실행하려면 현재 디렉터리 경로를 입력하거나, 점(.)으로 현재 디렉터리를 나타낸 뒤 경로 백슬래시(.\)를 붙여 입력해요. 로컬 디렉터리의 ServicesLog.ps1 스크립트를 실행한다면 이렇게요.
.\Get-ServiceLog.ps1
스크립트에 매개변수가 있다면 스크립트 파일 이름 뒤에 매개변수와 그 값을 입력해요. 아래 명령은 Get-ServiceLog 스크립트의 ServiceName 매개변수로 WinRM 서비스 활동 로그를 요청하는 예시예요.
.\Get-ServiceLog.ps1 -ServiceName WinRM
보안 기능으로서 PowerShell은 스크립트가 현재 디렉터리에 있더라도, 파일 탐색기에서 스크립트 아이콘을 더블클릭하거나 전체 경로 없이 스크립트 이름만 입력하면 실행하지 않아요. PowerShell에서 명령과 스크립트를 실행하는 방법에 대한 자세한 내용은 about_Command_Precedence를 참고하세요.
Run with PowerShell
PowerShell 3.0부터는 파일 탐색기에서 스크립트를 실행할 수 있어요. "Run with PowerShell" 기능을 사용하려면:
파일 탐색기를 열고 스크립트 파일 이름을 마우스 오른쪽 버튼으로 클릭한 다음 "Run with PowerShell"을 선택하세요.
"Run with PowerShell" 기능은 필수 매개변수가 없고 명령 프롬프트로 출력을 반환하지 않는 스크립트를 실행하도록 설계되었어요. 자세한 내용은 about_Run_With_PowerShell을 참고하세요.
다른 컴퓨터에서 스크립트 실행하기
하나 이상의 원격 컴퓨터에서 스크립트를 실행하려면 Invoke-Command cmdlet의 FilePath 매개변수를 사용하세요. 스크립트의 경로와 파일 이름을 FilePath 매개변수의 값으로 입력해요. 이때 스크립트는 로컬 컴퓨터에 있거나, 로컬 컴퓨터가 접근할 수 있는 디렉터리에 있어야 해요.
아래 명령은 Server01, Server02라는 원격 컴퓨터에서 Get-ServiceLog.ps1 스크립트를 실행해요.
$invokeCommandSplat = @{
ComputerName = 'Server01', 'Server02'
FilePath = 'C:\Scripts\Get-ServiceLog.ps1'
}
Invoke-Command @invokeCommandSplat
스크립트 도움말 가져오기
Get-Help cmdlet은 cmdlet 같은 명령뿐 아니라 스크립트의 Help 항목도 가져와요. 스크립트의 Help 항목을 보려면 Get-Help 뒤에 스크립트의 경로와 파일 이름을 입력하면 돼요. 스크립트 경로가 PATH 환경 변수에 있다면 경로는 생략해도 돼요. 예를 들어 ServicesLog.ps1 스크립트의 도움말을 보려면 이렇게 입력하세요.
Get-Help C:\admin\scripts\ServicesLog.ps1
스크립트 작성하기
스크립트에는 유효한 PowerShell 명령이라면 무엇이든 담을 수 있어요. 단일 명령, 파이프라인을 사용하는 명령, 함수, 그리고 if 문이나 for 루프 같은 제어 구조까지요.
스크립트를 작성하려면 텍스트 편집기에서 새 파일을 열고 명령을 입력한 뒤, .ps1 확장자를 가진 유효한 파일 이름으로 저장하면 돼요. 아래 예시는 현재 시스템에서 실행 중인 서비스를 가져와 로그 파일로 저장하는 간단한 스크립트예요. 로그 파일 이름은 현재 날짜로 만들어져요.
$date = (Get-Date).DayOfYear
Get-Service | Out-File "$date.log"
이 스크립트를 만들려면 텍스트 편집기나 스크립트 편집기를 열고 위 명령을 입력한 뒤 ServiceLog.ps1이라는 이름으로 저장하세요.
스크립트의 매개변수
스크립트에 매개변수를 정의하려면 param 문을 사용해요. param 문은 주석과 #Requires 문을 제외하고 스크립트에서 반드시 가장 처음에 와야 해요.
스크립트 매개변수는 함수 매개변수처럼 동작해요. 매개변수 값은 스크립트 안의 모든 명령이 사용할 수 있고, Parameter 특성과 그 명명된 인수까지 함수 매개변수의 모든 기능이 스크립트에서도 유효해요.
스크립트를 실행할 때는 스크립트 이름 뒤에 매개변수를 입력하면 돼요.
아래 예시는 ComputerName 매개변수가 있는 Test-Remote.ps1 스크립트예요. 스크립트의 두 함수가 모두 ComputerName 매개변수 값을 사용할 수 있어요.
param ($ComputerName = $(throw "ComputerName parameter is required."))
function CanPing {
$Error.Clear()
$tmp = Test-Connection $ComputerName -ErrorAction SilentlyContinue
if (!$?)
{Write-Host "Ping failed: $ComputerName."; return $false}
else
{Write-Host "Ping succeeded: $ComputerName"; return $true}
}
function CanRemote {
$s = New-PSSession $ComputerName -ErrorAction SilentlyContinue
if ($s -is [System.Management.Automation.Runspaces.PSSession])
{Write-Host "Remote test succeeded: $ComputerName."}
else
{Write-Host "Remote test failed: $ComputerName."}
}
if (CanPing $ComputerName) {CanRemote $ComputerName}
이 스크립트를 실행하려면 스크립트 이름 뒤에 매개변수 이름을 입력해요. 예를 들어:
C:\PS> .\test-remote.ps1 -ComputerName Server01
Ping succeeded: Server01
Remote test failed: Server01
param 문과 함수 매개변수에 대한 자세한 내용은 about_Functions와 about_Functions_Advanced_Parameters를 참고하세요.
스크립트 Help 작성하기
스크립트의 Help 항목은 다음 두 가지 방법 가운데 하나로 작성할 수 있어요.
Comment-Based Help for Scripts
특수 키워드를 주석에 넣어 Help 항목을 만들어요. 주석 기반 Help를 스크립트에 만들려면 주석을 스크립트 파일의 시작이나 끝에 배치해야 해요. 주석 기반 Help에 대한 자세한 내용은 about_Comment_Based_Help를 참고하세요.
XML-Based Help for Scripts
cmdlet용으로 만드는 방식과 같은 XML 기반 Help 항목을 만들어요. Help 항목을 여러 언어로 번역해야 한다면 XML 기반 Help가 필요해요. 스크립트를 XML 기반 Help 항목과 연결하려면 .EXTERNALHELP Help 주석 키워드를 사용하세요. 자세한 내용은 다음을 참고하세요.
종료 값 반환하기
기본적으로 스크립트는 끝날 때 종료 상태(exit status)를 반환하지 않아요. 스크립트에서 종료 코드를 반환하려면 반드시 exit 문을 사용해야 해요. 기본적으로 exit 문은 0을 반환하고, 다른 종료 상태를 반환하려면 숫자 값을 넣을 수 있어요. 0이 아닌 종료 코드는 대개 실패를 뜻해요.
Windows에서는 [int]::MinValue부터 [int]::MaxValue 사이의 어떤 숫자도 허용돼요.
Unix에서는 [byte]::MinValue(0)부터 [byte]::MaxValue(255) 사이의 양수만 허용돼요. -1부터 -255 범위의 음수는 256을 더해 자동으로 양수로 변환돼요. 예를 들어 -2는 254로 변환되죠.
PowerShell에서 exit 문은 $LASTEXITCODE 변수의 값을 설정해요. Windows 명령 셸(cmd.exe)에서는 exit 문이 %ERRORLEVEL% 환경 변수의 값을 설정해요.
숫자가 아니거나 플랫폼별 범위를 벗어난 인수는 0 값으로 변환돼요.
스크립트 범위와 dot sourcing
각 스크립트는 자신만의 범위(scope)에서 실행돼요. 스크립트 안에서 만든 함수, 변수, 별칭, 드라이브는 스크립트 범위 안에서만 존재해요. 스크립트가 실행되는 범위에서는 이런 항목이나 그 값에 접근할 수 없어요.
다른 범위에서 스크립트를 실행하려면 Global이나 Local 같은 범위를 지정하거나, 스크립트를 dot source하면 돼요.
dot sourcing 기능을 쓰면 스크립트 범위가 아니라 현재 범위에서 스크립트를 실행할 수 있어요. dot source한 스크립트를 실행하면, 그 스크립트의 명령은 마치 명령 프롬프트에 직접 입력한 것처럼 실행돼요. 스크립트가 만드는 함수, 변수, 별칭, 드라이브는 지금 작업 중인 범위에 만들어져요. 스크립트가 실행된 뒤에는 그 항목을 사용하고 세션에서 값을 접근할 수 있어요.
스크립트를 dot source하려면 스크립트 경로 앞에 점(.)과 공백을 입력해요. 예를 들어:
. C:\scripts\UtilityFunctions.ps1
또는
. .\UtilityFunctions.ps1
UtilityFunctions.ps1 스크립트가 실행된 뒤에는 이 스크립트가 만든 함수와 변수가 현재 범위에 추가돼요. UtilityFunctions.ps1 스크립트는 New-Profile 함수와 $ProfileName 변수를 만드는 예시예요.
#In UtilityFunctions.ps1
function New-Profile
{
Write-Host "Running New-Profile function"
$profileName = Split-Path $PROFILE -Leaf
if (Test-Path $PROFILE)
{Write-Error "Profile $profileName already exists on this computer."}
else
{New-Item -Type File -Path $PROFILE -Force }
}
UtilityFunctions.ps1 스크립트를 자기 스크립트 범위에서 실행하면 New-Profile 함수와 $ProfileName 변수는 스크립트가 실행되는 동안에만 존재해요. 스크립트가 종료되면 함수와 변수는 제거돼요. 다음 예시가 그 모습을 보여줘요.
C:\PS> .\UtilityFunctions.ps1
C:\PS> New-Profile
The term 'New-Profile' is not recognized as a cmdlet, function, operable
program, or script file. Verify the term and try again.
At line:1 char:12
+ New-Profile <<<<
+ CategoryInfo : ObjectNotFound: (New-Profile:String) [],
+ FullyQualifiedErrorId : CommandNotFoundException
C:\PS> $profileName
C:\PS>
반대로 스크립트를 dot source해서 실행하면, 스크립트가 New-Profile 함수와 $ProfileName 변수를 내 세션의 내 범위에 만들어요. 스크립트가 실행된 뒤에도 세션에서 New-Profile 함수를 계속 쓸 수 있어요. 다음 예시가 그 모습을 보여줘요.
C:\PS> . .\UtilityFunctions.ps1
C:\PS> New-Profile
Directory: C:\Users\juneb\Documents\WindowsPowerShell
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 1/14/2009 3:08 PM 0 Microsoft.PowerShellISE_profile.ps1
C:\PS> $profileName
Microsoft.PowerShellISE_profile.ps1
범위에 대한 자세한 내용은 about_Scopes를 참고하세요.
모듈 안의 스크립트
모듈은 하나의 단위로 배포할 수 있는 관련 PowerShell 리소스의 집합이에요. 모듈로 스크립트, 함수, 그 밖의 리소스를 정리할 수 있고, 코드를 다른 사람에게 배포하거나 신뢰할 수 있는 소스에서 코드를 받아올 수도 있어요.
모듈에 스크립트를 포함할 수도 있고, 스크립트 모듈을 만들 수도 있어요. 스크립트 모듈은 전적으로 또는 주로 스크립트와 보조 리소스로 이루어진 모듈을 말하고, .psm1 파일 확장자를 가진 스크립트일 뿐이에요. 모듈에 대한 자세한 내용은 about_Modules을 참고하세요.
다른 스크립트 기능
PowerShell에는 스크립트에서 유용하게 쓸 수 있는 기능이 여럿 있어요.
#Requires — #Requires 문을 사용하면 지정한 모듈·스냅인과 지정한 PowerShell 버전 없이는 스크립트가 실행되지 않도록 막을 수 있어요. 자세한 내용은 about_Requires를 참고하세요.
$PSCommandPath — 실행 중인 스크립트의 전체 경로와 이름을 담아요. 이 매개변수는 모든 스크립트에서 유효하고, 이 자동 변수는 PowerShell 3.0에서 도입되었어요.
$PSScriptRoot — 스크립트가 실행되는 디렉터리를 담아요. PowerShell 2.0에서는 이 변수가 스크립트 모듈(.psm1)에서만 유효했어요. PowerShell 3.0부터는 모든 스크립트에서 유효해요.
$MyInvocation — $MyInvocation 자동 변수는 현재 스크립트에 대한 정보를 담아요. 시작되거나 "호출(invoked)"된 방식에 대한 정보도 포함되죠. 이 변수와 그 속성으로 실행 중인 스크립트의 정보를 얻을 수 있어요. 예를 들어 $MyInvocation.MyCommand.Path 변수는 스크립트의 경로와 파일 이름을 담고, $MyInvocation.Line은 매개변수와 값을 포함해 스크립트를 시작시킨 명령을 담아요.
PowerShell 3.0부터 $MyInvocation에는 현재 스크립트를 호출하거나 불러낸 스크립트에 대한 정보를 제공하는 속성 두 개가 새로 생겼어요. 이 속성의 값은 호출자(caller)가 스크립트일 때만 채워져요.
PSCommandPath— 현재 스크립트를 호출하거나 불러낸 스크립트의 전체 경로와 이름을 담아요.PSScriptRoot— 현재 스크립트를 호출하거나 불러낸 스크립트의 디렉터리를 담아요.
현재 스크립트의 정보를 담는 $PSCommandPath, $PSScriptRoot 자동 변수와 달리, $MyInvocation 변수의 PSCommandPath, PSScriptRoot 속성은 현재 스크립트를 호출한 스크립트의 정보를 담아요.
데이터 섹션 — Data 키워드로 스크립트 안의 데이터와 로직을 분리할 수 있어요. 데이터 섹션은 지역화(localization)도 쉽게 만들어 줘요. 자세한 내용은 about_Data_Sections와 about_Script_Internationalization을 참고하세요.
스크립트 서명(Script Signing) — 스크립트에 디지털 서명을 추가할 수 있어요. 실행 정책에 따라 디지털 서명으로 안전하지 않은 명령이 포함된 스크립트의 실행을 제한할 수 있어요. 자세한 내용은 about_Execution_Policies와 about_Signing을 참고하세요.