1717
1818.CHANGELOG
1919 15/04/25 SAN Code Cleaup & Publication
20+ 12.02.26 SAN Code improvement and fix for v13
2021
2122.TODO
2223 Var to env
23- get latest logs in case of error and output the logs
2424
2525#>
2626
27+ # CONFIG
2728$RootDirectory = " C:\ProgramData\Veeam\Endpoint"
2829$ThresholdHours = 48
29- $DateFormat = " dd.MM.yyyy HH:mm:ss"
30+ $DateFormat = " dd.MM.yyyy HH:mm:ss.fff "
3031$LogPattern = " Job session '.*' has been completed, status: '(.*?)',"
32+ $FailureLogLines = 50
33+
3134
3235function Get-RecentLogFile {
33- try {
34- $logFile = Get-ChildItem - Path $RootDirectory - Filter " *.Backup.log" - Recurse |
35- Sort-Object LastWriteTime - Descending |
36- Select-Object - First 1
37- return $logFile
38- } catch {
39- Write-Output " KO: Error accessing files: $_ "
40- exit 1
36+ if (-not (Test-Path $RootDirectory )) {
37+ throw " Directory not found: $RootDirectory "
38+ }
39+
40+ $logFile = Get-ChildItem - Path $RootDirectory - Filter " *.Backup.log" - Recurse - ErrorAction Stop |
41+ Sort-Object LastWriteTime - Descending |
42+ Select-Object - First 1
43+
44+ if (-not $logFile ) {
45+ throw " No .Backup.log files found."
4146 }
47+
48+ return $logFile
4249}
4350
4451function Get-JobStatusFromLog {
45- param ($logFile )
46- try {
47- $recentLine = Select-String - Path $logFile.FullName - Pattern $LogPattern |
48- Select-Object - Last 1
49-
50- if ($recentLine -and $recentLine.Line -match " \[(.*?)\] .* Job session '.*' has been completed, status: '(.*?)'," ) {
51- $dateTime = $matches [1 ]
52- $status = $matches [2 ]
53- return @ { DateTime = $dateTime ; Status = $status }
54- } else {
55- Write-Output " KO: No matching lines found in the log file."
56- exit 1
52+ param (
53+ [Parameter (Mandatory )]
54+ [System.IO.FileInfo ]$LogFile
55+ )
56+
57+ $recentLine = Select-String - Path $LogFile.FullName - Pattern $LogPattern - ErrorAction Stop |
58+ Select-Object - Last 1
59+
60+ if (-not $recentLine ) {
61+ throw " No matching job completion entry found in log."
62+ }
63+
64+ if ($recentLine.Line -match " \[(.*?)\].*status: '(.*?)'," ) {
65+ return @ {
66+ DateTime = $matches [1 ]
67+ Status = $matches [2 ]
5768 }
58- } catch {
59- Write-Output " KO: Error processing the log file: $_ "
60- exit 1
6169 }
70+
71+ throw " Log entry found but parsing failed."
6272}
6373
6474function Check-JobStatus {
6575 param (
66- [string ]$dateTime ,
67- [string ]$status
76+ [Parameter ( Mandatory )][ string ]$DateTime ,
77+ [Parameter ( Mandatory )][ string ]$Status
6878 )
6979
80+ $culture = [System.Globalization.CultureInfo ]::InvariantCulture
81+
7082 try {
71- $logDate = [datetime ]::ParseExact($dateTime , $DateFormat , $null )
72- $timeSpan = New-TimeSpan - Start $logDate - End ( Get-Date )
73-
74- if ( $status -ne " Success " ) {
75- Write-Output " KO: Job status is not 'Success'. "
76- exit 1
77- } elseif ( $timeSpan .TotalHours -gt $ThresholdHours ) {
78- Write-Output " KO: Log entry is older than $ThresholdHours hours. "
79- exit 1
80- } else {
81- Write-Output " OK: Job Status: $status , Date and Time: $dateTime "
82- exit 0
83+ $logDate = [datetime ]::ParseExact($DateTime , $DateFormat , $culture )
84+ }
85+ catch {
86+ throw " Timestamp format invalid: ' $DateTime ' "
87+ }
88+
89+ $timeSpan = New-TimeSpan - Start $logDate - End ( Get-Date )
90+
91+ if ( $Status -ne " Success " ) {
92+ return @ {
93+ Code = 1
94+ Message = " KO: Job status is ' $Status ' "
8395 }
84- } catch {
85- Write-Output " KO: Error checking job status: $_ "
86- exit 1
96+ }
97+
98+ if ($timeSpan.TotalHours -gt $ThresholdHours ) {
99+ return @ {
100+ Code = 1
101+ Message = " KO: Last backup older than $ThresholdHours hours (Last run: $DateTime )"
102+ }
103+ }
104+
105+ return @ {
106+ Code = 0
107+ Message = " OK: Job succeeded at $DateTime "
87108 }
88109}
89110
111+ function Write-FailureDetails {
112+ param (
113+ [string ]$Message ,
114+ [System.IO.FileInfo ]$LogFile
115+ )
116+
117+ Write-Output $Message
118+
119+ if ($LogFile -and (Test-Path $LogFile.FullName )) {
120+ Write-Output " ---- Last $FailureLogLines log lines ----"
121+ try {
122+ Get-Content - Path $LogFile.FullName - Tail $FailureLogLines - ErrorAction Stop |
123+ ForEach-Object { Write-Output $_ }
124+ }
125+ catch {
126+ Write-Output " Unable to read log tail: $ ( $_.Exception.Message ) "
127+ }
128+ }
129+ }
130+
131+ # MAIN
132+
133+ $logFile = $null
134+
90135try {
91136 $logFile = Get-RecentLogFile
137+ $jobInfo = Get-JobStatusFromLog - LogFile $logFile
138+ $result = Check- JobStatus - DateTime $jobInfo.DateTime - Status $jobInfo.Status
92139
93- if ($logFile ) {
94- $jobInfo = Get-JobStatusFromLog - logFile $logFile
95- if ($jobInfo ) {
96- Check- JobStatus - dateTime $jobInfo.DateTime - status $jobInfo.Status
97- }
98- } else {
99- Write-Output " KO: No .Backup.log files found in the directory or subdirectories."
140+ if ($result.Code -eq 0 ) {
141+ Write-Output $result.Message
142+ exit 0
143+ }
144+ else {
145+ Write-FailureDetails - Message $result.Message - LogFile $logFile
100146 exit 1
101147 }
102- } catch {
103- Write-Output " KO: Unexpected error: $_ "
104- exit 1
105148}
149+ catch {
150+ $errorMessage = " KO: $ ( $_.Exception.Message ) "
151+ Write-FailureDetails - Message $errorMessage - LogFile $logFile
152+ exit 1
153+ }
0 commit comments