Se stai scrivendo script PowerShell che fanno qualcosa di significativo, hai bisogno di logging. Sia che tu stia distribuendo software, gestendo servizi o automatizzando compiti, avere un registro di ciò che il tuo script ha fatto (o non ha fatto) è cruciale. In questo tutorial, imparerai come creare una semplice ma efficace funzione di logging in PowerShell.
Prerequisiti
Se desideri seguire questo tutorial, assicurati di avere:
- Windows 10 o Windows Server con PowerShell 5.1 o PowerShell 7+
- Un editor di testo (si consiglia VSCode)
- Una comprensione di base delle funzioni di PowerShell
Il Problema con il Logging di Base
Supponiamo che tu stia scrivendo uno script per installare silenziosamente del software. L’approccio di base potrebbe apparire così:
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."
Funziona, ma ha alcuni problemi:
- Nessun timestamp
- Codice ripetitivo
- Formato di logging incoerente
- Percorso di log hard-coded
Risolveremo questi problemi costruendo una funzione di logging adeguata.
Costruire una Funzione Write-Log di Base
Prima di tutto, creiamo una semplice funzione che aggiunge timestamp alle nostre voci di 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" }
Ora puoi usarla in questo modo:
Write-Log -Message "Starting install..." Start-Process -FilePath 'installer.exe' -ArgumentList '/i /s' -Wait -NoNewWindow Write-Log -Message "Finished install."
Il file di log (C:\Scripts\script.log) conterrà voci che appariranno così:
09:42:15 - Starting install... 09:43:22 - Finished install.
Molto più pulito! Ma possiamo fare di meglio.
Aggiungere Maggiore Funzionalità
Miglioriamo la nostra funzione di logging con alcune funzionalità utili:
- Percorsi di log personalizzati
- Diversi livelli di log (Info, Avviso, Errore)
- Data nel nome del file
- Gestione degli errori
Ecco la versione migliorata:
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: $_" } }
Questa versione potenziata ti offre molta più flessibilità. Ecco come utilizzarla:
# 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"
Il file di log risultante (log-03-12-2024.txt) avrà questo aspetto:
10:15:22 [Information] - Starting software installation 10:15:23 [Warning] - Config file not found, using defaults 10:15:25 [Error] - Installation failed!
E in D:\CustomLogs\log-03-12-2024.txt:
10:15:26 [Information] - Custom path log
Nota come ogni voce include il timestamp, il livello di log tra parentesi e il messaggio. Questo formato strutturato facilita l’analisi dei log e l’identificazione rapida dei problemi.
Esempio concreto: Script di installazione del software
Mettiamo a lavoro la nostra funzione di logging in uno script reale che installa il software in modo silenzioso:
# 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"
Il file di log risultante avrà un aspetto simile a questo:
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
Suggerimenti utili
Ecco alcuni consigli utili per l’utilizzo di questa funzione di logging:
-
Registra sempre l’inizio e la fine dello script – Questo aiuta a tracciare il tempo di esecuzione dello script e lo stato di completamento.
-
Utilizza i livelli di log appropriati – Non contrassegnare tutto come errore; utilizza il livello corretto per la situazione:
- Informazioni: Operazioni normali
- Avviso: Problemi non critici
- Errore: Problemi critici che richiedono attenzione
-
Includi dettagli rilevanti – Registra sufficienti informazioni per capire cosa è successo:
# Cattivo Write-Log "Impossibile connettersi" # Buono Write-Log "Impossibile connettersi al server 'SQL01' - timeout dopo 30 secondi" -Level Error
-
Pulisci i vecchi log – Considera di aggiungere la rotazione dei log per evitare di riempire lo spazio su disco:
# Elimina i log più vecchi di 30 giorni Get-ChildItem -Path $LogFilePath -Filter "*.txt" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | Remove-Item
Conclusione
Una buona funzione di logging è essenziale per qualsiasi script PowerShell serio. Con la funzione Write-Log
che abbiamo costruito, ora hai un modo flessibile e riutilizzabile per aggiungere un logging adeguato a tutti i tuoi script. Ricorda di adattare la funzione alle tue esigenze specifiche – potresti voler aggiungere funzionalità come:
Rotazione dei 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... }
Formati di Output Differenti (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" } } }
Supporto per Percorsi di Rete
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... }
Notifiche via Email per Errori
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: $_" } } }
La chiave è partire da una base solida e costruire da lì in base alle tue esigenze specifiche. Questi esempi dovrebbero darti un buon punto di partenza per estendere la funzione di logging di base con funzionalità più avanzate.
Ad esempio, potresti combinare diverse di queste funzionalità in una singola, soluzione di logging completa:
Write-Log -Message "Critical error in payment processing" ` -Level Error ` -Format CSV ` -NetworkPath "\\\\server\\logs" ` -NotifyOnError "[email protected]","[email protected]" ` -MaxLogFiles 90
Questo permetterebbe di:
- Registrare l’errore in formato CSV
- Archiviarlo in una condivisione di rete
- Inviare e-mail a più destinatari
- Mantenere un registro storico di 90 giorni
Ricordati di testare attentamente, specialmente quando si implementano percorsi di rete o notifiche via email, poiché queste dipendenze esterne possono influire sulla affidabilità dello script. Buona scrittura di script!
Source:
https://adamtheautomator.com/powershell-write-log-tutorial/