如果您正在編寫有意義的 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/