Featured image of post Veeam log file analysis with PowerShell

Veeam log file analysis with PowerShell

A few weeks ago I did an Update of the Veeam Backup & Replication environment in my Lab. After the update I wanted to make sure everything went fine and started analyzing all event logs and file logs during and after the update. I quickly realized that the Veeam log file analysis without a proper tool will take a while. Since my last public PowerShell project was already a few month ago (and I was looking for a use case for PowerShell Classes), I have started to create a Function for the Veeam log file analysis with PowerShell.

Veeam log file analysis with PowerShell - Invoke-VeeamLogParser -LogType PowerShell

Veeam log file analysis

Per default all of the Veeam log files are located in ‘C:\ProgramData\Veeam\’. Most of the relevant Veeam Services create in their Sub-Folder a log file like these: ‘Svc.VeeamEndpointBackup.log’ (Veeam Agent for Microsoft Windows).

Most of the Veeam log files have the same schema for the main part:

1
[23.11.2016 23:07:16] <01> Info     ------- Veeam Endpoint Job Started -------

The analysis with PowerShell

PowerShell is a great tool for quickly grep data from files with a given schema:

1
2
$Content = Get-Content -Path "C:\ProgramData\Veeam\Endpoint\Svc.VeeamEndpointBackup.log"
$Content | Select-String -Pattern "\[\d+.\d+.\d+\s\d+\:\d+:\d+]\s\<\d+\>\sError"

These two lines return all Error messages in the Veeam Agent for Microsoft Windows log file.

Executing these commands for all the relevant log files is not really comfortable, so I have decided to create a PowerShell module with a function for the Veeam log file analysis. The function should have inputs for the log that should be analyzed and some optional parameters to modify the output of the messages.

This Example shows the output of all known (by the function) log files limited to the last Error or Warning message per file:

Veeam log file analysis with PowerShell - Invoke-VeeamLogParser -LogType All

If the output parameter -Context 2  is used all message are shown in context. The Warning or Error messages are highlighted by a >:

Veeam log file analysis with PowerShell - Invoke-VeeamLogParser -LogType PowerShell

