Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Wednesday, November 7, 2012

Backup event logs on multiple servers with PowerShell

This PowerShell cmdlet was developed for my PowerShell class in Miami.  This is very specific to their needs.  The requirement was to be able to backup event logs from multiple servers to a single location.  The logs needed to be saved in a folder structure of Year/Month.  They also needed an option to clear the log.  This was a fun one, but complex so I took it on.

It is designed as a function so you can add it to a custom library.

Function Backup-EventLog
{
[CmdletBinding(HelpUri = 'http://get-help-jason-yoder.blogspot.com/2012/10/backup-eventlog.html')]
Param(
    [Parameter(Mandatory=$True)][String[]]$ComputerName,
    [Parameter(Mandatory=$True)]$LogFiles,
    [Parameter(Mandatory=$True)][String]$Path,
    [Switch]$ClearLog,
    [Switch]$Quiet
)

    # Support Function: Write-Info --------------------------------------------
    # Provides pre-defined color formatting for text output.
    Function Write-Info
    {
    Param (
        $String,
        $Color,
        $Width = 80,
        $Quiet,
        [Switch]$NoWidth
    )

        If ($Quiet -eq $False)
        {
            # Get the width of the text.
            $StringWidth = $String.length

            If (($StringWidth -lt $Width) -and ($NoWidth -eq $False))
            {
                For ($X = $StringWidth;$X -le $Width; $X++)
                {
                    $String += " "
                }
            }

            Switch ($Color)
            {
            # Green Font
            "G1" {Write-Host $String -ForegroundColor Green `
                                     -BackgroundColor DarkGreen}
            "G2" {Write-Host $String -ForegroundColor DarkGreen `
                                     -BackgroundColor Green}
            "G3" {Write-Host $String -ForegroundColor Green `
                                     -BackgroundColor DarkBlue}
            "G4" {Write-Host $String -ForegroundColor Green `
                                     -BackgroundColor Black}
            "G5" {Write-Host $String -ForegroundColor Green}
       
            # Yellow Font
            "Y1" {Write-Host $String -ForegroundColor Yellow `
                                     -BackgroundColor DarkGray}
            "Y2" {Write-Host $String -ForegroundColor DarkGray `
                                     -BackgroundColor Yellow}
            "Y3" {Write-Host $String -ForegroundColor Yellow `
                                     -BackgroundColor DarkBlue}
            "Y4" {Write-Host $String -ForegroundColor Yellow `
                                     -BackgroundColor Black}
            "Y5" {Write-Host $String -ForegroundColor Yellow}
       
            # Red Font
            "R1" {Write-Host $String -ForegroundColor Red `
                                     -BackgroundColor DarkRed}
            "R2" {Write-Host $String -ForegroundColor DarkRed `
                                     -BackgroundColor Red}
            "R3" {Write-Host $String -ForegroundColor Red `
                                     -BackgroundColor DarkBlue}
            "R4" {Write-Host $String -ForegroundColor Red `
                                     -BackgroundColor Black}
            "R5" {Write-Host $String -ForegroundColor Red}       
       
            # Cyan Font
            "C1" {Write-Host $String -ForegroundColor Cyan `
                                     -BackgroundColor DarkCyan}
            "C2" {Write-Host $String -ForegroundColor DarkCyan `
                                     -BackgroundColor Cyan}
            "C3" {Write-Host $String -ForegroundColor Cyan `
                                     -BackgroundColor DarkBlue}
            "C4" {Write-Host $String -ForegroundColor Cyan `
                                     -BackgroundColor Black}
            "C5" {Write-Host $String -ForegroundColor Cyan}
       
            # White Font
            "W1" {Write-Host $String -ForegroundColor White `
                                     -BackgroundColor DarkGray}
            "W2" {Write-Host $String -ForegroundColor DarkGray `
                                     -BackgroundColor White}
            "W3" {Write-Host $String -ForegroundColor White `
                                     -BackgroundColor DarkBlue}
            "W4" {Write-Host $String -ForegroundColor White `
                                     -BackgroundColor Black}
            "W5" {Write-Host $String -ForegroundColor White}
       
            # Blue Font
            "B1" {Write-Host $String -ForegroundColor Blue 1 `
                                     -BackgroundColor DarkBlue}
            "B2" {Write-Host $String -ForegroundColor Gray `
                                     -BackgroundColor Blue}
            "B3" {Write-Host $String -ForegroundColor Blue `
                                     -BackgroundColor DarkBlue}
            "B4" {Write-Host $String -ForegroundColor Blue `
                                     -BackgroundColor Black}
            "B5" {Write-Host $String -ForegroundColor Blue}      
            }
        }
    }
    # End: Write-Info ---------------------------------------------------------

    # Support Function: Get-EventLogInfo --------------------------------------
    # Returns the event log file information from the target computer.
    Function Get-EventLogInfo
    {
    Param (
        $ComputerName
    )
       
        $Info = Get-WmiObject Win32_NTEventLogFile -ComputerName $ComputerName
        Write-Output $Info
    }

    # End: Get-EventLogInfo ---------------------------------------------------

    # Support Function: Create-FolderStructure --------------------------------
    # Creates the folder structure
    Function Create-FolderStructure
    {
    Param(
        $Path
    )
        [String]$DateString = $Path + "\" + ((Get-Date).Year).ToString() + `
            "\" + ((Get-Date).Month).ToString()

        If ((Test-Path $DateString) -ne $True)
        {
            Try
            {
                New-Item -Path $DateString -ItemType Directory -ErrorAction Stop
               
            }
            Catch
            {
                Write-Host "Cannot create folder." -ForegroundColor Red
                Write-Host  "You may not have neccessary permissions" `
                    -ForegroundColor Red
                Break
            }
        }
        Write-Output $DateString
      
    }
    # End: Create-FolderStructure ---------------------------------------------


    # If the user specified a credential, create a PSCredential object
    If ($Credential -ne $Null)
    {
        $CredObject = Get-Credential `
         -UserName $Credential `
         -Message "Provide the credentials of a user who can clear the Security Log"
   
        $CredObject | FL *
    }


    # Test to see if the account being used has admin rights.  Notify the user
    # if they do not.
    $isAdmin = (new-object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole("Administrators")
    If ($IsAdmin -eq $False)
    {
        Write-Info "Cmdlet not being executed as an Administrator." -Color Y1 -Quiet $Quiet
        Write-Info "You may not be able to backup all event logs." -Color Y1 -Quiet $Quiet
    }

    # Test to see if the backup location is online
    If (Test-Path -Path $Path)
    {
        Write-Info "Backup Storage is online" -Color G1 -Quiet $Quiet
        # Out-Null will supress unnessessary text.
        Create-FolderStructure $Path | Out-Null
    }
    Else
    {
        Write-Info "Backup storage is not online" -Color R1 -Quiet $Quiet
        Write-Info "Terminating Operation" -Color R1 -Quiet $Quiet
        Break
    }

    # Create the folder structure. Return the path to be
    # used for backing up the logs.
    $DateString = Create-FolderStructure -Path $Path

    # Create the date/time stamp to be added to the
    # names of the backed up logs. This format will be appended to the
    # end of the log file name as -Hour-Minute.evtx.
    [String]$NameString = "-" + ((Get-Date).Day).ToString() + `
        "-" + ((Get-Date).Hour).ToString() + `
        "-" + ((Get-Date).Minute).ToString() + ".evtx"

    # Create an array to hold the Objects from this cmdlet.
    # As the cmdlet cycles through each computer, it will add the objects
    # created to this array.  This array will be sent to the pipeline
    # once the ComputerName list has been depleted.
    $FinalObj = @()


   
    # Cycle through each computer and examine the logs.
    ForEach ($Computer in $ComputerName)
    {

   
        # Inform the user which computer is being anaylised.
        Write-Info "Connecting to $Computer." -Color W1 -Quiet $Quiet
       
        # Test for a connection to the computer.
        $ConnectionMade = $False
        $Connection = Test-Connection -ComputerName $Computer -Count 1 -Quiet

        If ($Connection)
        {
             $ConnectionMade = $True
        }
        Else
        {
            Write-Info "PING attempt to $Computer failed" -Color R2 -Quiet $Quiet
           
            # Create an object to hold the data for this computer.
            $Obj = New-Object -TypeName PSObject
       
            # Add the Server Name to the object.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "ComputerName" `
                -Value $Computer
           
            # Add the online property.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "Online" `
                -Value $False
       
            # Add object properties for each log and the data to be recorded
            # from each log.
            ForEach ($Log in $LogFiles)
            {
                # Create the property names.
                $Exists = $Log+"_Exists"
                $Backedup = $Log+"_BackedUp"
                $Cleared = $Log+"_Cleared"
                # Create the properties in the object
                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Exists `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $BackedUp `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Cleared `
                    -Value $False   
               
                $FinalObj += $Obj            
       
            } # End: ForEach ($Log in $LogFiles)
        } # End: Else
       
        If ($ConnectionMade)
        {
            Write-Info "Connection Established" -Color G1  -Quiet $Quiet
          

            # Create an object to hold the data for this computer.
            $Obj = New-Object -TypeName PSObject
       
            # Add the Server Name to the object.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "ComputerName" `
                -Value $Computer

            # Add the online property.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "Online" `
                -Value $True
                       
            # Add object properties for each log and the data to be recorded
            # from each log.
            ForEach ($Log in $LogFiles)
            {
                # Create the property names.
                $Exists = $Log+"_Exists"
                $Backedup = $Log+"_BackedUp"
                $Cleared = $Log+"_Cleared"

                # Create the properties in the object
                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Exists `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $BackedUp `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Cleared `
                    -Value $False            
       
            } # End: ForEach ($Log in $LogFiles)

            # Retrieve the event log data from the target client.      

            $EventLogData = Get-EventLogInfo -ComputerName $Computer


            # Determine if a log exists.
            ForEach ($Log in $LogFiles)
            {

                ForEach ($EventLog in $EventLogData)
                {
                    If ($EventLog.LogFileName -eq $Log)
                    {
                        $Exists = $Log+"_Exists"
                        $Obj.$Exists = $True          
                       
                        # Move the event log.
                        Try
                        {
                            Copy-Item -Path $EventLog.Name `
                             -Destination $DateString `
                             -ErrorAction Stop `
                             -ErrorVariable Test
                        }
                        Catch
                        {
                            If ($Error[0] -like "*Access to the path*is denied.*")
                                {
                                    Write-Info "You do not have sufficent rights to copy log file: $Log" `
                                     -Color R1 `
                                     -Quiet $Quiet
                                    Write-Info "Re-run this Backup-EventLog with elevated credentials" `
                                     -Color R1 `
                                     -Quiet $Quiet
                                }
                        }
                       
                        # Test to see if the copy was successful.
                        $TestPath = "$DateString\$Log.evtx"
                       
                       
                        If (Test-Path $TestPath)
                        {
                       
                            $Backedup = $Log+"_BackedUp"
                            $Obj.$BackedUp = $True

                            # Rename the file.
                            $NewName = $Computer + "-" + $Log+$NameString
                            Try
                            {
                               
                                Rename-Item -Path $TestPath `
                                 -NewName $NewName `
                                 -ErrorAction Stop
                                
                                
                            }
                            Catch
                            {
                                Write-Info "Rename not successful on $Log" -Color R1  -Quiet $Quiet
                                Write-Info "Action on your part may be neccessary" -Color R1  -Quiet $Quiet
                                Write-Info "This may be caused by executing this cmdlet" -Color R1  -Quiet $Quiet
                                Write-Info "more than once a minute." -Color R1  -Quiet $Quiet
                               
                                # Remove the Backup.
                                Remove-Item -Path $TestPath -Force
                               
                                # Reset the Backup flag to False.
                                $Obj.$BackedUp = $False
                               
                                $Success = $False
                            }

                            Write-Info "Completed attempt to backup $Log" "$ClearLog" -Color G3 -Quiet $Quite
                        } # End: If (Test-Path $TestPath)
                    
                      
                       # Clear the event log if necessary.
                       Write-Info "Clearing log: $Log" -Color C3 -Quiet $Quite


                       If (($ClearLog -eq $True) -and ($Obj.$Backedup -eq $True))
                       {
                       
                           Write-Info "Clearing log: $Log" -Color C3 -Quiet $Quite
                          
                           # use the WMI Method for
                           # Win32_NTEvenltLogFile.ClearEventLog()
                           # to clear the event long.  The Out-Null
                           # cmdlet suppresses information that would
                           # be displaced from the ClearEventLog() method.
                           $EventLog.ClearEventLog() | Out-Null
                                              

                           # Set the $Log_Cleared property to $True.
                           $Cleared = $Log+"_Cleared"
                           $Obj.$Cleared = $True

                       } # End: If ($ClearLog)



                    } # End: If ($EventLog.LogFileName -eq $Log)
                } # End: ForEach ($EventLog in $EventLogData)
            } # End: ForEach ($Log in $LogFiles)
        } # End: If ($ConnectionMade)       
        Else
        {
            Write-Info "$Computer is offline" -Color R1  -Quiet $Quiet
        } # End: Else (Test-Connection -ComputerName $Computer -Count 2)

        # Write the data to the FinalObj
        If ($Connection) {$FinalObj += $Obj}

        # Inform the user that the cmdlet has finished working on
        # a client.
        Write-Info "Completed backup attempt for $Computer" -Color G3  -Quiet $Quiet
    } # End: ForEach ($Computer in $ComputerName)

    # Send the data to the PowerShell pipeline.
    Write-Output $FinalObj | Select-Object -Unique -Property *

