Pide tu presupuesto ya!
Si está escribiendo scripts de PowerShell que hacen algo significativo, necesita iniciar sesión. Ya sea que esté implementando software, administrando servicios o automatizando tareas, tener un registro de lo que hizo (o no hizo) su script es crucial. En este tutorial, aprenderá cómo crear una función de registro de PowerShell simple pero efectiva.
Si desea seguir este tutorial, asegúrese de tener:
Digamos que estás escribiendo un script para instalar silenciosamente algún software. El enfoque básico podría verse así:
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."
Esto funciona, pero tiene algunos problemas:
Solucionemos estos problemas creando una función de registro adecuada.
Primero, creemos una función simple que agregue marcas de tiempo a nuestras entradas de registro:
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"
}
Ahora puedes usarlo así:
Write-Log -Message "Starting install..." Start-Process -FilePath 'installer.exe' -ArgumentList '/i /s' -Wait -NoNewWindow Write-Log -Message "Finished install."
El archivo de registro (C:\Scripts\script.log) contendrá entradas similares a:
09:42:15 - Starting install... 09:43:22 - Finished install.
¡Mucho más limpio! Pero podemos hacerlo mejor.
Mejoremos nuestra función de registro con algunas características útiles:
Aquí está la versión mejorada:
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: $_"
}
}
Esta versión mejorada le brinda mucha más flexibilidad. Aquí se explica cómo usarlo:
# 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"
El archivo de registro resultante (log-03-12-2024.txt) tendrá este aspecto:
10:15:22 [Information] - Starting software installation 10:15:23 [Warning] - Config file not found, using defaults 10:15:25 [Error] - Installation failed!
Y en D:\CustomLogs\log-03-12-2024.txt:
10:15:26 [Information] - Custom path log
Observe cómo cada entrada incluye la marca de tiempo, el nivel de registro entre paréntesis y el mensaje. Este formato estructurado facilita el análisis de registros e identifica rápidamente problemas.
Pongamos nuestra función de registro a funcionar en un script real que instala el software de forma silenciosa:
# 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"
El archivo de registro resultante se verá así:
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
Estas son algunas de las mejores prácticas al utilizar esta función de registro:
Registre siempre el inicio y el final de su script – Esto ayuda a realizar un seguimiento del tiempo de ejecución del script y del estado de finalización.
Utilice niveles de registro apropiados – No marques todo como error; Utilice el nivel adecuado para la situación:
Incluir detalles relevantes – Registre suficiente información para comprender lo que sucedió:
# Bad Write-Log "Failed to connect" # Good Write-Log "Failed to connect to server 'SQL01' - timeout after 30 seconds" -Level Error
Limpiar registros viejos – Considere agregar rotación de registros para evitar llenar el espacio en disco:
# Delete logs older than 30 days
Get-ChildItem -Path $LogFilePath -Filter "*.txt" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Remove-Item
Una buena función de registro es esencial para cualquier script de PowerShell serio. Con el Write-Log función que hemos creado, ahora tiene una forma flexible y reutilizable de agregar el registro adecuado a todos sus scripts. Recuerde adaptar la función a sus necesidades específicas; es posible que desee agregar funciones como:
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...
}
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: $_"
}
}
}
La clave es comenzar con una base sólida y desarrollarla a partir de ahí en función de sus necesidades específicas. Estos ejemplos deberían brindarle un buen punto de partida para ampliar la función de registro básica con funciones más avanzadas.
Por ejemplo, puede combinar varias de estas funciones en una única solución de registro integral:
Write-Log -Message "Critical error in payment processing" `
-Level Error `
-Format CSV `
-NetworkPath "\\\\server\\logs" `
-NotifyOnError "[email protected]","[email protected]" `
-MaxLogFiles 90
Esto sería:
Recuerde realizar pruebas exhaustivas, especialmente al implementar rutas de red o notificaciones por correo electrónico, ya que estas dependencias externas pueden afectar la confiabilidad de su script. ¡Feliz guión!
Leave a comment