Backup e pulizia Event logs con Powershell e WMI

Published 29 August 07 01:24 PM | claudiog 

Un problema abbastanza frequente (e noioso) in una rete Windows è la gestione degli Event Log, sia a fini di sicurezza vera e propria che per la "compliance" con le varie leggi (DPS & c.). Se è pur vero che un backup del System State di Windows include gli Event Logs, di certo il restore e loro consultazione sarebbe decisamente scomoda.

Ho scritto quindi questa script, per poter eseguire le operazioni di backup, eventualmente seguite da una pulizia del log stesso, di uno o più host Windows XP/Windows Server 2003 (non l'ho provato su Windows Vista nè su Windows Server 2008 Beta - anzi se avete feedback ...).

Il tutto si basa su Powershell e Windows Management Instrumentation (WMI), che presuppone che vi sia connettività verso gli host da gestire (accesi Wink e senza restrizioni di Firewall o limitazioni sull'account di connessione) e che la directory di destinazione dei backup sia presente in locale su ciascun nodo.
Infatti se è vero che questa script può connettersi a ciascun host, il metodo di backup invocato "BackupEventLog", prevede che la destinazione sia raggiungibile dal nodo target della invocazione. In linea teorica sarebbe possibile probabilmente usare un percorso UNC per consolidare tutti i log, ma alcune rapide prove mi hanno fatto soprassedere (almeno per ora!), l'aspetto di delegation/permission/rights non è banalissimo.

Analizziamo insieme la script BackClear-EvtLogs.ps1,disponibile per il download.

param(
  [string] $MyLog='*',            # Any log
  [boolean] $MyClearFlag=$False,  # Don't clear
  [array] $MyComputer=@( '.' )    # LocalComputer
)

I parametri in ingresso, tutti opzionali servono a definire:

  1. il nome del file di log su cui vogliamo agire (Es: Application, 'Windows Powershell', Security)
    • se lasciamo vuoto o specifichiamo '*', faremo l'operazione su tutti i file di log
  2. se vogliamo o meno pulire il log, dopo il corretto backup
  3. la lista dei computer (Array con elementi separate da virgole) su cui eseguire l'operazione
    • se lasciamo vuoto o specifichiamo '.' eseguiremo sul computer locale, in puro stile WMI

set-variable MyDir 'D:\NoBdata\LogFiles.Bak\' -option constant -scope local

if ( $MyLog -eq '*') {
  $MyQuery = ''
} else {
  $MyQuery = " WHERE LogFileName='$MyLog'"
}

# ANSI date format, good for sorting
$local:strDate = Get-Date -Format 'yyyyMMdd'

Prepariamo un pò di costanti/variabili per la successiva elaborazione; in particolare viene definito come Costante (magari sarebbe più utile un altro parametro ?) il path di salvataggio dei Log e costruita una porzione della Query WMI, in base alla presenza o meno del parametro che specifica il nome del file di log.

Quindi iniziamo una iterazione sull'array dei nomi computer (eventualmente con il solo elemento '.'), che per ciascun nodo istanzia un oggetto WMI ed estrae il/gli oggetti Event Log; nidificato a questo vi è un'altro 'foreach' su ciascun Event Log, per eseguirne il backup, su un file che avrà il nome computer/la data in formato ANSI/il nome log come parti varianti.
Se eseguito con successo il backup (i codici di errore sono su MSDN), allora procederà alla cancellazione del log, se richiesto.

$MyComputer | % {    # For each Computer
  $local:strComputer = $_
  Get-WmiObject -computername $strComputer -namespace 'root/cimv2' -query "SELECT * FROM Win32_NTEventLogFile $MyQuery" | % {
    # For each Log
    $local:strLog = $_.LogFileName
    $_.PSBase.Scope.Options.EnablePrivileges = $True

    if ( $strComputer -eq '.') {
      $strComputer = $env:computername
    }
    $local:MyErr = ($_.BackupEventLog("$MyDir$strComputer.$strDate.$strLog.evt")).ReturnValue
    If ($MyErr -ne 0) {
      write-warning "The '$strLog' event log from '$strComputer' could not be backed up. ($MyErr)"
    } Else {
      if ( $MyClearFlag) {
        $MyErr = $_.ClearEventLog().ReturnValue
        if ( $MyErr -ne 0) {
            write-warning "The '$strLog' event log from '$strComputer' could not be cleared. ($MyErr)"
        }
      }
    }
  }
}

La script può quindi essere invocata ad esempio con:

.\BackClear-EvtLogs.ps1

.\BackClear-EvtLogs.ps1 'Security' $False '.','Server1','ServerSql'

.\BackClear-EvtLogs.ps1 '*' $True 'MyServer.dominio.local'

 

Punti aperti o argometi da valutare:

  1. Se avvengono Eventi tra il Backup ed il Clear ... potremmo perdere eventi, ma la finestra temporale dovrebbe essere davvero piccola. Comunque si potrebbe intercettare la cosa, valutando la proprietà NumberOfRecords prima e dopo il backup.
  2. Bisogna creare PRIMA la directory su ciascun nodo (codice errore 3)
  3. Se il file esiste gà, andrà in errore (codice errore 183 su XP e Windows 2003)
  4. Non c'è gestione delle eccezioni (Es: se il nodo è spento o irraggiungibile, l'account usato non ha i privilegi, ...)
  5. La directory di destinazione a lungo andare si riempirà, non c'è gestione del recycling. Si può mitigare usando NTFS compression, dato che i Log sono ben comprimibili

Non resta che schedulare questo task, magari con una esecuzione notturna giornaliera dei backup senza pulizia, ed una settimanale con anche il clear, semplicemente cambiando l'invocazione della script.

Graditi feedback.

Ciao, Claudio

Filed under: ,
Anonymous comments are disabled

About claudiog

MCSA, MCSE, MCT su NT/2000/2003