<#
.SYNOPSIS
Allows for the backing up and clearing of event logs.

.DESCRIPTION
Allows for the backing up and clearing of multiple event logs on multiple
Clients and Servers.  The event logs will be copied to the location
specified in the PATH parameter.  The cmdlet will automatically
create a file structure for Year and then month. 

The backed up files Names will have the format
Server-Log-Day-Hour-Minute to help denote separate backups
in the Month folders.

Logs are not cleared unless the CLEAR switch is invoked.

To work with the Security Log, the user must be running PowerShell
As an Administrator.


.PARAMETER ClearLog
Clears the log if the backup was successful.

.PARAMETER ComputerName
List of computer names in which to attempt a backup of event log data.

.PARAMETER LogFiles
List of all event logs to attempt to backup.

.PARAMETER Path
The root destination path to store the backup logs in.

.PARAMETER Quiet
Suppresses all information and warning messages.

.NOTES
===============================================================================
Copyright 2012 MCTExpert, Inc.

This script is provided without support, warranty, or guarantee.
User assumes all liability for cmdlet results.
===============================================================================

.EXAMPLE
 Backup-EventLog -ComputerName Indy-DC1 -LogFiles Security, Application -Path f:\Logs

 Backs up the Security and Application Logs from server Indy-DC1 to the path f:\Logs.