Main function of the PowerShell module

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
function Invoke-VeeamLogParser {
<#
    .DESCRIPTION
       The Veeam Log Parser Function extracts Error and Warning Messages from the Veeam File Logs of various products and services.

    .NOTES
        File Name  : Invoke-VeeamLogParser.psm1
        Author     : Markus Kraus
        Version    : 1.0
        State      : Ready

    .LINK
        https://mycloudrevolution.com/

    .EXAMPLE
        Invoke-VeeamLogParser -LogType Endpoint -Limit 2

    .EXAMPLE
        Invoke-VeeamLogParser -LogType Endpoint -Limit 2 -Context 2

    .PARAMETER VeeamBasePath
        The Base Path of the Veeam Log Files

        Default: "C:\ProgramData\Veeam\"

    .PARAMETER Context
        Show messages in Context

    .PARAMETER Limit
        Show limited number of messages

    .PARAMETER LogType
        The products or services Log you want to show

        Valid Pattern:  "All","Endpoint","Mount","Backup","EnterpriseServer","Broker","Catalog","RestAPI","BackupManager",
                        "CatalogReplication","DatabaseMaintenance","WebApp","PowerShell"
    #>

[CmdletBinding()]
param(
    [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="The Base Path of the Veeam Log Files")]
    [ValidateNotNullorEmpty()]
        [String] $VeeamBasePath = "C:\ProgramData\Veeam\",
    [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Show messages in Context")]
    [ValidateNotNullorEmpty()]
        [int]$Context,
    [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Show limited number of messages")]
    [ValidateNotNullorEmpty()]
        [Int]$Limit,
    [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="The products or services Log you want to show")]
    [ValidateNotNullorEmpty()]
    [ValidateSet("All","Endpoint","Mount","Backup","EnterpriseServer","Broker","Catalog","RestAPI","BackupManager",
    "CatalogReplication","DatabaseMaintenance","WebApp","PowerShell")]
        [String]$LogType
)

Begin {

    class LogParser {
        #Properties
        [String]$Name
        [String]$BasePath
        [String]$Folder
        [String]$File

        #Static
        Static [String] $WarningPattern = "\[\d+.\d+.\d+\s\d+\:\d+:\d+]\s\<\d+\>\sWarning"
        Static [String] $ErrorPattern = "\[\d+.\d+.\d+\s\d+\:\d+:\d+]\s\<\d+\>\sError"

        #Constructor
        LogParser ([String] $Name, [String]$BasePath, [String]$Folder, [String]$File) {
            $this.Name = $Name
            $this.BasePath = $BasePath
            $this.Folder = $Folder
            $this.File = $File
        }

        #Method
        [Bool]checkFolder() {
            return Test-Path $($this.BasePath + $this.Folder)
        }

        #Method
        [Bool]checkFile() {
            return Test-Path $($this.BasePath + $this.Folder + "\" + $this.File)
        }

        #Method
        [Array]getContent() {
            if ($this.checkFolder()) {
                if ($this.checkFile()) {
                    return Get-Content $($this.BasePath + $this.Folder + "\" + $this.File)
                }
                else {
                    return Write-Warning "File not found"
                }
            }
            else {
                return Write-Warning "Folder not found"
            }
        }

        #Method
        [Array]getErrors() {
            $Content = $this.getContent()
            return $Content | Select-String -Pattern $([LogParser]::ErrorPattern) -AllMatches

        }

        #Method
        [Array]getErrors([int]$ContentB, [int]$ContentA) {
            $Content = $this.getContent()
            return $Content | Select-String -Pattern $([LogParser]::ErrorPattern) -AllMatches -Context $ContentB, $ContentA
        }

        #Method
        [Array]getWarnings() {
            $Content = $this.getContent()
            return $Content | Select-String -Pattern $([LogParser]::WarningPattern) -AllMatches

        }

        #Method
        [Array]getWarnings([int]$ContentB, [int]$ContentA) {
            $Content = $this.getContent()
            return $Content | Select-String -Pattern $([LogParser]::WarningPattern) -AllMatches -Context $ContentB, $ContentA

        }

        #Method
        [Array]getErrorsAndWarnings() {
            $Content = $this.getContent()
            return $Content | Select-String -Pattern $([LogParser]::ErrorPattern), $([LogParser]::WarningPattern) -AllMatches

        }

        #Method
        [Array]getErrorsAndWarnings([int]$ContentB, [int]$ContentA) {
            $Content = $this.getContent()
            return $Content | Select-String -Pattern $([LogParser]::ErrorPattern), $([LogParser]::WarningPattern) -AllMatches -Context $ContentB, $ContentA

        }

    }
    function Invoke-Output ($item) {
        if ($Context) {
            $Select = $item.getErrorsAndWarnings($Context, $Context)
        }
        else {
            $Select =  $item.getErrorsAndWarnings()
        }

        if ($Limit) {
            $Select | Select-Object -Last $Limit
        }
        else {
            $Select
        }

    }

    $LogTypes = @()
    $LogTypes += [LogParser]::new("Endpoint", $VeeamBasePath, "Endpoint", "Svc.VeeamEndpointBackup.log")
    $LogTypes += [LogParser]::new("Mount", $VeeamBasePath, "Backup", "Svc.VeeamMount.log")
    $LogTypes += [LogParser]::new("Backup", $VeeamBasePath, "Backup", "Svc.VeeamBackup.log")
    $LogTypes += [LogParser]::new("EnterpriseServer", $VeeamBasePath, "Backup", "Svc.VeeamBES.log")
    $LogTypes += [LogParser]::new("Broker", $VeeamBasePath, "Backup", "Svc.VeeamBroker.log")
    $LogTypes += [LogParser]::new("Catalog", $VeeamBasePath, "Backup", "Svc.VeeamCatalog.log")
    $LogTypes += [LogParser]::new("RestAPI", $VeeamBasePath, "Backup", "Svc.VeeamRestAPI.log")
    $LogTypes += [LogParser]::new("BackupManager", $VeeamBasePath, "Backup", "VeeamBackupManager.log")
    $LogTypes += [LogParser]::new("CatalogReplication", $VeeamBasePath, "Backup", "CatalogReplicationJob.log")
    $LogTypes += [LogParser]::new("DatabaseMaintenance", $VeeamBasePath, "Backup", "Job.DatabaseMaintenance.log")
    $LogTypes += [LogParser]::new("WebApp", $VeeamBasePath, "Backup", "Veeam.WebApp.log")
    $LogTypes += [LogParser]::new("PowerShell", $VeeamBasePath, "Backup", "VeeamPowerShell.log")

}

Process {

    if ($LogType -eq "All") {
        foreach ($item in $LogTypes) {
            Write-Host "`nProcessing '$($item.File)' in '$($item.BasePath + $item.Folder + "\")'" -ForegroundColor Gray
            Invoke-Output $item
        }
    }
    else {
        $item = $LogTypes | Where-Object {$_.Name -eq $LogType }
        if ($item) {
            Write-Host "`nProcessing '$($item.File)' in '$($item.BasePath + $item.Folder + "\")'" -ForegroundColor Gray
            Invoke-Output $item
        }
        else {
            Throw "Internal Error: LogType Missmatch"
        }
    }
}
}

Contribute to the PowerShell Module

In case you hit any bug or have any enhancement request feel free to open an issue or submit a pull request.

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy