PowerShell Write-Log: Ein einfaches Tutorial zur Protokollierung

Wenn Sie PowerShell-Skripte schreiben, die etwas Bedeutendes tun, benötigen Sie ein Protokoll. Egal, ob Sie Software bereitstellen, Dienste verwalten oder Aufgaben automatisieren, es ist entscheidend, eine Aufzeichnung darüber zu haben, was Ihr Skript getan (oder nicht getan) hat. In diesem Tutorial lernen Sie, wie Sie eine einfache, aber effektive PowerShell-Protokollierungsfunktion erstellen.

Voraussetzungen

Wenn Sie diesem Tutorial folgen möchten, stellen Sie sicher, dass Sie folgendes haben:

  • Windows 10 oder Windows Server mit PowerShell 5.1 oder PowerShell 7+
  • Einen Texteditor (VSCode empfohlen)
  • Grundlegendes Verständnis von PowerShell-Funktionen

Das Problem mit der einfachen Protokollierung

Angenommen, Sie schreiben ein Skript, um einige Software lautlos zu installieren. Der grundlegende Ansatz könnte so aussehen:

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."

Dies funktioniert, hat jedoch einige Probleme:

  • Keine Zeitstempel
  • Wiederholender Code
  • Unkonsistentes Protokollierungsformat
  • Festgelegter Protokollpfad

Beheben wir diese Probleme, indem wir eine richtige Protokollierungsfunktion erstellen.

Erstellen einer grundlegenden Write-Log-Funktion

Zunächst erstellen wir eine einfache Funktion, die Zeitstempel zu unseren Protokolleinträgen hinzufügt:

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"
}

Jetzt können Sie es wie folgt verwenden:

Write-Log -Message "Starting install..."
Start-Process -FilePath 'installer.exe' -ArgumentList '/i /s' -Wait -NoNewWindow
Write-Log -Message "Finished install."

Die Protokolldatei (C:\Scripts\script.log) enthält Einträge, die so aussehen:

09:42:15 - Starting install...
09:43:22 - Finished install.

Viel übersichtlicher! Aber wir können es noch besser machen.

Hinzufügen weiterer Funktionalitäten

Erweitern wir unsere Protokollierungsfunktion um einige nützliche Funktionen:

  • Benutzerdefinierte Protokollpfade
  • Verschiedene Protokollebene (Info, Warnung, Fehler)
  • Datum im Dateinamen
  • Fehlerbehandlung

Hier ist die verbesserte Version:

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: $_"
    }
}

Diese erweiterte Version bietet Ihnen viel mehr Flexibilität. So verwenden Sie sie:

# 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"

Die resultierende Protokolldatei (log-03-12-2024.txt) wird so aussehen:

10:15:22 [Information] - Starting software installation
10:15:23 [Warning] - Config file not found, using defaults
10:15:25 [Error] - Installation failed!

Und in D:\CustomLogs\log-03-12-2024.txt:

10:15:26 [Information] - Custom path log

Beachten Sie, wie jeder Eintrag den Zeitstempel, die Protokollebene in Klammern und die Nachricht enthält. Dieses strukturierte Format erleichtert das Parsen von Protokollen und das schnelle Erkennen von Problemen.

Echtweltbeispiel: Softwareinstallationsskript

Lassen Sie uns unsere Protokollierungsfunktion in einem echten Skript verwenden, das Software im Stillen installiert:

# 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"

Die resultierende Protokolldatei wird ungefähr so aussehen:

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

Nützliche Tipps

Hier sind einige bewährte Verfahren bei der Verwendung dieser Protokollierungsfunktion:

  1. Protokollieren Sie immer den Beginn und das Ende Ihres Skripts – Dies hilft, die Ausführungszeit des Skripts und den Abschlussstatus zu verfolgen.

  2. Verwenden Sie geeignete Protokollebene – Markieren Sie nicht alles als Fehler; verwenden Sie die richtige Ebene für die Situation:

    • Information: Normale Vorgänge
    • Warnung: Nicht kritische Probleme
    • Fehler: Kritische Probleme, die Aufmerksamkeit erfordern
  3. Relevante Details einbeziehen – Protokollieren Sie ausreichend Informationen, um zu verstehen, was passiert ist:

    # Schlecht
    Write-Log "Verbindung fehlgeschlagen"
    
    # Gut
    Write-Log "Verbindung mit Server 'SQL01' fehlgeschlagen - Timeout nach 30 Sekunden" -Level Fehler
    
  4. Alte Protokolle bereinigen – Erwägen Sie die Hinzufügung von Protokollrotation, um ein Überfüllen des Speicherplatzes zu verhindern:

    # Löschen von Protokollen, die älter als 30 Tage sind
    Get-ChildItem -Path $LogFilePath -Filter "*.txt" |
        Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
        Remove-Item
    

Abschluss

Eine gute Protokollierungsfunktion ist für jedes ernsthafte PowerShell-Skript unerlässlich. Mit der von uns erstellten Write-Log-Funktion haben Sie nun eine flexible und wiederverwendbare Möglichkeit, ordnungsgemäße Protokollierung zu all Ihren Skripten hinzuzufügen. Denken Sie daran, die Funktion an Ihre spezifischen Anforderungen anzupassen – Sie könnten Funktionen wie hinzufügen wollen:

Protokollrotation

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...
}

Verschiedene Ausgabeformate (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" }
    }
}

Unterstützung von Netzwerkpfaden

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-Mail-Benachrichtigungen für Fehler

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: $_"
        }
    }
}

Der Schlüssel ist, mit einer soliden Grundlage zu beginnen und basierend auf Ihren spezifischen Anforderungen darauf aufzubauen. Diese Beispiele sollten Ihnen einen guten Ausgangspunkt bieten, um die grundlegende Protokollierungsfunktion um fortgeschrittenere Funktionen zu erweitern.

Zum Beispiel könnten Sie mehrere dieser Funktionen in einer einzigen, umfassenden Protokollierungslösung kombinieren:

Write-Log -Message "Critical error in payment processing" `
          -Level Error `
          -Format CSV `
          -NetworkPath "\\\\server\\logs" `
          -NotifyOnError "[email protected]","[email protected]" `
          -MaxLogFiles 90

Dies würde:

  • Den Fehler im CSV-Format protokollieren
  • Auf einem Netzlaufwerk speichern
  • Mehrere Empfänger per E-Mail benachrichtigen
  • 90 Tage Protokollhistorie aufbewahren

Denken Sie daran, gründlich zu testen, insbesondere beim Implementieren von Netzwerkpfaden oder E-Mail-Benachrichtigungen, da diese externen Abhängigkeiten die Zuverlässigkeit Ihres Skripts beeinträchtigen können. Viel Spaß beim Skripten!

Source:
https://adamtheautomator.com/powershell-write-log-tutorial/