.EXAMPLE
Backup-EventLog -ComputerName Indy-DC1, Indy-CLI1, LON-SVR2 -LogFiles System -Path "\\LON-SVR1\Logs" -ClearLog| Where-Object {$_.online -eq $True}

ComputerName    : Indy-DC1
Online          : True
System_Exists   : True
System_BackedUp : True
System_Cleared  : True

ComputerName    : Indy-SVR2
Online          : True
System_Exists   : True
System_BackedUp : True
System_Cleared  : True

Returns all clients eventlog backup information for clients that were online and connected.

.EXAMPLE
PS F:\code> Backup-EventLog -ComputerName Indy-DC1, Indy-CLI1, Indy-SVR2 -LogFiles System -Path "\\Indy-SVR1\Logs" -ClearLog | FT


ComputerName Online System_Exists System_BackedUp System_Cleared
------------ ------ ------------- --------------- --------------
Indy-DC1     True   True          True             True
Indy-CLI1    False  False         False            False
Indy-SVR2    True   True          True             True


.EXAMPLE
Backup-EventLog -ComputerName Indy-DC1, Indy-CLI1, Indy-SVR2 -LogFiles System, application, Security -Path "\\Indy-SVR1\Logs" -ClearLog -Quiet

ComputerName         : Indy-DC1
Online               : True
System_Exists        : True
System_BackedUp      : True
System_Cleared       : True
application_Exists   : True
application_BackedUp : True
application_Cleared  : True
Security_Exists      : True
Security_BackedUp    : True
Security_Cleared     : True

ComputerName         : Indy-CLI1
Online               : False
System_Exists        : False
System_BackedUp      : False
System_Cleared       : False
application_Exists   : False
application_BackedUp : False
application_Cleared  : False
Security_Exists      : False
Security_BackedUp    : False
Security_Cleared     : False

ComputerName         : Indy-SVR2
Online               : True
System_Exists        : True
System_BackedUp      : True
System_Cleared       : True
application_Exists   : True
application_BackedUp : True
application_Cleared  : True
Security_Exists      : True
Security_BackedUp    : True
Security_Cleared     : True

Backups and clears all System, Application, and Security events on server
Indy-DC, Indy-CLI1, and Indy, SVR2.  The logs are backup on Indy-SVR2. 
All status messages are suppressed.


#>

}

No comments: