PowerShell PSake를 사용하여 작업 자동화하기: 안내

그렇다면 PowerShell 스크립트를 사용하여 작업을 자동화하는 방법을 배웠습니다. 대단해요! 그러나 이제는 스크립트와 모듈이 뒤죽박죽인 상태로 정리되지 않은 상태입니다. 수동 스크립트 실행, 예약된 작업 등이 혼합되어 있습니다. 이제 혼돈 속에서 정리를 하고 PowerShell PSake라는 자동화 오케스트레이션 엔진을 구현할 시간입니다.

PSake는 PowerShell 모듈로 작성된 오케스트레이션 엔진으로, 스크립트에 순서를 부여하고 언제 어떤 조건으로 실행되는지를 완전히 제어할 수 있습니다. PSake는 빌드 자동화 도구이며 주로 빌드 스크립트에서 사용되지만 일상적인 스크립팅 시나리오에서는 일반적으로 간과되고 있습니다. 이를 바꿔보겠습니다.

이 자습서에서는 PSake의 작동 방식과 오늘 실습할 수 있는 훌륭한 예제를 배우게 될 것입니다!

전제 조건

이 문서는 따라하기를 기대하는 자습서입니다. 정확히 따라하기를 원한다면 다음 사항을 확인해주세요:

  • Windows PowerShell 3+입니다. 이 자습서는 Windows PowerShell v5.1을 사용합니다.
  • GitHub의 PSake zip 파일입니다. 이 자습서에서는 v4.9.0을 사용합니다.

PSake 모듈 설정하기

GitHub에서 다운로드한 PSake 프로젝트를 로컬 컴퓨터에 가지고 있다고 가정하고, 설정을 완료하기 위해 몇 가지 단계를 따라야 합니다.

  1. GitHub에서 다운로드한 PSake zip 파일을 추출합니다.
  2. 추출된 ZIP 파일 내용물의 src 폴더를 $env:PSModulePath 아래 경로로 이동하여 PowerShell이 새 모듈을 인식하도록 합니다.
  3. src 폴더의 이름을 PSake으로 변경합니다.
  4. 이제 Get-Module PSake -ListAvailable을 실행하여 표시되는지 확인합니다. 오류가 나지 않으면 진행할 준비가 되었습니다.

관련 내용: PowerShell 모듈 이해 및 빌드하기

기본 PowerShell PSake 스크립트 만들기

PSake를 이해하기 위해 무언가를 만들어보아야 합니다. 간단한 PSake 스크립트를 만들어서 무엇을 할 수 있는지 확인해 보겠습니다.

  1. 이름이 psakefile.ps1인 스크립트를 만들고 단일 작업을 추가합니다. 최소한 작업에는 이름과 액션 블록이 있어야 합니다. psakefile.ps1은 필수적인 이름은 아니지만 엔진에서 기본으로 기대하는 이름입니다.

A PSake task in its basic form is very similar to a PowerShell function:
a container for one or more commands that, when performed together, achieve a certain goal. These commands go into a script block that is passed to the Action parameter. A task has many advantages over a function. You will learn about these advantages as you read along.

다음은 상대적으로 간단한 작업이 포함된 psakefile.ps1의 예입니다.

task HelloWorld -Action {
    Write-Host '*** Hello World ***' -ForegroundColor Yellow
}

2. PSake 파일을 만들었으므로 PowerShell 콘솔에서 Invoke-PSake 명령어를 사용하여 호출하고 작업 이름을 TaskList 매개변수에 전달할 수 있습니다.

Invoke-PSake은 PSake의 실행 엔진입니다. 이 명령은 psakefile.ps1에 정의된 작업을 트리거합니다. TaskList 매개변수에 작업 이름이나 쉼표로 구분된 작업 목록을 전달합니다. 여러 작업을 실행하는 경우, 각 작업은 psakefile.ps1에 위치와 관계없이 TaskList에 전달된 순서대로 실행됩니다.

아래는 HelloWorld 작업을 실행하는 방법입니다:

Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList 'HelloWorld'

