의미 있는 작업을 수행하는 PowerShell 스크립트를 작성하고 있다면, 로그 기록이 필요합니다. 소프트웨어를 배포하든, 서비스를 관리하든, 작업을 자동화하든, 스크립트가 수행한 작업(또는 수행하지 않은 작업)의 기록을 남기는 것은 매우 중요합니다. 이 튜토리얼에서는 간단하지만 효과적인 PowerShell 로그 기록 기능을 만드는 방법을 배웁니다.
필수 조건
이 튜토리얼을 따라 하려면 다음이 필요합니다:
- PowerShell 5.1 또는 PowerShell 7+가 설치된 Windows 10 또는 Windows Server
- 텍스트 편집기 (VSCode 추천)
- PowerShell 함수에 대한 기본 이해
기본 로그 기록의 문제
소프트웨어를 조용히 설치하는 스크립트를 작성하고 있다고 가정해보겠습니다. 기본 접근 방식은 다음과 같을 수 있습니다:
Add-Content -Path "C:\\Scripts\\install.log" -Value "Starting install..." Start-Process -FilePath 'installer.exe' -ArgumentList '/i /s' -Wait -NoNewWindow Add-Content -Path "C:\\Scripts\\install.log" -Value "Finished install."
이것은 작동하지만 몇 가지 문제가 있습니다:
- 타임스탬프 없음
- 반복적인 코드
- 일관되지 않은 로그 형식
- 하드코딩된 로그 경로
적절한 로그 기록 기능을 구축하여 이러한 문제를 해결해 봅시다.
기본 Write-Log 함수 구축
먼저, 로그 항목에 타임스탬프를 추가하는 간단한 함수를 만들어 보겠습니다:
function Write-Log { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Message ) $timeGenerated = Get-Date -Format HH:mm:ss Add-Content -Path "C:\\Scripts\\script.log" -Value "$timeGenerated - $Message" }
이제 이렇게 사용할 수 있습니다:
Write-Log -Message "Starting install..." Start-Process -FilePath 'installer.exe' -ArgumentList '/i /s' -Wait -NoNewWindow Write-Log -Message "Finished install."
로그 파일(C:\Scripts\script.log)에는 다음과 같은 항목이 포함됩니다:
09:42:15 - Starting install... 09:43:22 - Finished install.
훨씬 깔끔합니다! 하지만 더 나아질 수 있습니다.
기능 추가하기
유용한 기능으로 로그 기록 함수를 강화해 보겠습니다:
- 사용자 지정 로그 경로
- 다른 로그 레벨(정보, 경고, 오류)
- 파일 이름에 날짜
- 오류 처리
개선된 버전은 다음과 같습니다:
function Write-Log { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter()] [ValidateNotNullOrEmpty()] [string]$LogFilePath = "C:\\Scripts\\Logs", [Parameter()] [ValidateSet('Information','Warning','Error')] [string]$Level = "Information" ) # Create the log directory if it doesn't exist if (!(Test-Path $LogFilePath)) { New-Item -Path $LogFilePath -ItemType Directory -Force | Out-Null } # Build the log file path with date $date = Get-Date -Format "MM-dd-yyyy" $logFile = Join-Path $LogFilePath "log-$date.txt" # Get the current timestamp $timeStamp = Get-Date -Format "HH:mm:ss" # Create the log entry $logEntry = "$timeStamp [$Level] - $Message" try { Add-Content -Path $logFile -Value $logEntry -ErrorAction Stop } catch { Write-Error "Failed to write to log file: $_" } }
이 향상된 버전은 훨씬 더 유연성을 제공합니다. 사용 방법은 다음과 같습니다:
# Basic information logging Write-Log -Message "Starting software installation" # Warning about a non-critical issue Write-Log -Message "Config file not found, using defaults" -Level Warning # Log an error Write-Log -Message "Installation failed!" -Level Error # Use a custom log path Write-Log -Message "Custom path log" -LogFilePath "D:\\CustomLogs"
결과적인 로그 파일(log-03-12-2024.txt)은 다음과 같이 보입니다:
10:15:22 [Information] - Starting software installation 10:15:23 [Warning] - Config file not found, using defaults 10:15:25 [Error] - Installation failed!
그리고 D:\CustomLogs\log-03-12-2024.txt에서는 다음과 같습니다:
10:15:26 [Information] - Custom path log
각 항목이 타임스탬프, 대괄호 안의 로그 레벨 및 메시지를 포함하고 있는 것에 주목하세요. 이 구조화된 형식을 통해 로그를 구문 분석하고 빠르게 문제를 식별할 수 있습니다.
실제 예시: 소프트웨어 설치 스크립트
로그 기능을 실제로 사용하는 소프트웨어를 조용히 설치하는 스크립트에 적용해 봅시다:
# First, dot-source the logging function . .\\Write-Log.ps1 # Script variables $installer = "C:\\Installers\\software.exe" $logPath = "C:\\Scripts\\InstallLogs" # Start logging Write-Log -Message "Beginning installation process" -LogFilePath $logPath # Check if installer exists if (Test-Path $installer) { Write-Log -Message "Found installer at: $installer" try { # Attempt installation Write-Log -Message "Starting installation..." $process = Start-Process -FilePath $installer -ArgumentList '/i /s' -Wait -NoNewWindow -PassThru # Check the exit code if ($process.ExitCode -eq 0) { Write-Log -Message "Installation completed successfully" } else { Write-Log -Message "Installation failed with exit code: $($process.ExitCode)" -Level Error } } catch { Write-Log -Message "Installation failed with error: $_" -Level Error } } else { Write-Log -Message "Installer not found at: $installer" -Level Error } Write-Log -Message "Installation script completed"
결과적인 로그 파일은 다음과 같이 보일 것입니다:
09:15:22 [Information] - Beginning installation process 09:15:22 [Information] - Found installer at: C:\\Installers\\software.exe 09:15:22 [Information] - Starting installation... 09:16:45 [Information] - Installation completed successfully 09:16:45 [Information] - Installation script completed
유용한 팁
이 로깅 기능을 사용할 때 최상의 실천 방법은 다음과 같습니다:
-
스크립트 시작과 끝을 항상 로그에 남기세요 – 이렇게 하면 스크립트 실행 시간과 완료 상태를 추적할 수 있습니다.
-
적절한 로그 레벨을 사용하세요 – 모든 것을 오류로 표시하지 마세요. 상황에 맞는 올바른 레벨을 사용하세요:
- 정보: 정상적인 작업
- 경고: 중요하지 않은 문제
- 오류: 주의가 필요한 심각한 문제
-
관련 세부 정보 포함 – 발생한 일을 이해할 수 있는 정보를 기록하십시오:
# 나쁨 Write-Log "연결 실패" # 좋음 Write-Log "서버 'SQL01'에 연결 실패 - 30초 후 타임아웃" -Level Error
-
오래된 로그 정리 – 디스크 공간이 가득 차지 않도록 로그 회전 추가 고려:
# 30일 이전 로그 삭제 Get-ChildItem -Path $LogFilePath -Filter "*.txt" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | Remove-Item
결론
좋은 로깅 함수는 심각한 PowerShell 스크립트에 필수적입니다. 우리가 만든 Write-Log
함수로 이제 모든 스크립트에 적절한 로깅을 추가할 수 있는 유연하고 재사용 가능한 방법이 생겼습니다. 함수를 특정 요구 사항에 맞게 조정하는 것을 기억하십시오 – 로테이션과 같은 기능을 추가할 수도 있습니다:
로그 회전
function Write-Log { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter()] [int]$MaxLogFiles = 30 # Keep last 30 days of logs ) # Remove old log files Get-ChildItem -Path $LogFilePath -Filter "*.txt" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$MaxLogFiles) } | Remove-Item -Force # Continue with normal logging... }
다양한 출력 형식 (CSV, JSON)
function Write-Log { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter()] [ValidateSet('TXT','CSV','JSON')] [string]$Format = 'TXT' ) $logEntry = [PSCustomObject]@{ Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Level = $Level Message = $Message } switch ($Format) { 'CSV' { $logEntry | Export-Csv -Path "$LogFilePath\\log.csv" -Append -NoTypeInformation } 'JSON' { $logEntry | ConvertTo-Json | Add-Content -Path "$LogFilePath\\log.json" } 'TXT' { "$($logEntry.Timestamp) [$($logEntry.Level)] - $($logEntry.Message)" | Add-Content -Path "$LogFilePath\\log.txt" } } }
네트워크 경로 지원
function Write-Log { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter()] [string]$NetworkPath = "\\\\server\\logs" ) # Test network path connectivity if (!(Test-Path $NetworkPath)) { # Fallback to local logging if network is unavailable $NetworkPath = "C:\\Scripts\\Logs" Write-Warning "Network path unavailable. Using local path: $NetworkPath" } # Continue with normal logging... }
오류에 대한 이메일 알림
function Write-Log { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter()] [string]$SmtpServer = "smtp.company.com", [Parameter()] [string[]]$NotifyOnError = "[email protected]" ) # Normal logging first... # Send email if this is an error if ($Level -eq 'Error' -and $NotifyOnError) { $emailParams = @{ From = "[email protected]" To = $NotifyOnError Subject = "PowerShell Script Error" Body = "Error occurred at $timeStamp`n`nMessage: $Message" SmtpServer = $SmtpServer } try { Send-MailMessage @emailParams } catch { Write-Warning "Failed to send error notification: $_" } } }
중요한 것은 견고한 기반으로 시작하고 특정 요구 사항에 따라 더 나아가는 것입니다. 이 예시들은 더 발전된 기능을 추가하면서 기본 로깅 함수를 확장하는 좋은 시작점을 제공해야 합니다.
예를 들어, 이러한 여러 기능을 하나의 포괄적인 로깅 솔루션으로 결합할 수 있습니다:
Write-Log -Message "Critical error in payment processing" ` -Level Error ` -Format CSV ` -NetworkPath "\\\\server\\logs" ` -NotifyOnError "[email protected]","[email protected]" ` -MaxLogFiles 90
이것은:
- CSV 형식으로 오류 기록
- 네트워크 공유에 저장
- 여러 수신자에게 이메일 전송
- 90일의 로그 이력 유지
특히 네트워크 경로나 이메일 알림을 구현할 때는 철저하게 테스트하는 것을 잊지 마세요. 이러한 외부 의존성이 스크립트의 신뢰성에 영향을 미칠 수 있습니다. 스크립트 작업을 즐기세요!
Source:
https://adamtheautomator.com/powershell-write-log-tutorial/