PowerShell Schrijf-Log: Een Eenvoudige Logging Functie Tutorial

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:

  1. Log altijd het begin en het einde van je script – Dit helpt bij het bijhouden van de scriptuitvoeringstijd en de voltooiingsstatus.

  2. 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
  3. 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
    
  4. 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/