From 6284e1a9d2e86eb54019fba40bb7e8d117f97b96 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Sun, 4 Jun 2023 18:05:32 -0400 Subject: [PATCH 1/8] Fix Node.js 12 actions are deprecated message --- .github/workflows/Release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 5e0b9f8..5615b83 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -8,7 +8,7 @@ jobs: publish-to-gallery: runs-on: windows-2019 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set PSRepository to Trusted for PowerShell Gallery shell: pwsh run: | From 5130f1d428041a1bc28410a81d429cfeb571f384 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 13 Jun 2023 20:26:25 -0400 Subject: [PATCH 2/8] Added Network Traffic Rules - Throttling Windows Time Period --- AsBuiltReport.Veeam.VBR.psd1 | 2 +- CHANGELOG.md | 7 ++ Src/Private/Get-AbrVbrBackupServerInfo.ps1 | 27 ++++++ Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 | 88 +++++++++++++++++++- 4 files changed, 122 insertions(+), 2 deletions(-) diff --git a/AsBuiltReport.Veeam.VBR.psd1 b/AsBuiltReport.Veeam.VBR.psd1 index fdc76b3..5c81808 100644 --- a/AsBuiltReport.Veeam.VBR.psd1 +++ b/AsBuiltReport.Veeam.VBR.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.Veeam.VBR.psm1' # Version number of this module. -ModuleVersion = '0.7.2' +ModuleVersion = '0.7.3' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/CHANGELOG.md b/CHANGELOG.md index 22bd640..03f1bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # :arrows_clockwise: Veeam VBR As Built Report Changelog +## [0.7.3] - 2023-06-13 + +### Added + +- Added Network Traffic Rules - Throttling Windows Time Period information +- Added Backup Server Domain Joined health check + ## [0.7.2] - 2023-06-04 ### Added diff --git a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 index d086686..f95a30f 100644 --- a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 +++ b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 @@ -35,6 +35,7 @@ function Get-AbrVbrBackupServerInfo { $CimSession = New-CimSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication $PssSession = New-PSSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication $SecurityOptions = Get-VBRSecurityOptions + try {$DomainJoined = Get-CimInstance -Class Win32_ComputerSystem -Property PartOfDomain -CimSession $CimSession} catch {'Unknown'} Write-PscriboMessage "Collecting Backup Server information from $($BackupServer.Name)." try { $VeeamVersion = Invoke-Command -Session $PssSession -ErrorAction SilentlyContinue -ScriptBlock { get-childitem -recurse HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | get-itemproperty | Where-Object { $_.DisplayName -match 'Veeam Backup & Replication Server' } | Select-Object -Property DisplayVersion } @@ -51,6 +52,7 @@ function Get-AbrVbrBackupServerInfo { Write-PscriboMessage "Discovered $BackupServer Server." $inObj = [ordered] @{ 'Server Name' = $BackupServer.Name + 'Is Domain Joined?' = ConvertTo-TextYN $DomainJoined.PartOfDomain 'Version' = Switch (($VeeamVersion).count) { 0 {"-"} default {$VeeamVersion.DisplayVersion} @@ -101,6 +103,7 @@ function Get-AbrVbrBackupServerInfo { if ($HealthCheck.Infrastructure.BackupServer) { $OutObj | Where-Object { $_.'Logging Level' -gt 4} | Set-Style -Style Warning -Property 'Logging Level' + $OutObj | Where-Object { $_.'Is Domain Joined?' -eq 'Yes'} | Set-Style -Style Warning -Property 'Is Domain Joined?' } $TableParams = @{ @@ -112,6 +115,30 @@ function Get-AbrVbrBackupServerInfo { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($HealthCheck.Infrastructure.BestPractice) { + if ($OutObj | Where-Object { $_.'Is Domain Joined?' -eq 'Yes'}) { + Paragraph "Health Check:" -Italic -Bold -Underline + Paragraph 'Best Practice: For the most secure deployment, Veeam recommend three options:' -Italic -Bold + + BlankLine + + Paragraph '1. Add the Veeam components to a management domain that resides in a separate Active Directory Forest and protect the administrative accounts with two-factor authentication mechanics.' -Italic -Bold + + BlankLine + + Paragraph '2. Add the Veeam components to a separate workgroup and place the components on a separate network where applicable.' -Italic -Bold + + BlankLine + + Paragraph '3. Add the Veeam components to the production domain but make sure the accounts with administrative privileges are protected with two-factor authentication.' -Italic -Bold + + BlankLine + + Paragraph 'Reference:' -Bold + Paragraph 'https://bp.veeam.com/vbr/Security/Security_domains.html' -Bold -Underline + + } + } #---------------------------------------------------------------------------------------------# # Backup Server Inventory Summary Section # #---------------------------------------------------------------------------------------------# diff --git a/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 b/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 index debc7c3..84ef04d 100644 --- a/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 +++ b/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrNetworkTrafficRule { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.1 + Version: 0.7.3 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -58,6 +58,92 @@ function Get-AbrVbrNetworkTrafficRule { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($TrafficRule.ThrottlingWindowEnabled) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "Throttling Windows Time Period" { + Paragraph { + Text 'Permited \' -Color 81BC50 -Bold + Text ' Denied' -Color dddf62 -Bold + } + $OutObj = @() + try { + $Days = 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' + $Hours24 = [ordered]@{ + 0 = 12 + 1 = 1 + 2 = 2 + 3 = 3 + 4 = 4 + 5 = 5 + 6 = 6 + 7 = 7 + 8 = 8 + 9 = 9 + 10 = 10 + 11 = 11 + 12 = 12 + 13 = 1 + 14 = 2 + 15 = 3 + 16 = 4 + 17 = 5 + 18 = 6 + 19 = 7 + 20 = 8 + 21 = 9 + 22 = 10 + 23 = 11 + } + $ScheduleTimePeriod = $TrafficRule.ThrottlingWindowOptions -split '(.{48})' | Where-Object {$_} + + foreach ($OBJ in $Hours24.GetEnumerator()) { + + $inObj = [ordered] @{ + 'H' = $OBJ.Value + 'Sun' = $ScheduleTimePeriod[0].Split(',')[$OBJ.Key] + 'Mon' = $ScheduleTimePeriod[1].Split(',')[$OBJ.Key] + 'Tue' = $ScheduleTimePeriod[2].Split(',')[$OBJ.Key] + 'Wed' = $ScheduleTimePeriod[3].Split(',')[$OBJ.Key] + 'Thu' = $ScheduleTimePeriod[4].Split(',')[$OBJ.Key] + 'Fri' = $ScheduleTimePeriod[5].Split(',')[$OBJ.Key] + 'Sat' = $ScheduleTimePeriod[6].Split(',')[$OBJ.Key] + } + $OutObj += $inobj + } + + $TableParams = @{ + Name = "Throttling Windows - $($TrafficRule.Name)" + List = $true + ColumnWidths = 6,4,3,4,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4 + Key = 'H' + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + if ($OutObj) { + $OutObj2 = Table -Hashtable $OutObj @TableParams + $OutObj2.Rows | Where-Object {$_.Sun -eq "0"} | Set-Style -Style OFF -Property "Sun" + $OutObj2.Rows | Where-Object {$_.Mon -eq "0"} | Set-Style -Style OFF -Property "Mon" + $OutObj2.Rows | Where-Object {$_.Tue -eq "0"} | Set-Style -Style OFF -Property "Tue" + $OutObj2.Rows | Where-Object {$_.Wed -eq "0"} | Set-Style -Style OFF -Property "Wed" + $OutObj2.Rows | Where-Object {$_.Thu -eq "0"} | Set-Style -Style OFF -Property "Thu" + $OutObj2.Rows | Where-Object {$_.Fri -eq "0"} | Set-Style -Style OFF -Property "Fri" + $OutObj2.Rows | Where-Object {$_.Sat -eq "0"} | Set-Style -Style OFF -Property "Sat" + + $OutObj2.Rows | Where-Object {$_.Sun -eq "1"} | Set-Style -Style ON -Property "Sun" + $OutObj2.Rows | Where-Object {$_.Mon -eq "1"} | Set-Style -Style ON -Property "Mon" + $OutObj2.Rows | Where-Object {$_.Tue -eq "1"} | Set-Style -Style ON -Property "Tue" + $OutObj2.Rows | Where-Object {$_.Wed -eq "1"} | Set-Style -Style ON -Property "Wed" + $OutObj2.Rows | Where-Object {$_.Thu -eq "1"} | Set-Style -Style ON -Property "Thu" + $OutObj2.Rows | Where-Object {$_.Fri -eq "1"} | Set-Style -Style ON -Property "Fri" + $OutObj2.Rows | Where-Object {$_.Sat -eq "1"} | Set-Style -Style ON -Property "Sat" + $OutObj2 + } + } + catch { + Write-PscriboMessage -IsWarning "Throttling Windows Time Period Section: $($_.Exception.Message)" + } + } + } } } catch { From 967f8f3fd16db1050de1815a373458f8c60a7087 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Sun, 9 Jul 2023 14:07:41 -0400 Subject: [PATCH 3/8] Improved health check recommendation look and feel --- Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 | 24 ++++++-- Src/Private/Get-AbrVbrBackupRepository.ps1 | 8 ++- Src/Private/Get-AbrVbrBackupServerInfo.ps1 | 34 ++++++----- Src/Private/Get-AbrVbrBackupToTape.ps1 | 8 ++- Src/Private/Get-AbrVbrCloudConnectCG.ps1 | 8 ++- Src/Private/Get-AbrVbrCloudConnectGP.ps1 | 8 ++- Src/Private/Get-AbrVbrCloudConnectTenant.ps1 | 16 +++-- .../Get-AbrVbrConfigurationBackupSetting.ps1 | 20 +++++-- .../Get-AbrVbrEmailNotificationSetting.ps1 | 8 ++- .../Get-AbrVbrEnterpriseManagerInfo.ps1 | 10 +++- .../Get-AbrVbrFileShareBackupjobConf.ps1 | 18 ++++-- Src/Private/Get-AbrVbrFileToTape.ps1 | 8 ++- .../Get-AbrVbrGlobalNotificationSetting.ps1 | 32 +++++++--- Src/Private/Get-AbrVbrObjectRepository.ps1 | 16 +++-- Src/Private/Get-AbrVbrReplFailoverPlan.ps1 | 8 ++- Src/Private/Get-AbrVbrRepljobHyperV.ps1 | 18 ++++-- Src/Private/Get-AbrVbrRepljobVMware.ps1 | 18 ++++-- Src/Private/Get-AbrVbrScaleOutRepository.ps1 | 8 ++- Src/Private/Get-AbrVbrSecInfraHard.ps1 | 58 +++++++++++++++---- Src/Private/Get-AbrVbrSureBackup.ps1 | 18 ++++-- Src/Private/Get-AbrVbrSureBackupjobconf.ps1 | 10 +++- Src/Private/Get-AbrVbrTapeMediaPool.ps1 | 8 ++- Src/Private/Get-AbrVbrTapeServer.ps1 | 8 ++- Src/Private/Get-AbrVbrTapeVault.ps1 | 8 ++- 24 files changed, 279 insertions(+), 101 deletions(-) diff --git a/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 b/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 index cf9e172..44e9763 100644 --- a/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 +++ b/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 @@ -72,8 +72,12 @@ function Get-AbrVbrAgentBackupjobConf { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } @@ -494,8 +498,12 @@ function Get-AbrVbrAgentBackupjobConf { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } } } } @@ -537,8 +545,12 @@ function Get-AbrVbrAgentBackupjobConf { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" + } } } } diff --git a/Src/Private/Get-AbrVbrBackupRepository.ps1 b/Src/Private/Get-AbrVbrBackupRepository.ps1 index 2d3b076..fa066bb 100644 --- a/Src/Private/Get-AbrVbrBackupRepository.ps1 +++ b/Src/Private/Get-AbrVbrBackupRepository.ps1 @@ -181,8 +181,12 @@ function Get-AbrVbrBackupRepository { $OutObj | Table @TableParams if (($HealthCheck.Infrastructure.BestPractice) -and ($OutObj | Where-Object { $_.'Immutability Supported' -eq 'Yes' -and $_.'Immutability Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommend to implement Immutability where it is supported. It is done for increased security: immutability protects your data from loss as a result of attacks, malware activity or any other injurious actions." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommend to implement Immutability where it is supported. It is done for increased security: immutability protects your data from loss as a result of attacks, malware activity or any other injurious actions." + } } } } diff --git a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 index f95a30f..de2f5dc 100644 --- a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 +++ b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 @@ -117,26 +117,24 @@ function Get-AbrVbrBackupServerInfo { $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice) { if ($OutObj | Where-Object { $_.'Is Domain Joined?' -eq 'Yes'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph 'Best Practice: For the most secure deployment, Veeam recommend three options:' -Italic -Bold - + Paragraph "Health Check:" -Bold -Underline BlankLine + Paragraph { + Text 'Best Practice:' -Bold - Paragraph '1. Add the Veeam components to a management domain that resides in a separate Active Directory Forest and protect the administrative accounts with two-factor authentication mechanics.' -Italic -Bold - - BlankLine - - Paragraph '2. Add the Veeam components to a separate workgroup and place the components on a separate network where applicable.' -Italic -Bold - + Text 'For the most secure deployment, Veeam recommend three options:' + } BlankLine + Paragraph '1. Add the Veeam components to a management domain that resides in a separate Active Directory Forest and protect the administrative accounts with two-factor authentication mechanics.' - Paragraph '3. Add the Veeam components to the production domain but make sure the accounts with administrative privileges are protected with two-factor authentication.' -Italic -Bold + Paragraph '2. Add the Veeam components to a separate workgroup and place the components on a separate network where applicable.' + Paragraph '3. Add the Veeam components to the production domain but make sure the accounts with administrative privileges are protected with two-factor authentication.' BlankLine - - Paragraph 'Reference:' -Bold - Paragraph 'https://bp.veeam.com/vbr/Security/Security_domains.html' -Bold -Underline - + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/Security_domains.html' + } } } #---------------------------------------------------------------------------------------------# @@ -194,8 +192,12 @@ function Get-AbrVbrBackupServerInfo { $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice) { if (([int]([regex]::Matches($OutObj.'Physical Memory (GB)', "\d+(?!.*\d+)").value) -lt 8) -or ($OutObj | Where-Object { $_.'Number of CPU Cores' -lt 2})) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Recommended Veeam Backup Server minimum configuration is two CPU cores and 8GB RAM." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Recommended Veeam Backup Server minimum configuration is two CPU cores and 8GB of RAM." + } } } #---------------------------------------------------------------------------------------------# diff --git a/Src/Private/Get-AbrVbrBackupToTape.ps1 b/Src/Private/Get-AbrVbrBackupToTape.ps1 index f9ab375..8aa6ddb 100644 --- a/Src/Private/Get-AbrVbrBackupToTape.ps1 +++ b/Src/Private/Get-AbrVbrBackupToTape.ps1 @@ -72,8 +72,12 @@ function Get-AbrVbrBackupToTape { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } diff --git a/Src/Private/Get-AbrVbrCloudConnectCG.ps1 b/Src/Private/Get-AbrVbrCloudConnectCG.ps1 index cab461c..9e84dba 100644 --- a/Src/Private/Get-AbrVbrCloudConnectCG.ps1 +++ b/Src/Private/Get-AbrVbrCloudConnectCG.ps1 @@ -83,8 +83,12 @@ function Get-AbrVbrCloudConnectCG { $OutObj | Sort-Object -Property 'Name' | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } diff --git a/Src/Private/Get-AbrVbrCloudConnectGP.ps1 b/Src/Private/Get-AbrVbrCloudConnectGP.ps1 index 51988fb..3c1f59b 100644 --- a/Src/Private/Get-AbrVbrCloudConnectGP.ps1 +++ b/Src/Private/Get-AbrVbrCloudConnectGP.ps1 @@ -68,8 +68,12 @@ function Get-AbrVbrCloudConnectGP { $OutObj | Sort-Object -Property 'Name' | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } diff --git a/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 b/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 index cbcd643..d6a7897 100644 --- a/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 +++ b/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 @@ -72,8 +72,12 @@ function Get-AbrVbrCloudConnectTenant { $OutObj | Sort-Object -Property 'Name' | Table @TableParams if ($HealthCheck.CloudConnect.BestPractice) { if ($OutObj | Where-Object { $Null -like $_.'Last Active' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Validate if the tenant's resources are being utilized" -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Validate if the tenant's resources are being utilized" + } } } #---------------------------------------------------------------------------------------------# @@ -141,8 +145,12 @@ function Get-AbrVbrCloudConnectTenant { $OutObj | Sort-Object -Property 'Name' | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } diff --git a/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 b/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 index 0c66e93..547b1e7 100644 --- a/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 +++ b/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 @@ -82,15 +82,27 @@ function Get-AbrVbrConfigurationBackupSetting { $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice) { if ($OutObj | Where-Object { $_.'Encryption Enabled' -like 'No' -or $_.'Run Job Automatically' -like 'No' -or $_.'Enabled' -like 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline + Paragraph "Health Check:" -Bold -Underline + BlankLine if ($OutObj | Where-Object { $_.'Encryption Enabled' -like 'No'} ) { - Paragraph "Best Practice: Whenever possible, enable configuration backup encryption." -Italic -Bold + Paragraph { + Text "Best Practice:" - Bold + Text "Whenever possible, enable configuration backup encryption." + } + BlankLine } if ($OutObj | Where-Object { $_.'Run Job Automatically' -like 'No'}) { - Paragraph "Best Practice: It`s a recommended best practice to activate the 'Run job automatically' option of the Backup Configuration job." -Italic -Bold + Paragraph { + Text "Best Practice:" - Bold + Text "It`s a recommended best practice to activate the 'Run job automatically' option of the Backup Configuration job." + } + BlankLine } if ($OutObj | Where-Object { $_.'Enabled' -like 'No'}) { - Paragraph "Best Practice: It`s a recommended best practice to enable the Backup Configuration job" -Italic -Bold + Paragraph { + Text "Best Practice:" -Bold + Text "It`s a recommended best practice to enable the Backup Configuration job" + } } } } diff --git a/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 b/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 index 5c7ba00..eb89aba 100644 --- a/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 +++ b/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 @@ -64,8 +64,12 @@ function Get-AbrVbrEmailNotificationSetting { } $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice -and ($OutObj | Where-Object { $_.'Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." + } } } } diff --git a/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 b/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 index e6a142c..9255f9f 100644 --- a/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 +++ b/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 @@ -28,7 +28,7 @@ function Get-AbrVbrEnterpriseManagerInfo { try { if ((Get-VBRServer -Type Local).count -gt 0) { Section -Style Heading3 'Enterprise Manager Information' { - Paragraph "The following table details information about Veeam Enterprise Manager" + Paragraph "The following table details information about Veeam Enterprise Manager configuration status" BlankLine $OutObj = @() $BackupServers = Get-VBRServer -Type Local @@ -68,8 +68,12 @@ function Get-AbrVbrEnterpriseManagerInfo { } $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice -and ($OutObj | Where-Object { $_.'Skip License Push' -eq 'Yes' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommends centralized license management through Enterprise Manager." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommends centralized license management through Enterprise Manager." + } } } } diff --git a/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 b/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 index 0d30d0a..ae6d7cf 100644 --- a/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 +++ b/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 @@ -72,8 +72,12 @@ function Get-AbrVbrFileShareBackupjobConf { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } @@ -257,8 +261,12 @@ function Get-AbrVbrFileShareBackupjobConf { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } } } } @@ -383,7 +391,7 @@ function Get-AbrVbrFileShareBackupjobConf { } } } - if ($Bkjob.GetScheduleOptions().NextRun -and $Bkjob.ScheduleOptions.OptionsContinuous.Enabled -ne "True") { + if ($Bkjob.IsScheduleEnabled -and $Bkjob.ScheduleOptions.OptionsContinuous.Enabled -ne "True") { Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { $OutObj = @() try { diff --git a/Src/Private/Get-AbrVbrFileToTape.ps1 b/Src/Private/Get-AbrVbrFileToTape.ps1 index d732021..a7ec34e 100644 --- a/Src/Private/Get-AbrVbrFileToTape.ps1 +++ b/Src/Private/Get-AbrVbrFileToTape.ps1 @@ -66,8 +66,12 @@ function Get-AbrVbrFileToTape { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } diff --git a/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 b/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 index c891f7f..3538243 100644 --- a/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 +++ b/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 @@ -54,8 +54,12 @@ function Get-AbrVbrGlobalNotificationSetting { } $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice -and ($OutObj | Where-Object { $_.'Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." + } } } Section -ExcludeFromTOC -Style NOTOCHeading5 'Production Datastore' { @@ -89,8 +93,12 @@ function Get-AbrVbrGlobalNotificationSetting { } $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice -and ($OutObj | Where-Object { $_.'Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." + } } } Section -ExcludeFromTOC -Style NOTOCHeading5 'Support Expiration' { @@ -114,8 +122,12 @@ function Get-AbrVbrGlobalNotificationSetting { } $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice -and ($OutObj | Where-Object { $_.'Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." + } } } Section -ExcludeFromTOC -Style NOTOCHeading5 'Update Notification' { @@ -135,8 +147,12 @@ function Get-AbrVbrGlobalNotificationSetting { } $OutObj | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice -and ($OutObj | Where-Object { $_.'Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommends configuring email notifications to be able to receive alerts with the results of jobs performed on the backup server." + } } } } diff --git a/Src/Private/Get-AbrVbrObjectRepository.ps1 b/Src/Private/Get-AbrVbrObjectRepository.ps1 index 0772170..5958a9d 100644 --- a/Src/Private/Get-AbrVbrObjectRepository.ps1 +++ b/Src/Private/Get-AbrVbrObjectRepository.ps1 @@ -153,8 +153,12 @@ function Get-AbrVbrObjectRepository { } $OutObj | Table @TableParams if (($HealthCheck.Infrastructure.BestPractice) -and ($OutObj | Where-Object { $_.'Immutability Enabled' -eq 'No' })) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommend to implement Immutability where it is supported. It is done for increased security: immutability protects your data from loss as a result of attacks, malware activity or any other injurious actions." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommend to implement Immutability where it is supported. It is done for increased security: immutability protects your data from loss as a result of attacks, malware activity or any other injurious actions." + } } } } @@ -232,8 +236,12 @@ function Get-AbrVbrObjectRepository { } $OutObj | Table @TableParams if (($HealthCheck.Infrastructure.BestPractice) -and ($OutObj | Where-Object { $_.'Immutability Enabled' -eq 'No'})) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam recommend to implement Immutability where it is supported. It is done for increased security: immutability protects your data from loss as a result of attacks, malware activity or any other injurious actions." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam recommend to implement Immutability where it is supported. It is done for increased security: immutability protects your data from loss as a result of attacks, malware activity or any other injurious actions." + } } } } diff --git a/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 b/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 index 1dade61..154a7e2 100644 --- a/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 +++ b/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 @@ -65,8 +65,12 @@ function Get-AbrVbrReplFailoverPlan { $OutObj | Table @TableParams if ($HealthCheck.Replication.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } if ($InfoLevel.Replication.FailoverPlan -ge 2) { diff --git a/Src/Private/Get-AbrVbrRepljobHyperV.ps1 b/Src/Private/Get-AbrVbrRepljobHyperV.ps1 index 5114b98..384b42d 100644 --- a/Src/Private/Get-AbrVbrRepljobHyperV.ps1 +++ b/Src/Private/Get-AbrVbrRepljobHyperV.ps1 @@ -345,8 +345,12 @@ function Get-AbrVbrRepljobHyperV { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } } } } @@ -404,8 +408,12 @@ function Get-AbrVbrRepljobHyperV { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" + } } } } @@ -771,7 +779,7 @@ function Get-AbrVbrRepljobHyperV { } } } - if ($Bkjob.GetScheduleOptions().NextRun) { + if ($Bkjob.IsScheduleEnabled) { Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { $OutObj = @() try { diff --git a/Src/Private/Get-AbrVbrRepljobVMware.ps1 b/Src/Private/Get-AbrVbrRepljobVMware.ps1 index 94a992f..ae699ef 100644 --- a/Src/Private/Get-AbrVbrRepljobVMware.ps1 +++ b/Src/Private/Get-AbrVbrRepljobVMware.ps1 @@ -349,8 +349,12 @@ function Get-AbrVbrRepljobVMware { if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } } } } @@ -408,8 +412,12 @@ function Get-AbrVbrRepljobVMware { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" + } } } } @@ -777,7 +785,7 @@ function Get-AbrVbrRepljobVMware { } } } - if ($Bkjob.GetScheduleOptions().NextRun) { + if ($Bkjob.IsScheduleEnabled) { Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { $OutObj = @() try { diff --git a/Src/Private/Get-AbrVbrScaleOutRepository.ps1 b/Src/Private/Get-AbrVbrScaleOutRepository.ps1 index 3921e8d..f9465a5 100644 --- a/Src/Private/Get-AbrVbrScaleOutRepository.ps1 +++ b/Src/Private/Get-AbrVbrScaleOutRepository.ps1 @@ -122,8 +122,12 @@ function Get-AbrVbrScaleOutRepository { $OutObj | Table @TableParams if (($HealthCheck.Infrastructure.BestPractice) -and ($OutObj | Where-Object { $_.'Encrypt data uploaded to Object Storage' -like 'No'})) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Veeam Backup & Replication allows you to encrypt offloaded data. With the Encrypt data uploaded to object storage setting selected, the entire collection of blocks along with the metadata will be encrypted while being offloaded regardless of the jobs encryption settings. This helps you protect the data from an unauthorized access." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Veeam Backup & Replication allows you to encrypt offloaded data. With the Encrypt data uploaded to object storage setting selected, the entire collection of blocks along with the metadata will be encrypted while being offloaded regardless of the jobs encryption settings. This helps you protect the data from an unauthorized access." + } } } } diff --git a/Src/Private/Get-AbrVbrSecInfraHard.ps1 b/Src/Private/Get-AbrVbrSecInfraHard.ps1 index e6be841..476821d 100644 --- a/Src/Private/Get-AbrVbrSecInfraHard.ps1 +++ b/Src/Private/Get-AbrVbrSecInfraHard.ps1 @@ -75,7 +75,10 @@ function Get-AbrVbrSecInfraHard { Paragraph "Remove all non-essential software programs and utilities from the deployed Veeam components. While these programs may offer useful features to the administrator, if they provide 'back-door' access to the system, they must be removed during the hardening process. Think about additional software like web browsers, java, adobe reader and such. All parts which do not belong to the operating system or to active Veeam components, remove it. It will make maintaining an up-to-date patch level much easier." BlankLine $Unused - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#remove-unused-components' -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#remove-unused-components' + } } } } @@ -113,7 +116,10 @@ function Get-AbrVbrSecInfraHard { Paragraph "Remove the Veeam Backup & Replication Console from the Veeam Backup & Replication server. The console is installed locally on the backup server by default." BlankLine $Console - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#how-to-remove-the-veeam-backup--replication-console' -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#how-to-remove-the-veeam-backup--replication-console' + } } } } @@ -155,7 +161,10 @@ function Get-AbrVbrSecInfraHard { Paragraph "Stop the Veeam vPower NFS Service if you do not plan on using the following Veeam features: SureBackup, Instant Recovery, or Other-OS File Level Recovery (FLR) operations." BlankLine $vPowerNFS - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#remove-unused-components' -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#remove-unused-components' + } } } } @@ -276,7 +285,10 @@ function Get-AbrVbrSecInfraHard { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#password-management-policy' -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#password-management-policy' + } } } $LockpolicyConfiObj = if ($policyConfigHash) { @@ -309,7 +321,10 @@ function Get-AbrVbrSecInfraHard { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#lockout-policy' -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#lockout-policy' + } } } if ($PasswordPolicyConfiObj -or $LockpolicyConfiObj) { @@ -354,7 +369,11 @@ function Get-AbrVbrSecInfraHard { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Sort-Object -Property 'Name' | Table @TableParams - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#roles-and-users' -Bold + $OutObj | Table @TableParams + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#roles-and-users' + } } catch { Write-PscriboMessage -IsWarning $_.Exception.Message @@ -454,7 +473,11 @@ function Get-AbrVbrSecInfraHard { Blankline Paragraph "Backup proxies must be considered the target for compromise. During backup, proxies obtain from the backup server credentials required to access virtual infrastructure servers. A person having administrator privileges on a backup proxy can intercept the credentials and use them to access the virtual infrastructure." $vSphereCredObj - Paragraph "Reference: https://helpcenter.veeam.com/docs/backup/permissions/installation.html?ver=110" -Bold + Blankline + Paragraph { + Text 'Reference:' -Bold + Text 'https://helpcenter.veeam.com/docs/backup/permissions/installation.html?ver=110' + } } } } @@ -747,7 +770,11 @@ function Get-AbrVbrSecInfraHard { if ($UpdatesObj) { Section -Style Heading3 'Patching and Updates' { Paragraph "Patch operating systems, software, and firmware on Veeam components. Most hacks succeed because there is already vulnerable software in use which is not up-to-date with current patch levels. So make sure all software and hardware where Veeam components are running are up-to-date. One of the most possible causes of a credential theft are missing guest OS updates and use of outdated authentication protocols." - Paragraph 'Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#patching-and-updates' -Bold + BlankLine + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#patching-and-updates' + } $UpdatesObj } } @@ -939,7 +966,10 @@ function Get-AbrVbrSecInfraHard { Paragraph "* Restrict user access to backups and replicas. Check that only authorized users have permissions to access backups and replicas on target servers." Paragraph "* Encrypt data in backups. Use Veeam Backup & Replication inbuilt encryption to protect data in backups. To guarantee security of data in backups, follow Encryption Best Practices." BlankLine - Paragraph "Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#encryption" -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#encryption' + } $BKJobsEncObj $EncryptNetworkTraffic } @@ -954,7 +984,10 @@ function Get-AbrVbrSecInfraHard { Section -Style Heading4 'Encrypt Data in Configuration Backups' { Paragraph 'Enable data encryption for configuration backup to secure sensitive data stored in the configuration database.' BlankLine - Paragraph "Reference: https://helpcenter.veeam.com/docs/backup/vsphere/config_backup_encrypted.html?ver=110" -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://helpcenter.veeam.com/docs/backup/vsphere/config_backup_encrypted.html?ver=110' + } BlankLine $OutObj = @() try { @@ -1013,7 +1046,10 @@ function Get-AbrVbrSecInfraHard { Section -Style Heading3 'Backup and Replication Database' { Paragraph "The Backup & Replication configuration database stores credentials to connect to virtual servers and other systems in the backup & replication infrastructure. All passwords stored in the database are encrypted. However, a user with administrator privileges on the backup server can decrypt the passwords, which presents a potential threat." BlankLine - Paragraph "Reference: https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#backup-and-replication-database" -Bold + Paragraph { + Text 'Reference:' -Bold + Text 'https://bp.veeam.com/vbr/Security/infrastructure_hardening.html#backup-and-replication-database' + } $BKPConf } } diff --git a/Src/Private/Get-AbrVbrSureBackup.ps1 b/Src/Private/Get-AbrVbrSureBackup.ps1 index 4196795..53120ed 100644 --- a/Src/Private/Get-AbrVbrSureBackup.ps1 +++ b/Src/Private/Get-AbrVbrSureBackup.ps1 @@ -243,8 +243,12 @@ function Get-AbrVbrSureBackup { $OutObj | Sort-Object -Property 'Production Network' | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice) { if ($OutObj | Where-Object { $Null -like $_.'Notes' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined notes. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined notes. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } @@ -266,7 +270,7 @@ function Get-AbrVbrSureBackup { Write-PscriboMessage -IsWarning "SureBackup vSphere Virtual Labs Configuration Section: $($_.Exception.Message)" } try { - $SureBackupVLs = Get-VBRHvVirtualLabConfiguration | Sort-Object -Property Name + $SureBackupVLs = try {Get-VBRHvVirtualLabConfiguration | Sort-Object -Property Name} catch {$Null} if ($SureBackupVLs) { Section -Style Heading5 "Hyper-V Virtual Labs Configuration" { foreach ($SureBackupVL in $SureBackupVLs) { @@ -353,8 +357,12 @@ function Get-AbrVbrSureBackup { $OutObj | Sort-Object -Property 'Production Network' | Table @TableParams if ($HealthCheck.Infrastructure.BestPractice) { if ($OutObj | Where-Object { $Null -like $_.'Notes' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined notes. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined notes. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } diff --git a/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 b/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 index e5fd0a6..98ceef4 100644 --- a/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 +++ b/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 @@ -66,8 +66,12 @@ function Get-AbrVbrSureBackupjobconf { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } @@ -85,7 +89,7 @@ function Get-AbrVbrSureBackupjobconf { 'Physical Host' = $SBkjob.VirtualLab.Server.Name 'Physical Host Version' = $SBkjob.VirtualLab.Server.Info.Info } - if ($SBkjob.VirtualLab.Platform -eq "HyperV") { + if ($SBkjob.VirtualLab.Platform -eq "HyperV" -and (Get-VBRHvVirtualLabConfiguration)) { $inObj.add('Destination', (Get-VBRHvVirtualLabConfiguration -Id $SBkjob.VirtualLab.Id).Path) } if ($SBkjob.VirtualLab.Platform -eq "VMWare") { diff --git a/Src/Private/Get-AbrVbrTapeMediaPool.ps1 b/Src/Private/Get-AbrVbrTapeMediaPool.ps1 index e2a26ae..ec48cf9 100644 --- a/Src/Private/Get-AbrVbrTapeMediaPool.ps1 +++ b/Src/Private/Get-AbrVbrTapeMediaPool.ps1 @@ -162,8 +162,12 @@ function Get-AbrVbrTapeMediaPool { $OutObj | Sort-Object -Property 'Name' | Table @TableParams if ($HealthCheck.Tape.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } #---------------------------------------------------------------------------------------------# diff --git a/Src/Private/Get-AbrVbrTapeServer.ps1 b/Src/Private/Get-AbrVbrTapeServer.ps1 index b991768..c177966 100644 --- a/Src/Private/Get-AbrVbrTapeServer.ps1 +++ b/Src/Private/Get-AbrVbrTapeServer.ps1 @@ -66,8 +66,12 @@ function Get-AbrVbrTapeServer { $OutObj | Sort-Object -Property 'Name' | Table @TableParams if ($HealthCheck.Tape.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } diff --git a/Src/Private/Get-AbrVbrTapeVault.ps1 b/Src/Private/Get-AbrVbrTapeVault.ps1 index 033f087..e6f2cf7 100644 --- a/Src/Private/Get-AbrVbrTapeVault.ps1 +++ b/Src/Private/Get-AbrVbrTapeVault.ps1 @@ -65,8 +65,12 @@ function Get-AbrVbrTapeVault { $OutObj | Table @TableParams if ($HealthCheck.Tape.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } From ae5c1becc5197297182e8d36770a2a281ea7a149 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Wed, 12 Jul 2023 14:08:02 -0400 Subject: [PATCH 4/8] Fix V12 - No Backup Copy Jobs detail in report #104 --- Src/Private/Get-AbrVbrBackupCopyjob .ps1 | 79 +++ Src/Private/Get-AbrVbrBackupCopyjobConf.ps1 | 640 ++++++++++++++++++ Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 | 5 + 3 files changed, 724 insertions(+) create mode 100644 Src/Private/Get-AbrVbrBackupCopyjob .ps1 create mode 100644 Src/Private/Get-AbrVbrBackupCopyjobConf.ps1 diff --git a/Src/Private/Get-AbrVbrBackupCopyjob .ps1 b/Src/Private/Get-AbrVbrBackupCopyjob .ps1 new file mode 100644 index 0000000..9993d66 --- /dev/null +++ b/Src/Private/Get-AbrVbrBackupCopyjob .ps1 @@ -0,0 +1,79 @@ + +function Get-AbrVbrBackupCopyjob { + <# + .SYNOPSIS + Used by As Built Report to returns backup copy jobs created in Veeam Backup & Replication. + .DESCRIPTION + Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. + .NOTES + Version: 0.8.0 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + Credits: Iain Brighton (@iainbrighton) - PScribo module + + .LINK + https://github.com/AsBuiltReport/AsBuiltReport.Veeam.VBR + #> + [CmdletBinding()] + param ( + + ) + + begin { + Write-PscriboMessage "Discovering Veeam VBR Backup Copy jobs information from $System." + } + + process { + try { + $BkCopyjobs = Get-VBRBackupCopyJob -WarningAction SilentlyContinue + if ($BkCopyjobs) { + Section -Style Heading3 'Backup Copy Jobs' { + Paragraph "The following section list backup copy jobs created within Veeam Backup & Replication." + BlankLine + $OutObj = @() + foreach ($BkCopyjob in $BkCopyjobs) { + try { + Write-PscriboMessage "Discovered $($BkCopyjob.Name) backup copy." + $inObj = [ordered] @{ + 'Name' = $BkCopyjob.Name + 'Copy Mode' = $BkCopyjob.Mode + 'Status' = Switch ($BkCopyjob.JobEnabled) { + 'False' {'Disabled'} + 'True' {'Enabled'} + } + 'Latest Result' = $BkCopyjob.LastResult + 'Scheduled?' = $BkCopyjob.ScheduleOptions.Type + } + $OutObj += [pscustomobject]$inobj + } + catch { + Write-PscriboMessage -IsWarning "Backup Copy Jobs $($BkCopyjob.Name) Section: $($_.Exception.Message)" + } + } + + if ($HealthCheck.Jobs.Status) { + $OutObj | Where-Object { $_.'Latest Result' -eq 'Failed' } | Set-Style -Style Critical -Property 'Latest Result' + $OutObj | Where-Object { $_.'Latest Result' -eq 'Warning' } | Set-Style -Style Warning -Property 'Latest Result' + $OutObj | Where-Object { $_.'Status' -eq 'Disabled' } | Set-Style -Style Warning -Property 'Status' + } + + $TableParams = @{ + Name = "Backup Copy Jobs - $VeeamBackupServer" + List = $false + ColumnWidths = 40, 15, 15, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Sort-Object -Property 'Name' |Table @TableParams + } + } + } + catch { + Write-PscriboMessage -IsWarning "Backup Copy Jobs Section: $($_.Exception.Message)" + } + } + end {} + +} diff --git a/Src/Private/Get-AbrVbrBackupCopyjobConf.ps1 b/Src/Private/Get-AbrVbrBackupCopyjobConf.ps1 new file mode 100644 index 0000000..ec5ea0f --- /dev/null +++ b/Src/Private/Get-AbrVbrBackupCopyjobConf.ps1 @@ -0,0 +1,640 @@ + +function Get-AbrVbrBackupCopyjobConf { + <# + .SYNOPSIS + Used by As Built Report to returns vmware backup copy jobs created in Veeam Backup & Replication. + .DESCRIPTION + Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. + .NOTES + Version: 0.8.0 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + Credits: Iain Brighton (@iainbrighton) - PScribo module + + .LINK + https://github.com/AsBuiltReport/AsBuiltReport.Veeam.VBR + #> + [CmdletBinding()] + param ( + + ) + + begin { + Write-PscriboMessage "Discovering Veeam VBR backup copy jobs information from $System." + } + + process { + try { + $Bkjobs = Get-VBRBackupCopyJob -WarningAction SilentlyContinue | Sort-Object -Property Name + if (($Bkjobs).count -gt 0) { + Section -Style Heading3 'Backup Copy Jobs Configuration' { + Paragraph "The following section details the configuration of backup copy jobs." + BlankLine + $OutObj = @() + foreach ($Bkjob in $Bkjobs) { + try { + Section -Style Heading4 $($Bkjob.Name) { + Section -Style NOTOCHeading4 -ExcludeFromTOC 'Common Information' { + $OutObj = @() + try { + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) common information." + $inObj = [ordered] @{ + 'Name' = $Bkjob.Name + 'Id' = $Bkjob.Id + 'Type' = $Bkjob.type + 'Copy Mode' = $Bkjob.Mode + 'Last Result' = $Bkjob.LastResult + 'Status' = $Bkjob.LastState + 'Next Run' = ConvertTo-EmptyToFiller $Bkjob.NextRun + 'Include database transaction log backup' = ConvertTo-TextYN $Bkjob.TransactionLogCopyEnabled + 'Description' = ConvertTo-EmptyToFiller $Bkjob.Description + 'Modified By' = (get-VBRJob -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Where-Object {$_.id -eq $Bkjob.Id}).Info.CommonInfo.ModifiedBy.FullName + } + $OutObj = [pscustomobject]$inobj + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + + if ($HealthCheck.Jobs.BestPractice) { + $OutObj | Where-Object { $Null -like $_.'Description' -or $_.'Description' -eq "-" } | Set-Style -Style Warning -Property 'Description' + $OutObj | Where-Object { $_.'Description' -match "Created by" } | Set-Style -Style Warning -Property 'Description' + $OutObj | Where-Object { $_.'Latest Result' -eq 'Failed' } | Set-Style -Style Critical -Property 'Latest Result' + $OutObj | Where-Object { $_.'Latest Result' -eq 'Warning' } | Set-Style -Style Warning -Property 'Latest Result' + $OutObj | Where-Object { $_.'Status' -eq 'Disabled' } | Set-Style -Style Warning -Property 'Status' + } + + $TableParams = @{ + Name = "Common Information - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($HealthCheck.Jobs.BestPractice) { + if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $_.'Description' -eq '-'}) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + if ($Bkjob.BackupJob) { + Section -Style NOTOCHeading5 -ExcludeFromTOC 'Backup Jobs Objects' { + $OutObj = @() + try { + foreach ($LinkedBkJob in $Bkjob.BackupJob) { + try { + Write-PscriboMessage "Discovered $($LinkedBkJob.Name) linked backup job objects." + $inObj = [ordered] @{ + 'Name' = $LinkedBkJob.Name + 'Type' = $LinkedBkJob.TypeToString + 'Size' = ConvertTo-FileSizeString $LinkedBkJob.Info.IncludedSize + 'Repository' = $LinkedBkJob.GetTargetRepository().Name + } + $OutObj += [pscustomobject]$inobj + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Backup Jobs Objects - $($Bkjob.Name)" + List = $false + ColumnWidths = 35, 25, 15, 25 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Sort-Object -Property 'Name' | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + if ($Bkjob.SourceRepository) { + Section -Style NOTOCHeading5 -ExcludeFromTOC 'Repositories Objects' { + $OutObj = @() + try { + foreach ($LinkedRepository in $Bkjob.SourceRepository) { + try { + Write-PscriboMessage "Discovered $($LinkedRepository.Name) linked repository objects." + if ($LinkedRepository.Type -eq "ExtendableRepository") { + $inObj = [ordered] @{ + 'Name' = $LinkedRepository.Name + 'Type' = "ScaleOut" + 'Size' = "$($LinkedRepository.GetContainer().CachedTotalSpace.InGigabytes) GB" + } + } else { + $inObj = [ordered] @{ + 'Name' = $LinkedRepository.Name + 'Type' = "Standard" + 'Size' = "$($LinkedRepository.GetContainer().CachedTotalSpace.InGigabytes) Gb" + } + } + $OutObj += [pscustomobject]$inobj + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Repositories Objects - $($Bkjob.Name)" + List = $false + ColumnWidths = 35, 35, 30 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Sort-Object -Property 'Name' | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + Section -Style NOTOCHeading5 -ExcludeFromTOC 'Target' { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) Target options." + if ($Bkjob.RetentionType -eq "RestoreDays") { + $RetainString = 'Retain Days To Keep' + $Retains = $Bkjob.RetentionNumber + } + elseif ($Bkjob.RetentionType -eq "RestorePoints") { + $RetainString = 'Restore Points' + $Retains = $Bkjob.RetentionNumber + } + $inObj = [ordered] @{ + 'Backup Repository' = $Bkjob.Target + 'Retention Type' = SWitch ($Bkjob.RetentionType) { + 'RestoreDays' {'Restore Days'} + 'RestorePoints' {'Restore Points'} + default {'Unknown'} + } + $RetainString = $Retains + } + if ($Bkjob.GFSOptions) { + if (-Not $Bkjob.GFSOptions.WeeklyGFSEnabled) { + $inObj.add('Keep Weekly full backup', ('Disabled')) + } else { + $inObj.add('Keep Weekly full backup for', ("$($Bkjob.GFSOptions.WeeklyOptions.RetentionPeriod) weeks,`r`nCreate weekly full on this day: $($Bkjob.GFSOptions.WeeklyOptions.SelectedDay)")) + } + if (-Not $Bkjob.GFSOptions.MonthlyGFSEnabled) { + $inObj.add('Keep Monthly full backup', ('Disabled')) + } else { + $inObj.add('Keep Monthly full backup for', ("$($Bkjob.GFSOptions.MonthlyOptions.RetentionPeriod) months,`r`nUse weekly full backup from the following week of the month: $($Bkjob.GFSOptions.MonthlyOptions.SelectedWeek)")) + } + if (-Not $Bkjob.GFSOptions.YearlyGFSEnabled) { + $inObj.add('Keep Yearly full backup', ('Disabled')) + } else { + $inObj.add('Keep Yearly full backup for', ("$($Bkjob.GFSOptions.YearlyOptions.RetentionPeriod) years,`r`nUse monthly full backup from the following month: $($Bkjob.GFSOptions.YearlyOptions.SelectedMonth)")) + } + $inObj.add('Read the entire RestorePoint fromSource Backup', (ConvertTo-TextYN $Bkjob.GFSOptions.ReadEntireRestorePoint)) + } + $OutObj = [pscustomobject]$inobj + + $TableParams = @{ + Name = "Target Options - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($InfoLevel.Jobs.BackupCopy -ge 2) { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Advanced Settings (Maintenance)" { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) maintenance options." + $inObj = [ordered] @{ + 'Storage-Level Corruption Guard (SLCG)' = ConvertTo-TextYN $Bkjob.HealthCheckOptions.Enabled + 'SLCG Schedule Type' = $Bkjob.HealthCheckOptions.ScheduleType + } + + if ($Bkjob.HealthCheckOptions.ScheduleType -eq 'Monthly') { + $inObj.add("SLCG Backup Monthly Schedule at", "Hour of Day: $($Bkjob.HealthCheckOptions.MonthlyPeriod)`r`nDay Number In Month: $($Bkjob.HealthCheckOptions.DayNumber)`r`nDay Of Week: $($Bkjob.HealthCheckOptions.DayOfWeek)`r`nDay of Month: $($Bkjob.HealthCheckOptions.DayOfMonth)`r`nMonths: $($Bkjob.HealthCheckOptions.SelectedMonths)") + + } elseif ($Bkjob.HealthCheckOptions.ScheduleType -eq 'Weekly') { + $inObj.add("SLCG Backup Weekly Schedule at", "Hour of Day: $($Bkjob.HealthCheckOptions.WeeklyPeriod)`r`nSelected Days: $($Bkjob.HealthCheckOptions.SelectedDays)") + + } + + $OutObj = [pscustomobject]$inobj + + if ($HealthCheck.Jobs.BestPractice) { + $OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq "No" } | Set-Style -Style Warning -Property 'Storage-Level Corruption Guard (SLCG)' + } + + $TableParams = @{ + Name = "Advanced Settings (Maintenance) - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($HealthCheck.Jobs.BestPractice) { + if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + if ($InfoLevel.Jobs.BackupCopy -ge 2) { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Advanced Settings (Storage)" { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) storage options." + $inObj = [ordered] @{ + 'Inline Data Deduplication' = ConvertTo-TextYN $Bkjob.StorageOptions.DataDeduplicationEnabled + 'Compression Level' = $Bkjob.StorageOptions.CompressionLevel + 'Enabled Backup File Encryption' = ConvertTo-TextYN $Bkjob.StorageOptions.EncryptionEnabled + 'Encryption Key' = ConvertTo-EmptyToFiller $Bkjob.StorageOptions.EncryptionKey.Description + } + $OutObj = [pscustomobject]$inobj + + if ($HealthCheck.Jobs.BestPractice) { + $OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'} | Set-Style -Style Warning -Property 'Enabled Backup File Encryption' + } + + $TableParams = @{ + Name = "Advanced Settings (Storage) - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($HealthCheck.Jobs.BestPractice) { + if ($OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'}) { + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + + if ($InfoLevel.Jobs.BackupCopy -ge 2) { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Advanced Settings (RPO Monitor)" { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) rpo monitor options." + $BackupJob = $Bkjob.RpoWarningOptions | Where-Object {$_.RpoType -eq 'BackupJob'} + $BackupLogJob = $Bkjob.RpoWarningOptions | Where-Object {$_.RpoType -eq 'BackupLogJob'} + + $inObj = [ordered] @{ + 'Alert me when new backup is not copied within' = "$($BackupJob.Value) $($BackupJob.TimeUnit)`r`nEnable:$(ConvertTo-TextYN $BackupJob.EnableRpoWarning)" + 'Alert me when new log backup is not copied within' = "$($BackupLogJob.Value) $($BackupLogJob.TimeUnit)`r`nEnabled:$(ConvertTo-TextYN $BackupLogJob.EnableRpoWarning)" + + } + $OutObj = [pscustomobject]$inobj + + $TableParams = @{ + Name = "Advanced Settings (RPO Monitor) - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + + if ($InfoLevel.Jobs.BackupCopy -ge 2) { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Advanced Settings (Notification)" { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) notification options." + $inObj = [ordered] @{ + 'Send Snmp Notification' = ConvertTo-TextYN $Bkjob.NotificationOptions.EnableSnmpNotification + 'Send Email Notification' = ConvertTo-TextYN $Bkjob.NotificationOptions.EnableAdditionalNotification + 'Email Notification Additional Addresses' = Switch ($Bkjob.NotificationOptions.AdditionalAddress) { + $Null {'--'} + default {$Bkjob.NotificationOptions.AdditionalAddress} + } + 'Email Notify Time' = $Bkjob.NotificationOptions.SendTime + 'Use Custom Email Notification Options' = ConvertTo-TextYN $Bkjob.NotificationOptions.UseNotificationOptions + 'Use Custom Notification Setting' = $Bkjob.NotificationOptions.NotificationSubject + 'Notify On Success' = ConvertTo-TextYN $Bkjob.NotificationOptions.NotifyOnSuccess + 'Notify On Warning' = ConvertTo-TextYN $Bkjob.NotificationOptions.NotifyOnWarning + 'Notify On Error' = ConvertTo-TextYN $Bkjob.NotificationOptions.NotifyOnError + 'Send notification' = Switch ($Bkjob.NotificationOptions.EnableDailyNotification) { + 'False' {'Immediately after each copied backup'} + 'True' {'Daily as a summary'} + default {'Unknown'} + } + } + $OutObj = [pscustomobject]$inobj + + $TableParams = @{ + Name = "Advanced Settings (Notification) - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + + if ($InfoLevel.Jobs.BackupCopy -ge 2) { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Advanced Settings (Script)" { + $OutObj = @() + try { + if ($Bkjob.ScriptOptions.Periodicity -eq 'Days') { + $FrequencyValue = $Bkjob.ScriptOptions.Days -join "," + $FrequencyText = 'Run Script on the Selected Days' + } + elseif ($Bkjob.ScriptOptions.Periodicity -eq 'Cycles') { + $FrequencyValue = $Bkjob.ScriptOptions.Frequency + $FrequencyText = 'Run Script Every Backup Session' + } + Write-PscriboMessage "Discovered $($Bkjob.Name) script options." + $inObj = [ordered] @{ + 'Run the Following Script Before' = ConvertTo-TextYN $Bkjob.ScriptOptions.PreScriptEnabled + 'Run Script Before the Job' = ConvertTo-EmptyToFiller $Bkjob.ScriptOptions.PreCommand + 'Run the Following Script After' = ConvertTo-TextYN $Bkjob.ScriptOptions.PostScriptEnabled + 'Run Script After the Job' = ConvertTo-EmptyToFiller $Bkjob.ScriptOptions.PostCommand + 'Run Script Frequency' = $Bkjob.ScriptOptions.Periodicity + $FrequencyText = $FrequencyValue + + } + $OutObj = [pscustomobject]$inobj + + $TableParams = @{ + Name = "Advanced Settings (Script) - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + Section -Style NOTOCHeading5 -ExcludeFromTOC 'Data Transfer' { + $OutObj = @() + try { + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) data transfer." + $inObj = [ordered] @{ + 'Use Wan accelerator' = Switch ($Bkjob.DataTransferMode) { + 'ThroughWanAccelerators' {'Yes'} + 'Direct' {'No'} + default {'Unkwnown'} + } + 'Source Wan accelerator' = ConvertTo-EmptyToFiller $Bkjob.SourceAccelerator.Name + 'Target Wan accelerator' = ConvertTo-EmptyToFiller $Bkjob.TargetAccelerator.Name + } + $OutObj += [pscustomobject]$inobj + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + + $TableParams = @{ + Name = "Data Transfer - $($Bkjob.Name)" + List = $True + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + if ($Bkjob.Mode -eq 'Periodic') { + Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) schedule options." + if ($Bkjob.ScheduleOptions.Type -eq "Daily") { + $ScheduleType = "Daily" + $Schedule = "Kind: $($Bkjob.ScheduleOptions.DailyOptions.Type) at $($Bkjob.ScheduleOptions.DailyOptions.Period.ToString()), Days of Week: $($Bkjob.ScheduleOptions.DailyOptions.DayOfWeek)" + } + elseif ($Bkjob.ScheduleOptions.Type -eq "Monthly") { + $ScheduleType = "Monthly" + $Schedule = "Day Of Month: $($Bkjob.ScheduleOptions.MonthlyOptions.DayOfMonth),`r`nDay Number In Month: $($Bkjob.ScheduleOptions.MonthlyOptions.DayNumberInMonth),`r`nDay Of Week: $($Bkjob.ScheduleOptions.MonthlyOptions.DayOfWeek),`r`nAt $($Bkjob.ScheduleOptions.MonthlyOptions.Period.ToString())," + } + elseif ($Bkjob.ScheduleOptions.Type -eq "Periodically") { + $ScheduleType = $Bkjob.ScheduleOptions.PeriodicallyOptions.PeriodicallyKind + $Schedule = "Full Period: $($Bkjob.ScheduleOptions.PeriodicallyOptions.FullPeriod),`r`nHourly Offset: $($Bkjob.ScheduleOptions.PeriodicallyOptions.HourlyOffset),`r`nUnit: $($Bkjob.ScheduleOptions.PeriodicallyOptions.Unit)" + } + elseif ($Bkjob.ScheduleOptions.Type -eq "AfterJob") { + $ScheduleType = 'AfterJob' + $Schedule = "After Job: $($BKjob.ScheduleOptions.Job.Name)" + } + $inObj = [ordered] @{ + 'Retry Failed Enabled?' = ConvertTo-TextYN $Bkjob.ScheduleOptions.RetryEnabled + 'Retry Failed item processing' = $Bkjob.ScheduleOptions.RetryCount + 'Wait before each retry' = "$($Bkjob.ScheduleOptions.RetryTimeout)/min" + 'Backup Window' = ConvertTo-TextYN $Bkjob.ScheduleOptions.BackupTerminationWindowEnabled + 'Shedule type' = $ScheduleType + 'Shedule Options' = $Schedule + } + $OutObj = [pscustomobject]$inobj + + $TableParams = @{ + Name = "Schedule Options - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($Bkjob.ScheduleOptions.BackupTerminationWindowEnabled) { + try { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Backup Window Time Period" { + Paragraph { + Text 'Permited \' -Color 81BC50 -Bold + Text ' Denied' -Color dddf62 -Bold + } + $OutObj = @() + $Days = 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' + $Hours24 = [ordered]@{ + 0 = 12 + 1 = 1 + 2 = 2 + 3 = 3 + 4 = 4 + 5 = 5 + 6 = 6 + 7 = 7 + 8 = 8 + 9 = 9 + 10 = 10 + 11 = 11 + 12 = 12 + 13 = 1 + 14 = 2 + 15 = 3 + 16 = 4 + 17 = 5 + 18 = 6 + 19 = 7 + 20 = 8 + 21 = 9 + 22 = 10 + 23 = 11 + } + + $ScheduleTimePeriod = $Bkjob.ScheduleOptions.TerminationWindow -split '(.{48})' | Where-Object {$_} + + foreach ($OBJ in $Hours24.GetEnumerator()) { + + $inObj = [ordered] @{ + 'H' = $OBJ.Value + 'Sun' = $ScheduleTimePeriod[0].Split(',')[$OBJ.Key] + 'Mon' = $ScheduleTimePeriod[1].Split(',')[$OBJ.Key] + 'Tue' = $ScheduleTimePeriod[2].Split(',')[$OBJ.Key] + 'Wed' = $ScheduleTimePeriod[3].Split(',')[$OBJ.Key] + 'Thu' = $ScheduleTimePeriod[4].Split(',')[$OBJ.Key] + 'Fri' = $ScheduleTimePeriod[5].Split(',')[$OBJ.Key] + 'Sat' = $ScheduleTimePeriod[6].Split(',')[$OBJ.Key] + } + $OutObj += $inobj + } + + $TableParams = @{ + Name = "Backup Window - $($Bkjob.Name)" + List = $true + ColumnWidths = 6,4,3,4,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4 + Key = 'H' + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + if ($OutObj) { + $OutObj2 = Table -Hashtable $OutObj @TableParams + $OutObj2.Rows | Where-Object {$_.Sun -eq "0"} | Set-Style -Style OFF -Property "Sun" + $OutObj2.Rows | Where-Object {$_.Mon -eq "0"} | Set-Style -Style OFF -Property "Mon" + $OutObj2.Rows | Where-Object {$_.Tue -eq "0"} | Set-Style -Style OFF -Property "Tue" + $OutObj2.Rows | Where-Object {$_.Wed -eq "0"} | Set-Style -Style OFF -Property "Wed" + $OutObj2.Rows | Where-Object {$_.Thu -eq "0"} | Set-Style -Style OFF -Property "Thu" + $OutObj2.Rows | Where-Object {$_.Fri -eq "0"} | Set-Style -Style OFF -Property "Fri" + $OutObj2.Rows | Where-Object {$_.Sat -eq "0"} | Set-Style -Style OFF -Property "Sat" + + $OutObj2.Rows | Where-Object {$_.Sun -eq "1"} | Set-Style -Style ON -Property "Sun" + $OutObj2.Rows | Where-Object {$_.Mon -eq "1"} | Set-Style -Style ON -Property "Mon" + $OutObj2.Rows | Where-Object {$_.Tue -eq "1"} | Set-Style -Style ON -Property "Tue" + $OutObj2.Rows | Where-Object {$_.Wed -eq "1"} | Set-Style -Style ON -Property "Wed" + $OutObj2.Rows | Where-Object {$_.Thu -eq "1"} | Set-Style -Style ON -Property "Thu" + $OutObj2.Rows | Where-Object {$_.Fri -eq "1"} | Set-Style -Style ON -Property "Fri" + $OutObj2.Rows | Where-Object {$_.Sat -eq "1"} | Set-Style -Style ON -Property "Sat" + $OutObj2 + } + } + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + if ($Bkjob.Mode -eq 'Immediate') { + Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { + $OutObj = @() + try { + Write-PscriboMessage "Discovered $($Bkjob.Name) schedule options." + $inObj = [ordered] @{ + 'Retry Failed Enabled?' = ConvertTo-TextYN $Bkjob.ScheduleOptions.RetryEnabled + 'Retry Failed item processing' = $Bkjob.ScheduleOptions.RetryCount + 'Wait before each retry' = "$($Bkjob.ScheduleOptions.RetryTimeout)/min" + 'Backup Window' = ConvertTo-TextYN $Bkjob.ScheduleOptions.BackupTerminationWindowEnabled + 'Shedule type' = $Bkjob.ScheduleOptions.Type + 'Shedule Options' = "Continuously" + } + $OutObj = [pscustomobject]$inobj + + $TableParams = @{ + Name = "Schedule Options - $($Bkjob.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + end {} + +} \ No newline at end of file diff --git a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 index 5e7c768..c1c8f6d 100644 --- a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 @@ -302,6 +302,11 @@ function Invoke-AsBuiltReport.Veeam.VBR { Get-AbrVbrFileShareBackupjob Get-AbrVbrFileShareBackupjobConf } + Write-PScriboMessage "Backup Copy Jobs InfoLevel set at $($InfoLevel.Jobs.BackupCopy)." + if ($InfoLevel.Jobs.BackupCopy -ge 1 -and ((Get-Item "C:\Program Files\Veeam\Backup and Replication\Console\Veeam.Backup.PowerShell.dll").VersionInfo.ProductVersion -ge 12)) { + Get-AbrVbrBackupCopyjob + Get-AbrVbrBackupCopyjobConf + } } } } From 7b30ea6e6f3ab263535ce8f8058f9c14112e949c Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Wed, 12 Jul 2023 14:11:14 -0400 Subject: [PATCH 5/8] Fix V12 - No Backup Copy Jobs detail in report #104 --- AsBuiltreport.Veeam.VBR.json | 1 + 1 file changed, 1 insertion(+) diff --git a/AsBuiltreport.Veeam.VBR.json b/AsBuiltreport.Veeam.VBR.json index 1baf5a3..dcaeef0 100644 --- a/AsBuiltreport.Veeam.VBR.json +++ b/AsBuiltreport.Veeam.VBR.json @@ -60,6 +60,7 @@ }, "Jobs": { "Backup": 1, + "BackupCopy": 1, "Tape": 1, "Surebackup": 1, "Agent": 1, From 7745406e837e3ec5bce4d5b8526e4e90574884e8 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Wed, 12 Jul 2023 14:11:25 -0400 Subject: [PATCH 6/8] Improved health check recommendation look and feel --- AsBuiltReport.Veeam.VBR.psd1 | 2 +- CHANGELOG.md | 10 +++ Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 | 2 +- Src/Private/Get-AbrVbrBackupRepository.ps1 | 2 +- Src/Private/Get-AbrVbrBackupServerInfo.ps1 | 45 +--------- Src/Private/Get-AbrVbrBackupToTape.ps1 | 2 +- Src/Private/Get-AbrVbrBackupjob.ps1 | 7 +- Src/Private/Get-AbrVbrBackupjobHyperV.ps1 | 66 ++++++++------ Src/Private/Get-AbrVbrBackupjobVMware.ps1 | 87 +++++++++++-------- Src/Private/Get-AbrVbrCloudConnectCG.ps1 | 2 +- Src/Private/Get-AbrVbrCloudConnectGP.ps1 | 2 +- Src/Private/Get-AbrVbrCloudConnectTenant.ps1 | 2 +- .../Get-AbrVbrConfigurationBackupSetting.ps1 | 2 +- .../Get-AbrVbrEmailNotificationSetting.ps1 | 2 +- .../Get-AbrVbrEnterpriseManagerInfo.ps1 | 2 +- Src/Private/Get-AbrVbrFileShareBackupjob.ps1 | 7 ++ .../Get-AbrVbrFileShareBackupjobConf.ps1 | 2 +- Src/Private/Get-AbrVbrFileToTape.ps1 | 2 +- .../Get-AbrVbrGlobalNotificationSetting.ps1 | 2 +- Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 | 2 +- Src/Private/Get-AbrVbrObjectRepository.ps1 | 2 +- Src/Private/Get-AbrVbrReplFailoverPlan.ps1 | 2 +- Src/Private/Get-AbrVbrRepljobHyperV.ps1 | 2 +- Src/Private/Get-AbrVbrRepljobVMware.ps1 | 2 +- Src/Private/Get-AbrVbrScaleOutRepository.ps1 | 2 +- Src/Private/Get-AbrVbrSecInfraHard.ps1 | 2 +- Src/Private/Get-AbrVbrSureBackup.ps1 | 2 +- Src/Private/Get-AbrVbrSureBackupjobconf.ps1 | 2 +- Src/Private/Get-AbrVbrTapeMediaPool.ps1 | 2 +- Src/Private/Get-AbrVbrTapeServer.ps1 | 2 +- Src/Private/Get-AbrVbrTapeVault.ps1 | 2 +- 31 files changed, 139 insertions(+), 133 deletions(-) diff --git a/AsBuiltReport.Veeam.VBR.psd1 b/AsBuiltReport.Veeam.VBR.psd1 index 5c81808..62f6cd0 100644 --- a/AsBuiltReport.Veeam.VBR.psd1 +++ b/AsBuiltReport.Veeam.VBR.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.Veeam.VBR.psm1' # Version number of this module. -ModuleVersion = '0.7.3' +ModuleVersion = '0.8.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/CHANGELOG.md b/CHANGELOG.md index 03f1bcb..b9a23d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # :arrows_clockwise: Veeam VBR As Built Report Changelog +## [0.8.0] - 2023-07-13 + +### Added + +- Added a separated Backup Copy Job section for v12 edition + +### Changed + +- Improved Health Check recommendation text + ## [0.7.3] - 2023-06-13 ### Added diff --git a/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 b/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 index 44e9763..36af256 100644 --- a/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 +++ b/Src/Private/Get-AbrVbrAgentBackupjobConf.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrAgentBackupjobConf { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrBackupRepository.ps1 b/Src/Private/Get-AbrVbrBackupRepository.ps1 index fa066bb..7c8ec2b 100644 --- a/Src/Private/Get-AbrVbrBackupRepository.ps1 +++ b/Src/Private/Get-AbrVbrBackupRepository.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrBackupRepository { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.1 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 index de2f5dc..baa1209 100644 --- a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 +++ b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrBackupServerInfo { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.1 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -520,49 +520,6 @@ function Get-AbrVbrBackupServerInfo { catch { Write-PscriboMessage -IsWarning "Backup Server Service Status Section: $($_.Exception.Message)" } - try { - Write-PScriboMessage "Infrastructure Backup Server InfoLevel set at $($InfoLevel.Infrastructure.BackupServer)." - if ($InfoLevel.Infrastructure.BackupServer -ge 3) { - $NetStats = Get-VeeamNetStat -Session $PssSession | Where-Object { $_.ProcessName -Like "*veeam*" } | Sort-Object -Property State,LocalPort - Write-PscriboMessage "Collecting Backup Server Network Statistics from $($BackupServer.Name)." - if ($NetStats) { - Section -Style Heading4 "HealthCheck - Network Statistics" { - $OutObj = @() - foreach ($NetStat in $NetStats) { - try { - $inObj = [ordered] @{ - 'Proto' = $NetStat.Protocol - 'Local IP' = $NetStat.LocalAddress - 'Local Port' = $NetStat.LocalPort - 'Remote IP' = $NetStat.RemoteAddress - 'Remote Port' = $NetStat.RemotePort - 'State' = $NetStat.State - 'Process Name' = $NetStat.ProcessName - 'PID' = $NetStat.PID - } - $OutObj += [pscustomobject]$inobj - } - catch { - Write-PscriboMessage -IsWarning "Backup Server Network Statistics $($NetStat.Protocol) Section: $($_.Exception.Message)" - } - } - - $TableParams = @{ - Name = "HealthCheck - Network Statistics - $($BackupServer.Name.Split(".")[0])" - List = $false - ColumnWidths = 8, 16, 8, 16, 9, 16, 19, 8 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $OutObj | Table @TableParams - } - } - } - } - catch { - Write-PscriboMessage -IsWarning "Backup Server Network Statistics Section: $($_.Exception.Message)" - } } } } diff --git a/Src/Private/Get-AbrVbrBackupToTape.ps1 b/Src/Private/Get-AbrVbrBackupToTape.ps1 index 8aa6ddb..024a0ce 100644 --- a/Src/Private/Get-AbrVbrBackupToTape.ps1 +++ b/Src/Private/Get-AbrVbrBackupToTape.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrBackupToTape { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrBackupjob.ps1 b/Src/Private/Get-AbrVbrBackupjob.ps1 index 1315129..6fd9345 100644 --- a/Src/Private/Get-AbrVbrBackupjob.ps1 +++ b/Src/Private/Get-AbrVbrBackupjob.ps1 @@ -40,9 +40,10 @@ function Get-AbrVbrBackupjob { 'True' {'Enabled'} } 'Latest Result' = $Bkjob.info.LatestStatus - 'Scheduled?' = Switch ([string]::IsNullOrEmpty($Bkjob.GetScheduleOptions().NextRun)) { - $true {'No'} - default {'Yes'} + 'Scheduled?' = Switch ($Bkjob.IsScheduleEnabled) { + 'True' {'Yes'} + 'False' {'No'} + default {'Unknown'} } } $OutObj += [pscustomobject]$inobj diff --git a/Src/Private/Get-AbrVbrBackupjobHyperV.ps1 b/Src/Private/Get-AbrVbrBackupjobHyperV.ps1 index f7abce1..2771ee2 100644 --- a/Src/Private/Get-AbrVbrBackupjobHyperV.ps1 +++ b/Src/Private/Get-AbrVbrBackupjobHyperV.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrBackupjobHyperV { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -107,8 +107,12 @@ function Get-AbrVbrBackupjobHyperV { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } @@ -158,27 +162,31 @@ function Get-AbrVbrBackupjobHyperV { try { try { Write-PscriboMessage "Discovered $($Bkjob.Name) data transfer." - try { - $TargetWanAccelerator = $Bkjob.GetTargetWanAccelerator().Name - } - catch { - Write-PscriboMessage -IsWarning "Hyper-V Backup Jobs Data Transfer Section: $($_.Exception.Message)" - } - try { - $SourceWanAccelerator = $Bkjob.GetSourceWanAccelerator().Name - } - catch { - Write-PscriboMessage -IsWarning "Hyper-V Backup Jobs Data Transfer Section: $($_.Exception.Message)" + if ($Bkjob.IsWanAcceleratorEnabled()) { + try { + $TargetWanAccelerator = $Bkjob.GetTargetWanAccelerator().Name + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + try { + $SourceWanAccelerator = $Bkjob.GetSourceWanAccelerator().Name + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } } $inObj = [ordered] @{ 'Use Wan accelerator' = ConvertTo-TextYN $Bkjob.IsWanAcceleratorEnabled() - 'Source Wan accelerator' = Switch ($SourceWanAccelerator) { - $null {'Unknown'} - default {$SourceWanAccelerator} + 'Source Wan accelerator' = Switch ($Bkjob.IsWanAcceleratorEnabled()) { + 'False' {'Direct Mode'} + 'True' {$SourceWanAccelerator} + default {'Unknown'} } - 'Target Wan accelerator' = Switch ($TargetWanAccelerator) { - $null {'Unknown'} - default {$TargetWanAccelerator} + 'Target Wan accelerator' = Switch ($Bkjob.IsWanAcceleratorEnabled()) { + 'False' {'Direct Mode'} + 'True' {$TargetWanAccelerator} + default {'Unknown'} } } $OutObj += [pscustomobject]$inobj @@ -339,8 +347,12 @@ function Get-AbrVbrBackupjobHyperV { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } } } } @@ -398,8 +410,12 @@ function Get-AbrVbrBackupjobHyperV { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" + } } } } @@ -721,7 +737,7 @@ function Get-AbrVbrBackupjobHyperV { } } } - if ($Bkjob.GetScheduleOptions().NextRun) { + if ($Bkjob.IsScheduleEnabled) { Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { $OutObj = @() try { diff --git a/Src/Private/Get-AbrVbrBackupjobVMware.ps1 b/Src/Private/Get-AbrVbrBackupjobVMware.ps1 index 7614e12..3e583c5 100644 --- a/Src/Private/Get-AbrVbrBackupjobVMware.ps1 +++ b/Src/Private/Get-AbrVbrBackupjobVMware.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrBackupjobVMware { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -107,8 +107,12 @@ function Get-AbrVbrBackupjobVMware { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Description' -match 'Created by' -or $Null -like $_.'Description'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is a general rule of good practice to establish well-defined descriptions. This helps to speed up the fault identification process, as well as enabling better documentation of the environment." + } } } } @@ -203,27 +207,31 @@ function Get-AbrVbrBackupjobVMware { try { try { Write-PscriboMessage "Discovered $($Bkjob.Name) data transfer." - try { - $TargetWanAccelerator = $Bkjob.GetTargetWanAccelerator().Name - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - try { - $SourceWanAccelerator = $Bkjob.GetSourceWanAccelerator().Name - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message + if ($Bkjob.IsWanAcceleratorEnabled()) { + try { + $TargetWanAccelerator = $Bkjob.GetTargetWanAccelerator().Name + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + try { + $SourceWanAccelerator = $Bkjob.GetSourceWanAccelerator().Name + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } } $inObj = [ordered] @{ 'Use Wan accelerator' = ConvertTo-TextYN $Bkjob.IsWanAcceleratorEnabled() - 'Source Wan accelerator' = Switch ($SourceWanAccelerator) { - $null {'Unknown'} - default {$SourceWanAccelerator} + 'Source Wan accelerator' = Switch ($Bkjob.IsWanAcceleratorEnabled()) { + 'False' {'Direct Mode'} + 'True' {$SourceWanAccelerator} + default {'Unknown'} } - 'Target Wan accelerator' = Switch ($TargetWanAccelerator) { - $null {'Unknown'} - default {$TargetWanAccelerator} + 'Target Wan accelerator' = Switch ($Bkjob.IsWanAcceleratorEnabled()) { + 'False' {'Direct Mode'} + 'True' {$TargetWanAccelerator} + default {'Unknown'} } } $OutObj += [pscustomobject]$inobj @@ -384,8 +392,12 @@ function Get-AbrVbrBackupjobVMware { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Storage-Level Corruption Guard (SLCG)' -eq 'No' }) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to use storage-level corruption guard for any backup job with no active full backups scheduled. Synthetic full backups are still 'incremental forever' and may suffer from corruption over time. Storage-level corruption guard was introduced to provide a greater level of confidence in integrity of the backups." + } } } } @@ -443,8 +455,12 @@ function Get-AbrVbrBackupjobVMware { $OutObj | Table @TableParams if ($HealthCheck.Jobs.BestPractice) { if ($OutObj | Where-Object { $_.'Enabled Backup File Encryption' -eq 'No'}) { - Paragraph "Health Check:" -Italic -Bold -Underline - Paragraph "Best Practice: Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" -Italic -Bold + Paragraph "Health Check:" -Bold -Underline + Blankline + Paragraph { + Text "Best Practice:" -Bold + Text "Backup and replica data is a high potential source of vulnerability. To secure data stored in backups and replicas, use Veeam Backup & Replication inbuilt encryption to protect data in backups" + } } } } @@ -766,7 +782,7 @@ function Get-AbrVbrBackupjobVMware { } } } - if ($Bkjob.GetScheduleOptions().NextRun) { + if ($Bkjob.IsScheduleEnabled) { Section -Style NOTOCHeading5 -ExcludeFromTOC "Schedule" { $OutObj = @() try { @@ -811,13 +827,13 @@ function Get-AbrVbrBackupjobVMware { } $OutObj | Table @TableParams if ($Bkjob.ScheduleOptions.OptionsBackupWindow.IsEnabled -or $Bkjob.ScheduleOptions.OptionsContinuous.Enabled) { - Section -Style NOTOCHeading6 -ExcludeFromTOC "Backup Window Time Period" { - Paragraph { - Text 'Permited \' -Color 81BC50 -Bold - Text ' Denied' -Color dddf62 -Bold - } - $OutObj = @() - try { + try { + Section -Style NOTOCHeading6 -ExcludeFromTOC "Backup Window Time Period" { + Paragraph { + Text 'Permited \' -Color 81BC50 -Bold + Text ' Denied' -Color dddf62 -Bold + } + $OutObj = @() $Days = 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' $Hours24 = [ordered]@{ 0 = 12 @@ -849,7 +865,7 @@ function Get-AbrVbrBackupjobVMware { foreach ($Day in $Days) { $Regex = [Regex]::new("(?<=<$Day>)(.*)(?=)") - if ($Bkjob.TypeToString -eq "VMware Backup Copy") { + if ($Bkjob.TypeToString -eq "VMware Backup Copy" -or $Bkjob.TypeToString -eq "Backup Copy") { $BackupWindow = $Bkjob.ScheduleOptions.OptionsContinuous.Schedule } else {$BackupWindow = $Bkjob.ScheduleOptions.OptionsBackupWindow.BackupWindow} $Match = $Regex.Match($BackupWindow) @@ -903,9 +919,8 @@ function Get-AbrVbrBackupjobVMware { $OutObj2 } } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message } } } diff --git a/Src/Private/Get-AbrVbrCloudConnectCG.ps1 b/Src/Private/Get-AbrVbrCloudConnectCG.ps1 index 9e84dba..91cdc9c 100644 --- a/Src/Private/Get-AbrVbrCloudConnectCG.ps1 +++ b/Src/Private/Get-AbrVbrCloudConnectCG.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrCloudConnectCG { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrCloudConnectGP.ps1 b/Src/Private/Get-AbrVbrCloudConnectGP.ps1 index 3c1f59b..cc41a88 100644 --- a/Src/Private/Get-AbrVbrCloudConnectGP.ps1 +++ b/Src/Private/Get-AbrVbrCloudConnectGP.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrCloudConnectGP { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 b/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 index d6a7897..786f4c0 100644 --- a/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 +++ b/Src/Private/Get-AbrVbrCloudConnectTenant.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrCloudConnectTenant { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 b/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 index 547b1e7..dee4b5f 100644 --- a/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 +++ b/Src/Private/Get-AbrVbrConfigurationBackupSetting.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrConfigurationBackupSetting { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.1 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 b/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 index eb89aba..24548f1 100644 --- a/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 +++ b/Src/Private/Get-AbrVbrEmailNotificationSetting.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrEmailNotificationSetting { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 b/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 index 9255f9f..98c65b4 100644 --- a/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 +++ b/Src/Private/Get-AbrVbrEnterpriseManagerInfo.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrEnterpriseManagerInfo { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.1 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrFileShareBackupjob.ps1 b/Src/Private/Get-AbrVbrFileShareBackupjob.ps1 index 717243e..8934245 100644 --- a/Src/Private/Get-AbrVbrFileShareBackupjob.ps1 +++ b/Src/Private/Get-AbrVbrFileShareBackupjob.ps1 @@ -55,6 +55,13 @@ function Get-AbrVbrFileShareBackupjob { } } + if ($HealthCheck.Jobs.Status) { + $OutObj | Where-Object { $_.'Latest Result' -eq 'Failed' } | Set-Style -Style Critical -Property 'Latest Result' + $OutObj | Where-Object { $_.'Latest Result' -eq 'Warning' } | Set-Style -Style Warning -Property 'Latest Result' + $OutObj | Where-Object { $_.'Status' -eq 'Disabled' } | Set-Style -Style Warning -Property 'Status' + $OutObj | Where-Object { $_.'Scheduled?' -eq 'No' } | Set-Style -Style Warning -Property 'Scheduled?' + } + $TableParams = @{ Name = "File Share Backup Jobs - $VeeamBackupServer" List = $false diff --git a/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 b/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 index ae6d7cf..a4638c5 100644 --- a/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 +++ b/Src/Private/Get-AbrVbrFileShareBackupjobConf.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrFileShareBackupjobConf { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrFileToTape.ps1 b/Src/Private/Get-AbrVbrFileToTape.ps1 index a7ec34e..ad34e3f 100644 --- a/Src/Private/Get-AbrVbrFileToTape.ps1 +++ b/Src/Private/Get-AbrVbrFileToTape.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrFileToTape { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 b/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 index 3538243..5fa86b0 100644 --- a/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 +++ b/Src/Private/Get-AbrVbrGlobalNotificationSetting.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrGlobalNotificationSetting { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 b/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 index 84ef04d..8d6032d 100644 --- a/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 +++ b/Src/Private/Get-AbrVbrNetworkTrafficRule.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrNetworkTrafficRule { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.3 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrObjectRepository.ps1 b/Src/Private/Get-AbrVbrObjectRepository.ps1 index 5958a9d..05165ab 100644 --- a/Src/Private/Get-AbrVbrObjectRepository.ps1 +++ b/Src/Private/Get-AbrVbrObjectRepository.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrObjectRepository { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 b/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 index 154a7e2..a4481f9 100644 --- a/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 +++ b/Src/Private/Get-AbrVbrReplFailoverPlan.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrReplFailoverPlan { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrRepljobHyperV.ps1 b/Src/Private/Get-AbrVbrRepljobHyperV.ps1 index 384b42d..3223c0d 100644 --- a/Src/Private/Get-AbrVbrRepljobHyperV.ps1 +++ b/Src/Private/Get-AbrVbrRepljobHyperV.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrRepljobHyperV { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrRepljobVMware.ps1 b/Src/Private/Get-AbrVbrRepljobVMware.ps1 index ae699ef..c53f028 100644 --- a/Src/Private/Get-AbrVbrRepljobVMware.ps1 +++ b/Src/Private/Get-AbrVbrRepljobVMware.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrRepljobVMware { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrScaleOutRepository.ps1 b/Src/Private/Get-AbrVbrScaleOutRepository.ps1 index f9465a5..9fded65 100644 --- a/Src/Private/Get-AbrVbrScaleOutRepository.ps1 +++ b/Src/Private/Get-AbrVbrScaleOutRepository.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrScaleOutRepository { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrSecInfraHard.ps1 b/Src/Private/Get-AbrVbrSecInfraHard.ps1 index 476821d..cd331f2 100644 --- a/Src/Private/Get-AbrVbrSecInfraHard.ps1 +++ b/Src/Private/Get-AbrVbrSecInfraHard.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrSecInfraHard { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.6.0 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrSureBackup.ps1 b/Src/Private/Get-AbrVbrSureBackup.ps1 index 53120ed..682d518 100644 --- a/Src/Private/Get-AbrVbrSureBackup.ps1 +++ b/Src/Private/Get-AbrVbrSureBackup.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrSureBackup { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 b/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 index 98ceef4..2d2b4a4 100644 --- a/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 +++ b/Src/Private/Get-AbrVbrSureBackupjobconf.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrSureBackupjobconf { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrTapeMediaPool.ps1 b/Src/Private/Get-AbrVbrTapeMediaPool.ps1 index ec48cf9..716b7fb 100644 --- a/Src/Private/Get-AbrVbrTapeMediaPool.ps1 +++ b/Src/Private/Get-AbrVbrTapeMediaPool.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrTapeMediaPool { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrTapeServer.ps1 b/Src/Private/Get-AbrVbrTapeServer.ps1 index c177966..31da07e 100644 --- a/Src/Private/Get-AbrVbrTapeServer.ps1 +++ b/Src/Private/Get-AbrVbrTapeServer.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrTapeServer { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux diff --git a/Src/Private/Get-AbrVbrTapeVault.ps1 b/Src/Private/Get-AbrVbrTapeVault.ps1 index e6f2cf7..2f46b76 100644 --- a/Src/Private/Get-AbrVbrTapeVault.ps1 +++ b/Src/Private/Get-AbrVbrTapeVault.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrTapeVault { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux From 0f1c24400afa262b9f23fe611160549fa9a49a6f Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Wed, 12 Jul 2023 17:08:00 -0400 Subject: [PATCH 7/8] v0.8.0 release --- CHANGELOG.md | 6 +++++- Src/Private/Get-AbrVbrSureBackup.ps1 | 2 +- Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a23d2..af83af3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,11 @@ ### Changed -- Improved Health Check recommendation text +- Improved Health Check recommendations + +### Fixed + +- Fix [#104](https://github.com/AsBuiltReport/AsBuiltReport.Veeam.VBR/issues/104) ## [0.7.3] - 2023-06-13 diff --git a/Src/Private/Get-AbrVbrSureBackup.ps1 b/Src/Private/Get-AbrVbrSureBackup.ps1 index 682d518..33026e6 100644 --- a/Src/Private/Get-AbrVbrSureBackup.ps1 +++ b/Src/Private/Get-AbrVbrSureBackup.ps1 @@ -222,7 +222,7 @@ function Get-AbrVbrSureBackup { 'Production Network' = $NetworkOption.ProductionNetwork.Name 'Isolated IP Address' = $NetworkOption.IsolatedIPAddress 'Access IP Address' = $NetworkOption.AccessIPAddress - 'Notes' = $NetworkOption.Note + 'Notes' = ConvertTo-EmptyToFiller $NetworkOption.Note } $OutObj += [pscustomobject]$inobj diff --git a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 index c1c8f6d..6017ec8 100644 --- a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 @@ -5,7 +5,7 @@ function Invoke-AsBuiltReport.Veeam.VBR { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.2 + Version: 0.8.0 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux From 96464b76379c4920b747718092ca1a18805c5763 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Wed, 12 Jul 2023 21:22:58 -0400 Subject: [PATCH 8/8] Updated Readme --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7054cdd..91a0d7d 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,8 @@ The Veeam VBR As Built Report supports the following Veeam Backup & Replication - Veeam Backup & Replication V11 (Standard, Enterprise & Enterprise Plus Edition) - Veeam Backup & Replication V12 (Standard, Enterprise & Enterprise Plus Edition) +:exclamation: Community Edition is not supported :exclamation: + ### PowerShell This report is compatible with the following PowerShell versions; @@ -197,6 +199,7 @@ The table below outlines the default and maximum **InfoLevel** settings for each | Sub-Schema | Default Setting | Maximum Setting | |--------------|:---------------:|:---------------:| | Backup | 1 | 2 | +| BackupCopy | 1 | 2 | | Tape | 1 | 2 | | Surebackup | 1 | 2 | | Agent | 1 | 2 | @@ -254,5 +257,5 @@ PS C:\> New-AsBuiltReport -Report Veeam.VBR -Target veeam-vbr.pharmax.local -Use ## :x: Known Issues -- Since many of Veeam's features depend on the Standard+ license, the Community edition will not be supported. -- If the Veeam Backup Server is not joined to an Active Directory domain (WorkGroup Auth), the PSDefaultAuthentication option must be set to Negotiate. If it is not, some of the report sections will be missing +- Since many of Veeam's features depend on the Standard+ license, the Community edition is not supported. +- If the Veeam Backup Server is not joined to an Active Directory domain (WorkGroup Auth), the PSDefaultAuthentication option must be set to Negotiate. If it is not, some of the report sections will be missing.