psakefile.ps1이라는 이름을 유지하고, 해당 폴더로 콘솔을 설정한 경우에는 BuildFile 매개변수와 그 값을 생략할 수 있습니다.

  1. Invoke-PSake 를 실행하면 콘솔에 PSake 출력이 표시됩니다. psakefile.ps1에서 작업을 실행할 때, 아래와 같은 출력이 표시됩니다.
Psake script output

출력은 다음 구성 요소로 이루어져 있습니다:

  1. PSake 버전에 대한 세부 정보.
  2. 각 빌드 작업이 실행되기 전에 해당 작업의 이름 (PSake는 모든 작업을 빌드 작업으로 간주합니다). 예제에서는 청록색으로 HelloWorld 실행.
  3. 작업이 생성한 출력. 예제에서는 노란색으로 Hello World.
  4. 성공/실패 메시지. 예제에서는 초록색으로 psake succeeded….
  5. 각 작업의 지속 시간 및 전체 스크립트의 총 지속 시간을 포함한 시간 요약 (빌드 시간 보고서)

PSake를 사용하여 SQL 설치하기

이전 섹션에서는 더 이상하지 않고 더미 PSake 스크립트를 실행했습니다. 이제 이 지식을 기반으로 SQL을 설치하는 PSake 스크립트를 생성해 보세요!

이 예제에서는 다음과 같은 PSake 스크립트를 만들 예정입니다:

  1. 컴퓨터의 여유 디스크 공간을 유효성 검사합니다.
  2. 로컬 저장소에서 SQL ZIP 파일을 다운로드합니다.
  3. ZIP 파일을 추출합니다.
  4. C 또는 D 드라이브(둘 중 하나가 존재하는 경우)에 설치를 실행합니다.

다음으로 PSake를 사용하여 작업을 수행하는 방법을 알아보겠습니다.

Building Blocks 설계

PSake는 작업을 조율하는 데 있어 핵심입니다. 각 작업은 고유한 이름을 가져야 하며 PowerShell 함수와 같은 단일 원자 작업을 수행하는 것이 이상적입니다. 이 개념을 사용하여 아래 단계를 설명하고 각 작업을 빌드할 수 있습니다.

  1. ValidateDiskSpace
  2. DownloadSql
  3. ExtractSql
  4. InstallSqlDriveC
  5. InstallSqlDriveD

이 시점에서 실제로 무언가를 구축하는 것이 아닙니다. 작업을 설계하고 PSake 파일을 만들고 있을 뿐입니다. 아래 작업에 대한 Write-Host 참조를 주목하십시오. 작업을 나중에 추가할 예정입니다.

각 작업에는 항상 Description 매개변수를 사용해야 합니다. Description 매개변수는 작업을 실행하거나 코드를 검토할 때 각 작업에 대한 자세한 정보를 제공합니다.

task ValidateDiskSpace -Description 'Validate Disk Free Space' -Action {
	
	Write-Host "`n   *** Checking disk free space ***`n" -ForegroundColor Yellow
	
}

task DownloadSql -Description 'Download SQL Setup' -Action {
	
	Write-Host "`n   *** Downloading SQL Setup from LAN ***`n" -ForegroundColor Yellow
	
}

task ExtractSql -Description 'Extract SQL Setup' -Action {
	
	Write-Host "`n   *** Extracting SQL Setup files ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveC -Description 'Install SQL on C:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow

}

task InstallSqlDriveD -Description 'Install SQL on D:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

작업 실행 순서 정의

이제 작업 세트가 포함된 PSake 파일이 준비되었습니다. 이 시점에서 모든 작업을 한 번에 실행하거나 Invoke-PSake 명령을 사용하여 일부 작업만 실행할 수 있습니다.

당신은 Invoke-PSakeTaskList 매개변수를 사용하여 몇 가지 (또는 모든 작업)를 호출할 수 있습니다. 이전에 간단한 예제에서처럼 배열을 만들고 각 작업의 이름을 항목으로 정의하십시오.

Invoke-PSake는 배열에서 정의된 순서대로 각 작업을 실행합니다.

$taskList = @()

$taskList += 'ValidateDiskSpace'
$taskList += 'DownloadSql'
$taskList += 'ExtractSql'
$taskList += 'InstallSqlDriveC'
$taskList += 'InstallSqlDriveD'

