Als u PowerShell-scripts schrijft die iets betekenisvols doen, heeft u logging nodig. Of u nu software implementeert, services beheert of taken automatiseert, een logboek bijhouden van wat uw script heeft gedaan (of niet heeft gedaan) is cruciaal. In deze zelfstudie leert u hoe u een eenvoudige maar effectieve PowerShell-loggingfunctie kunt maken.
Vereisten
Als u deze zelfstudie wilt volgen, zorg er dan voor dat u beschikt over:
- Windows 10 of Windows Server met PowerShell 5.1 of PowerShell 7+
- Een teksteditor (VSCode aanbevolen)
- Basiskennis van PowerShell-functies
Het Probleem met Basislogging
Laten we zeggen dat u een script schrijft om stil software te installeren. De basisaanpak zou er ongeveer zo uitzien:
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."
Dit werkt, maar het heeft enkele problemen:
- Geen tijdstempels
- Herhaalde code
- Onconsistente loggingindeling
- Hardgecodeerd logboekpad
Laten we deze problemen oplossen door een juiste loggingfunctie te bouwen.
Het Bouwen van een Basis Write-Log Functie
Laten we eerst een eenvoudige functie maken die tijdstempels toevoegt aan onze logboekvermeldingen:
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" }
Nu kunt u het als volgt gebruiken:
Write-Log -Message "Starting install..." Start-Process -FilePath 'installer.exe' -ArgumentList '/i /s' -Wait -NoNewWindow Write-Log -Message "Finished install."
Het logbestand (C:\Scripts\script.log) bevat vermeldingen die eruitzien als:
09:42:15 - Starting install... 09:43:22 - Finished install.
Veel schoner! Maar we kunnen het nog beter doen.
Meer Functionaliteit Toevoegen
Laten we onze loggingfunctie verbeteren met enkele nuttige functies:
- Aangepaste logboekpaden
- Verschillende logniveaus (Info, Waarschuwing, Fout)
- Datum in bestandsnaam
- Foutafhandeling
Hier is de verbeterde versie:
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: $_" } }
Deze verbeterde versie geeft je veel meer flexibiliteit. Zo gebruik je het:
# 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"
Het resulterende logbestand (log-03-12-2024.txt) zal er zo uitzien:
10:15:22 [Information] - Starting software installation 10:15:23 [Warning] - Config file not found, using defaults 10:15:25 [Error] - Installation failed!
En in D:\CustomLogs\log-03-12-2024.txt:
10:15:26 [Information] - Custom path log
Merk op hoe elke vermelding de tijdstempel, logniveau tussen haakjes en de boodschap bevat. Dit gestructureerde formaat maakt het gemakkelijk om logs te analyseren en snel problemen te identificeren.
Praktijkvoorbeeld: Software-installatiescript
Laten we onze logfunctie aan het werk zetten in een echt script dat software stil installeert:
# 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"
Het resulterende logbestand zal er ongeveer zo uitzien:
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
Nuttige tips
Hier zijn enkele beste praktijken bij het gebruik van deze logfunctie:
-
Log altijd het begin en het einde van je script – Dit helpt bij het bijhouden van de scriptuitvoeringstijd en de voltooiingsstatus.
-
Gebruik passende logniveaus – Markeer niet alles als een fout; gebruik het juiste niveau voor de situatie:
- Informatie: Normale operaties
- Waarschuwing: Niet-kritieke problemen
- Fout: Kritieke problemen die aandacht vereisen
-
Inclusief relevante details – Log voldoende informatie om te begrijpen wat er is gebeurd:
# Slecht Write-Log "Verbinden mislukt" # Goed Write-Log "Verbinden mislukt met server 'SQL01' - time-out na 30 seconden" -Level Error
-
Oude logs opruimen – Overweeg logrotatie toe te voegen om te voorkomen dat de schijfruimte vol raakt:
# Verwijder logs ouder dan 30 dagen Get-ChildItem -Path $LogFilePath -Filter "*.txt" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | Remove-Item
Conclusie
Een goede logfunctie is essentieel voor elk serieus PowerShell-script. Met de Write-Log
functie die we hebben gebouwd, heb je nu een flexibele en herbruikbare manier om goede logging aan al je scripts toe te voegen. Vergeet niet de functie aan te passen aan je specifieke behoeften – je wilt misschien functies toevoegen zoals:
Logrotatie
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... }
Verschillende uitvoerformaten (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" } } }
Ondersteuning voor netwerkpaden
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... }
E-mailmeldingen voor fouten
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: $_" } } }
De sleutel is om te beginnen met een solide basis en daarbovenop verder te bouwen op basis van je specifieke behoeften. Deze voorbeelden zouden je een goed startpunt moeten geven voor het uitbreiden van de basislogfunctie met meer geavanceerde functies.
Bijvoorbeeld, je zou verschillende van deze functies kunnen combineren in een enkele, allesomvattende logging-oplossing:
Write-Log -Message "Critical error in payment processing" ` -Level Error ` -Format CSV ` -NetworkPath "\\\\server\\logs" ` -NotifyOnError "[email protected]","[email protected]" ` -MaxLogFiles 90
Dit zou:
- De fout loggen in CSV-indeling
- Het opslaan op een netwerkshare
- Meerdere ontvangers e-mailen
- 90 dagen aan logboekgeschiedenis bijhouden
Vergeet niet grondig te testen, vooral bij het implementeren van netwerkpaden of e-mailmeldingen, aangezien deze externe afhankelijkheden de betrouwbaarheid van je script kunnen beïnvloeden. Veel scriptplezier!
Source:
https://adamtheautomator.com/powershell-write-log-tutorial/