Invoke-PSake -TaskList $taskList

위의 코드를 실행하면 다음과 같은 결과를 얻을 수 있어야 합니다:

PSake script output

PreCondition 추가

특정 조건이 충족될 경우에만 작업을 수행해야 할 수도 있습니다. 이 튜토리얼의 예제 SQL 설치 스크립트에서는 설치 프로그램을 저장하는 볼륨이 실행 중인지 확인해야 할 수도 있습니다.

PreCondition 매개변수를 사용하여 작업이 실행되는지 여부를 결정하는 불리언 True 또는 False를 반환하는 코드를 실행할 수 있습니다.

아래 예제에서 $installSqlOn_C_Drive$installSqlOn_D_Drive 변수를 주목하세요. Invoke-PSake가 이 스크립트를 호출할 때, 이러한 변수는 C 또는 D 볼륨이 존재하는지 여부에 따라 True 또는 False 값을 포함할 것입니다.

task 줄에서는 각 작업이 해당 변수의 값을 가진 PreCondition 스크립트블록 매개변수를 가지고 있다는 것을 볼 수 있습니다. 실행 시간에는 이러한 변수에 따라 InstallSqlDriveC 또는 InstallSqlDriveD 작업 중 하나가 실행됩니다.

$installSqlOn_C_Drive = (Test-Path -Path 'C:') -and (-not (Test-Path -Path 'D:'))
$installSqlOn_D_Drive = (-not (Test-Path -Path 'C:')) -and (Test-Path -Path 'D:')

task InstallSqlDriveC -Description 'Install SQL on C:' -PreCondition { $installSqlOn_C_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

작업 매개변수

ActionDescription 외에도 작업은 다음 매개변수를 지원합니다:

  • PreCondition – 부울 값을 반환하는 스크립트 블록입니다. False 인 경우 특정 작업이 건너뜁니다. (사용 예제는 위에 표시됨).
  • PostCondition 유효성 검사 단계입니다. 부울 값을 반환하는 스크립트 블록입니다. False는 유효성 검사가 실패하여 전체 스크립트가 중지됨을 의미합니다.
  • PreAction – 작업 전에 실행할 스크립트 블록입니다.
  • PostAction 작업이 성공적으로 완료된 직후 실행할 스크립트 블록입니다.
  • ContinueOnError 스위치 매개변수입니다. 사용하면 작업 실행 중 발생할 수 있는 모든 오류가 전체 스크립트를 중단시키지 않습니다.
  • Depends 현재 작업이 실행되기 전에 실행해야하는 작업의 이름 (또는 작업 이름 목록)입니다. PSake는 이 정보를 사용하여 작업 종속성을 올바른 순서로 실행합니다. 예를 들어, 작업 A가 작업 B에 종속되어 있다면, PSake 엔진은 A를 실행하기 전에 B를 실행합니다.

먼저 종속성 메커니즘은 좋은 아이디어처럼 보입니다. 작업을 논리적인 순서로 설정하는 데 도움이 됩니다. 그러나 Depends 매개변수를 사용하면 다른 작업들을 서로 연결하여 나중에 독립적으로 테스트하기가 어려워집니다. 그러나 사용자는 명시적으로 작업 실행 순서를 설정하고 PSake 파일을 호출할 때 이 순서를 전달할 수 있으므로 Depends 매개변수의 사용을 완전히 피할 수 있습니다.

다음은 이러한 작업 매개변수 중 일부에 대한 사용 예제를 살펴보겠습니다.

PreAction과 PostCondition 추가

위의 예제에서 InstallSqlDriveD 작업을 시작점으로 사용하여 설치에 대한 추가 요청이 있을 수 있습니다.

아마도 설치가 시작되고 끝나는 시간을 기록해야 할 필요가 있을 것입니다. 이러한 시간을 SqlSetupStartDateSqlSetupEndDate라는 두 개의 환경 변수에 기록해야 합니다. 두 번째로, 설치가 완료된 후에는 D:\TempSqlFiles 폴더가 존재하지 않는지 확인해야 합니다.

다행히, PSake 작업 매개변수인 PreAction, PostAction PostCondition (각각)은 이러한 새로운 요구 사항을 정확히 충족시킵니다. 아래에는 이를 수행하는 예시가 있습니다:

task InstallSqlDriveD -Description 'Install SQL on D:' -PreAction {

     Write-Host '*** Writing SQL install start time to env. var. SqlSetupStartDate ***' -ForegroundColor Yellow
     $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupStartDate',$date,'Machine')

 } -PreCondition { 

     $installSqlOn_D_Drive

 } -Action {  
  
     Write-Host '*** Installing SQL Server on D drive... please wait... ***' -ForegroundColor Yellow 

} -PostAction {     

    Write-Host '*** Writing SQL install end time to env. var. SqlSetupEndDate ***' -ForegroundColor Yellow     
    $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupEndDate',$date,'Machine') 

} -PostCondition { 
    
Write-Host '*** Verifying temp files deleted ***' -ForegroundColor Yellow
     # 폴더가 존재하는 경우 전체 스크립트가 중단되도록 False를 반환합니다
     (-not (Test-Path -Path 'D:\TempSqlFiles'))

 }

Pester 테스트에서 PSake 스크립트 실행

PowerShell 스크립트를 호출할 수 있는 곳이라면 어디서든 PSake 파일을 호출할 수 있습니다. Pester를 사용하여 인프라 테스트를 빌드하는 경우, 테스트 내에서 PSake를 호출할 수 있습니다.

관련 정보: PowerShell에 대한 Pester 테스트 작성하기

예를 들어, DownloadSql 작업을 실행한 후 폴더에 SQL 설치 ZIP 파일이 존재하는지 확인하는 Pester 테스트가 있다고 가정해 보겠습니다. 이 경우, 간단한 Pester 테스트를 작성하고 테스트 내에서 DownloadSql 작업을 호출하고 실행 직후에 ZIP 파일을 확인합니다.

Describe 'SQL install with PSake' {

    It 'Downloads Sql files' {

        $setup = 'C:\Downloads\SqlSetup.zip'

        if(Test-Path -Path $setup)
        {
            Remove-Item -Path $setup
        }

        # 여기서 테스트 대상은 DownloadSql 작업입니다
        Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList DownloadSql
        
        $setup | Should -Exist
    }
}

작업에 매개변수 전달하기

PSake를 사용하면 일부 작업을 매개변수화 할 수 있습니다. 일반적으로 PowerShell 함수와 스크립트를 사용할 때 함수/스크립트에 여러 개의 이름 있는 매개변수를 전달합니다. 그러나 PSake는 조금 다릅니다.

PSake 파일에 매개변수를 전달하려면 각 작업 안에서 사용할 수 있도록 PSake에서 사용할 수 있는 키/값 쌍을 정의하는 Properties 블록을 사용할 수 있습니다.

PSake 파일 맨 위에 Properties 블록을 정의하는 것을 잊지 마세요. 모든 PSake 작업은 위에서 아래로 읽힙니다.

예를 들어, PSake 파일의 각 작업에 동적인 SqlYearSqlVersion 변수를 전달하려면 다음과 같이 정의할 수 있습니다.

Properties {
    $SqlYear = '2017'
    $SqlVersion = '14.0'
}

task -Name DownloadSql -Action {
    
    Write-Host "SQL version to install: SQL $SqlYear (version $SqlVersion)"

}

Invoke-PSake로 PSake 파일을 호출할 때 다음과 같은 출력이 표시됩니다. $SqlYear$SqlVersion 변수가 Properties 블록에서 정의된 값으로 확장되었음을 알 수 있습니다.

psake version 4.9.1
Copyright (c) 2010-2018 James Kovacs & Contributors

Executing DownloadSql
SQL version to install: SQL 2017 (version 14.0)

psake succeeded executing C:\Work\PSakefile.ps1

--------------------------------------------------
Build Time Report
--------------------------------------------------

Name        Duration
----        --------
DownloadSql 00:00:00
------      --------
Total:      00:00:00

Properties 매개변수 사용

작업에 매개변수를 전통적인 매개변수를 통해 전달하려면 PSake를 사용할 수 있습니다. 앞서 설명한 예제와 같이 psakefile.ps1의 맨 위에는 여전히 Properties 블록을 유지해야하지만 PSake를 사용하면 값을 재정의할 수 있습니다.

그렇게 하려면, 각 키/값 쌍으로 해시테이블을 정의하십시오. 그런 다음, 해시테이블을 Properties 매개변수에 전달하십시오. PSake 엔진은 psakefile.ps1 스크립트 내의 Properties 블록에 지정된 값보다 전달된 해시테이블의 값을 사용합니다.

Properties 블록과 Properties 매개변수 사이의 구문 차이에 유의하십시오. Properties 블록에서 각 줄은 변수이므로 달러 기호로 시작되며, Properties 매개변수는 해시테이블이므로 각 항목은 키로 작성되며 선행하는 달러 기호가 없습니다. 또 다른 차이점은 해시테이블이 @ 문자로 시작된다는 것입니다.

아래에 Properties 매개변수를 사용하는 예시가 나와 있습니다.

$myNewProperties = @{
    SqlYear = '2019'
    SqlVersion = '15.0'
}

Invoke-PSake -TaskList DownloadSql -Properties $myNewProperties

PSake 작업 모듈화: 파일로 작업

언젠가는 PSake 파일이 매우 커져서 대규모 자동화 작업을 조율해야 할 수도 있습니다. 모든 작업을 관리할 수 있도록 하기 위해 모듈화 또는 작업을 분할하는 데 초점을 맞추어야 합니다.

관련: 지옥 같은 PowerShell 스크립트에서 Refactoring을 어떻게 생존할까요?

이 튜토리얼의 예시에서는 다섯 가지 작업을 다루었습니다:

  • ValidateDiskSpace
  • DownloadSql
  • ExtractSql
  • InstallSqlDriveC
  • InstallSqlDriveD

각 작업은 하나의 pssakefile.ps1 스크립트 내에 정의됩니다. 시간이 지남에 따라 더 많은 작업을 추가할 것으로 예상되면, 이러한 작업을 별도의 파일로 분할해야 합니다. 각 작업은 ValidateDiskSpace.ps1, DownloadSql.ps1, InstallSqlDriveD.ps1, InstallSqlDriveD.ps1 등과 같은 별도의 파일에 포함되어야 합니다.

예를 들어, InstallSqlDriveD.ps1 파일에는 다음 코드만 포함됩니다:

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

작업이 이동된 후에는 Include 함수를 사용하여 파일을 psakefile.ps1에 가져옵니다. 이 작업이 완료되면, psakefile.ps1은 다음 코드로 줄어듭니다:

$installSqlOn_C_Drive = $true
$installSqlOn_D_Drive = $false

Include "$PSScriptRoot\ValidateDiskSpace.ps1"
Include "$PSScriptRoot\DownloadSql.ps1"
Include "$PSScriptRoot\ExtractSql.ps1"
Include "$PSScriptRoot\InstallSqlOnC.ps1"
Include "$PSScriptRoot\InstallSqlOnD.ps1"

Invoke-PSake가 psakefile.ps1 스크립트를 트리거할 때, Invoke-PSake는 작업이 psake 파일 내에 있는지 아니면 Include 메소드로 가져온 것인지에 대해 알지도 신경쓰지도 않습니다.

다음 단계

PSake는 소프트웨어 빌드, CI/CD, 패키지 배포, 설치 프로그램 생성 등 다양한 목적으로 사용할 수 있는 강력한 스크립트 조정 도구입니다. 유일한 제한은 상상력입니다. PSake를 사용하여 대규모 스크립트를 작성하는 것에 익숙해지면, 작업(코드 빌딩 블록)으로 생각해야 하는 습관이 생깁니다. 작업의 개념은 PowerShell 구문을 활용하며, 작업을 사용함으로써 기존의 명령줄 지식을 향상시킬 수 있습니다.

PSake로 생성한 코드는 더 가독성이 좋고 유지보수가 용이하며 테스트하기도 쉽습니다. 약간의 추가 작업이 필요하지만 중장기적으로 큰 보상을 받을 수 있습니다.

PSake를 어떻게 업무 프로젝트에 활용할 계획이신가요?

Source:
https://adamtheautomator.com/powershell-psake/