From ad085492f1a9e08be1c777587d45f8b4aea4bd69 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Sun, 16 Jun 2024 11:33:20 -0400 Subject: [PATCH 01/14] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b1a7899..7034351 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ Please refer to the AsBuiltReport [website](https://www.asbuiltreport.com) for m # :books: Sample Reports -## Sample Report - Veeam Style +## Sample Report - Veeam Style with EnableHealthCheck Sample Veeam VBR As Built Report HTML file: [Sample Report](https://htmlpreview.github.io/?https://raw.githubusercontent.com/AsBuiltReport/AsBuiltReport.Veeam.VBR/dev/Samples/Sample%20Veeam%20Backup%20%26%20Replication%20As%20Built%20Report.html) -## Sample Diagram - Veeam Style +## Sample Diagram Sample Veeam VBR As Built Report Diagram file: [Sample Diagram](Samples/AsBuiltReport.Veeam.VBR.png) @@ -275,4 +275,4 @@ PS C:\> New-AsBuiltReport -Report Veeam.VBR -Target veeam-vbr.pharmax.local -Use - 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. -- This project uses the PScribo module to generate the report. It has been identified that the EvotecIT module `PSWriteWord` uses the same cmdlet names. In order for this report to be generated correctly it is necessary to uninstall the `PSWriteWord` module. \ No newline at end of file +- This project uses the PScribo module to generate the report. It has been identified that the EvotecIT module `PSWriteWord` uses the same cmdlet names. In order for this report to be generated correctly it is necessary to uninstall the `PSWriteWord` module. From 5497e0b3756de5b932de9562885be92726acedb4 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 08:16:17 -0400 Subject: [PATCH 02/14] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7034351..52a3050 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ Buy Me a Coffee at ko-fi.com

+# This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates. + # Veeam VBR As Built Report Veeam VBR As Built Report is a PowerShell module which works in conjunction with [AsBuiltReport.Core](https://github.com/AsBuiltReport/AsBuiltReport.Core). From 94ffb9023ae8557b7536c0ef574900d099b8e310 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 08:31:06 -0400 Subject: [PATCH 03/14] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a33f16..3a72dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +##### This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates. + ## [0.8.7] - 2024-05-28 ### Added From 40e1226b4267155e64ed1c0b92ff6662a02f6585 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 08:59:30 -0400 Subject: [PATCH 04/14] Update AsBuiltReport.Veeam.VBR.psd1 --- AsBuiltReport.Veeam.VBR.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsBuiltReport.Veeam.VBR.psd1 b/AsBuiltReport.Veeam.VBR.psd1 index b2da5dd..dcf5d85 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.8.7' + ModuleVersion = '0.8.8' # Supported PSEditions # CompatiblePSEditions = @() From 59640c9db98ef7c394b638a750f964d895e31262 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 08:59:55 -0400 Subject: [PATCH 05/14] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a72dca..29499f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ##### This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates. +## [0.8.8] - Unreleased + +### Added + ## [0.8.7] - 2024-05-28 ### Added From f80025ccf02c1cd144f8fb086d59406df93c4e21 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 11:55:29 -0400 Subject: [PATCH 06/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52a3050..c855ffd 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Buy Me a Coffee at ko-fi.com

-# This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates. +#### This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates. # Veeam VBR As Built Report From 1729dc2782e73579d9e3391f3bdd5ac4d2b67184 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 14:15:08 -0400 Subject: [PATCH 07/14] Added Diagrammer.Core to the module requirements --- .github/workflows/Release.yml | 4 ++++ AsBuiltReport.Veeam.VBR.psd1 | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 10c4cf2..b7dfe59 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -21,6 +21,10 @@ jobs: shell: pwsh run: | Install-Module -Name PScriboCharts -Repository PSGallery -Force + - name: Install Diagrammer.Core module + shell: pwsh + run: | + Install-Module -Name Diagrammer.Core -Repository PSGallery -Force - name: Install Veeam.Diagrammer module shell: pwsh run: | diff --git a/AsBuiltReport.Veeam.VBR.psd1 b/AsBuiltReport.Veeam.VBR.psd1 index dcf5d85..2059bb9 100644 --- a/AsBuiltReport.Veeam.VBR.psd1 +++ b/AsBuiltReport.Veeam.VBR.psd1 @@ -61,6 +61,10 @@ ModuleName = 'PScriboCharts'; ModuleVersion = '0.9.0' } + @{ + ModuleName = 'Diagrammer.Core'; + ModuleVersion = '0.2.1' + } @{ ModuleName = 'Veeam.Diagrammer'; ModuleVersion = '0.6.0' From a9fa495f9a93f8a93e1700a484ec431a4a7f29f2 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Tue, 18 Jun 2024 14:15:26 -0400 Subject: [PATCH 08/14] Improved error logging --- Src/Private/Get-AbrVbrBackupProxy.ps1 | 54 +++++++++++++++---- Src/Private/Get-AbrVbrBackupServerInfo.ps1 | 14 +++-- Src/Private/Get-AbrVbrDiagramObjects.ps1 | 13 ++++- Src/Private/Get-AbrVbrRepljobHyperV.ps1 | 4 +- Src/Private/Get-AbrVbrRepljobVMware.ps1 | 4 +- Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 | 4 +- 6 files changed, 74 insertions(+), 19 deletions(-) diff --git a/Src/Private/Get-AbrVbrBackupProxy.ps1 b/Src/Private/Get-AbrVbrBackupProxy.ps1 index a5a526f..94f0ee6 100644 --- a/Src/Private/Get-AbrVbrBackupProxy.ps1 +++ b/Src/Private/Get-AbrVbrBackupProxy.ps1 @@ -6,7 +6,7 @@ function Get-AbrVbrBackupProxy { .DESCRIPTION Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.8.7 + Version: 0.8.8 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -122,8 +122,16 @@ function Get-AbrVbrBackupProxy { if (Test-Connection -ComputerName $BackupProxy.Host.Name -Quiet -Count 2) { try { Write-PScriboMessage "Collecting Backup Proxy Inventory Summary from $($BackupProxy.Host.Name)." - $CimSession = New-CimSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication - $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + # $CimSession = New-CimSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication + $CimSession = try { New-CimSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'HardwareInventory' -ErrorAction Stop } catch { Write-PScriboMessage -IsWarning "VMware Backup Proxies Hardware/Software Section: New-CimSession: Unable to connect to $($BackupProxy.Host.Name): $($_.Exception.MessageId)" } + + $PssSession = try { New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction Stop -Name 'VMwareHardwareInventory' } catch { + if (-Not $_.Exception.MessageId) { + $ErrorMessage = $_.FullyQualifiedErrorId + } else { $ErrorMessage = $_.Exception.MessageId } + Write-PScriboMessage -IsWarning "VMware Backup Proxies Hardware/Software Section: New-PSSession: Unable to connect to $($BackupProxy.Host.Name): $ErrorMessage" + } + # $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue if ($PssSession) { $HW = Invoke-Command -Session $PssSession -ScriptBlock { Get-ComputerInfo } } else { Write-PScriboMessage -IsWarning "VMware Backup Proxies Hardware/Software Inventory: Unable to connect to $($BackupProxy.Host.Name)" } @@ -354,8 +362,10 @@ function Get-AbrVbrBackupProxy { Remove-CimSession $CimSession } } catch { - Write-PScriboMessage -IsWarning "VMware Backup Proxies Section: $($_.Exception.Message)" + Write-PScriboMessage -IsWarning "VMware Backup Proxies Section: $($_.Exception.Message)" } + } else { + Write-PScriboMessage -IsWarning "VMware Backup Proxies Section: Failed to Test-Connection on $($BackupProxies.Host.Name), disabling section" } } if ($vSphereVBProxyObj) { @@ -380,7 +390,13 @@ function Get-AbrVbrBackupProxy { foreach ($BackupProxy in $BackupProxies) { if (Test-Connection -ComputerName $BackupProxy.Host.Name -Quiet -Count 2) { try { - $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + # $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + $PssSession = try { New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction Stop -Name 'VMwareBackupProxyService' } catch { + if (-Not $_.Exception.MessageId) { + $ErrorMessage = $_.FullyQualifiedErrorId + } else { $ErrorMessage = $_.Exception.MessageId } + Write-PScriboMessage -IsWarning "Backup Proxy Service Section: New-PSSession: Unable to connect to $($BackupProxy.Host.Name): $ErrorMessage" + } if ($PssSession) { $Available = Invoke-Command -Session $PssSession -ScriptBlock { Get-Service "W32Time" | Select-Object DisplayName, Name, Status } Write-PScriboMessage "Collecting Backup Proxy Service information from $($BackupProxy.Name)." @@ -420,6 +436,8 @@ function Get-AbrVbrBackupProxy { } catch { Write-PScriboMessage -IsWarning "VMware Backup Proxies $($BackupProxy.Host.Name) Services Status Section: $($_.Exception.Message)" } + } else { + Write-PScriboMessage -IsWarning "VMware Backup Proxy Service Section: Failed to Test-Connection on $($BackupProxy.Host.Name), disabling section" } } } @@ -547,11 +565,19 @@ function Get-AbrVbrBackupProxy { if (Test-Connection -ComputerName $BackupProxy.Host.Name -Quiet -Count 2) { try { Write-PScriboMessage "Collecting Backup Proxy Inventory Summary from $($BackupProxy.Host.Name)." - $CimSession = New-CimSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication - $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + # $CimSession = New-CimSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication + # $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + $CimSession = try { New-CimSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'HardwareInventory' -ErrorAction Stop } catch { Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Hardware/Software Section: New-CimSession: Unable to connect to $($BackupProxy.Host.Name): $($_.Exception.MessageId)" } + + $PssSession = try { New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction Stop -Name 'HyperVHardwareInventory' } catch { + if (-Not $_.Exception.MessageId) { + $ErrorMessage = $_.FullyQualifiedErrorId + } else { $ErrorMessage = $_.Exception.MessageId } + Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Hardware/Software Section: New-PSSession: Unable to connect to $($BackupProxy.Host.Name): $ErrorMessage" + } if ($PssSession) { $HW = Invoke-Command -Session $PssSession -ScriptBlock { Get-ComputerInfo } - } else { Write-PScriboMessage -IsWarning "VMware Backup Proxies Inventory Section: Unable to connect to $($BackupProxy.Host.Name)" } + } else { Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Inventory Section: Unable to connect to $($BackupProxy.Host.Name)" } if ($HW) { $License = Get-CimInstance -Query 'Select * from SoftwareLicensingProduct' -CimSession $CimSession | Where-Object { $_.LicenseStatus -eq 1 } $HWCPU = Get-CimInstance -Class Win32_Processor -CimSession $CimSession @@ -784,6 +810,8 @@ function Get-AbrVbrBackupProxy { } catch { Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Hardware & Software Inventory Section: $($_.Exception.Message)" } + } else { + Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Section: Failed to Test-Connection on $($BackupProxies.Host.Name), disabling section" } } if ($HyperVBProxyObj) { @@ -808,7 +836,13 @@ function Get-AbrVbrBackupProxy { foreach ($BackupProxy in $BackupProxies) { if (Test-Connection -ComputerName $BackupProxy.Host.Name -Quiet -Count 2) { try { - $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + # $PssSession = New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction SilentlyContinue + $PssSession = try { New-PSSession $BackupProxy.Host.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction Stop -Name 'HyperVBackupProxyService' } catch { + if (-Not $_.Exception.MessageId) { + $ErrorMessage = $_.FullyQualifiedErrorId + } else { $ErrorMessage = $_.Exception.MessageId } + Write-PScriboMessage -IsWarning "Hyper-V Backup Proxy Service Section: New-PSSession: Unable to connect to $($BackupProxy.Host.Name): $ErrorMessage" + } if ($PssSession) { $Available = Invoke-Command -Session $PssSession -ScriptBlock { Get-Service "W32Time" | Select-Object DisplayName, Name, Status } Write-PScriboMessage "Collecting Backup Proxy Service information from $($BackupProxy.Name)." @@ -848,6 +882,8 @@ function Get-AbrVbrBackupProxy { } catch { Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Services Status - $($BackupProxy.Host.Name.Split(".")[0]) Section: $($_.Exception.Message)" } + } else { + Write-PScriboMessage -IsWarning "Hyper-V Backup Proxies Services Section: Failed to Test-Connection on $($BackupProxy.Host.Name), disabling section" } } } diff --git a/Src/Private/Get-AbrVbrBackupServerInfo.ps1 b/Src/Private/Get-AbrVbrBackupServerInfo.ps1 index d60a2a8..a19d4fd 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.8.7 + Version: 0.8.8 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -31,8 +31,16 @@ function Get-AbrVbrBackupServerInfo { $OutObj = @() try { foreach ($BackupServer in $BackupServers) { - $CimSession = New-CimSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication - $PssSession = New-PSSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication + # $CimSession = New-CimSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication + # $PssSession = New-PSSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication + $CimSession = try { New-CimSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'CIMBackupServer' -ErrorAction Stop } catch { Write-PScriboMessage -IsWarning "Backup Server Section: New-CimSession: Unable to connect to $($BackupServer.Name): $($_.Exception.MessageId)" } + + $PssSession = try { New-PSSession $BackupServer.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction Stop -Name 'PSSBackupServer' } catch { + if (-Not $_.Exception.MessageId) { + $ErrorMessage = $_.FullyQualifiedErrorId + } else { $ErrorMessage = $_.Exception.MessageId } + Write-PScriboMessage -IsWarning "Backup Server Section: New-PSSession: Unable to connect to $($BackupServer.Name): $ErrorMessage" + } $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)." diff --git a/Src/Private/Get-AbrVbrDiagramObjects.ps1 b/Src/Private/Get-AbrVbrDiagramObjects.ps1 index 95b9e49..a1055b4 100644 --- a/Src/Private/Get-AbrVbrDiagramObjects.ps1 +++ b/Src/Private/Get-AbrVbrDiagramObjects.ps1 @@ -92,8 +92,16 @@ function Get-VbrBackupServerInfo { ) process { try { - $CimSession = New-CimSession $BackupServers.Name -Credential $Credential -Authentication Negotiate - $PssSession = New-PSSession $BackupServers.Name -Credential $Credential -Authentication Negotiate + # $CimSession = New-CimSession $BackupServers.Name -Credential $Credential -Authentication Negotiate + # $PssSession = New-PSSession $BackupServers.Name -Credential $Credential -Authentication Negotiate + $CimSession = try { New-CimSession $BackupServers.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'CIMBackupServerDiagram' -ErrorAction Stop } catch { Write-PScriboMessage -IsWarning "Backup Server Section: New-CimSession: Unable to connect to $($BackupServers.Name): $($_.Exception.MessageId)" } + + $PssSession = try { New-PSSession $BackupServers.Name -Credential $Credential -Authentication $Options.PSDefaultAuthentication -ErrorAction Stop -Name 'PSSBackupServerDiagram' } catch { + if (-Not $_.Exception.MessageId) { + $ErrorMessage = $_.FullyQualifiedErrorId + } else { $ErrorMessage = $_.Exception.MessageId } + Write-PScriboMessage -IsWarning "Backup Server Section: New-PSSession: Unable to connect to $($BackupServers.Name): $ErrorMessage" + } Write-PScriboMessage "Collecting Backup Server information from $($BackupServers.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 } @@ -418,6 +426,7 @@ function Get-VbrRepositoryInfo { $RepositoriesInfo = @() foreach ($Repository in $Repositories) { + $IconType = Get-IconType $Role = Get-RoleType -String $Repository.Type $Rows = @{} diff --git a/Src/Private/Get-AbrVbrRepljobHyperV.ps1 b/Src/Private/Get-AbrVbrRepljobHyperV.ps1 index cbd1fab..9f3e4c8 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.8.7 + Version: 0.8.8 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -38,7 +38,7 @@ function Get-AbrVbrRepljobHyperV { $inObj = [ordered] @{ 'Name' = $VMcount.Name 'Creation Time' = $VMcount.CreationTime - 'VM Count' = (Get-VBRReplica | Where-Object { $_.JobName -eq $VMcount.Name }).VMcount + 'VM Count' = try { (Get-VBRReplica | Where-Object { $_.JobName -eq $VMcount.Name }).VMcount } catch { Out-Null } } $OutObj += [pscustomobject]$inobj } catch { diff --git a/Src/Private/Get-AbrVbrRepljobVMware.ps1 b/Src/Private/Get-AbrVbrRepljobVMware.ps1 index 7944aa7..57cf27a 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.8.7 + Version: 0.8.8 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -38,7 +38,7 @@ function Get-AbrVbrRepljobVMware { $inObj = [ordered] @{ 'Name' = $VMcount.Name 'Creation Time' = $VMcount.Info.CreationTimeUtc.ToLongDateString() - 'VM Count' = (Get-VBRReplica | Where-Object { $_.JobName -eq $VMcount.Name }).VMcount + 'VM Count' = try {(Get-VBRReplica | Where-Object { $_.JobName -eq $VMcount.Name }).VMcount} catch {Out-Null} } $OutObj += [pscustomobject]$inobj } catch { diff --git a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 index 4047cd3..885ec0d 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.8.7 + Version: 0.8.8 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -25,6 +25,8 @@ function Invoke-AsBuiltReport.Veeam.VBR { Write-PScriboMessage -Plugin "Module" -IsWarning "Do not forget to update your report configuration file after each new version release." Write-PScriboMessage -Plugin "Module" -IsWarning "Documentation: https://github.com/AsBuiltReport/AsBuiltReport.Veeam.VBR" Write-PScriboMessage -Plugin "Module" -IsWarning "Issues or bug reporting: https://github.com/AsBuiltReport/AsBuiltReport.Veeam.VBR/issues" + Write-PScriboMessage -Plugin "Module" -IsWarning "This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates." + # Check the current AsBuiltReport.Veeam.VBR module Try { From 97951e282be85776f33f4e0989a40ac46ffe4f13 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 21 Jun 2024 08:54:35 -0400 Subject: [PATCH 09/14] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index c855ffd..09a6d48 100644 --- a/README.md +++ b/README.md @@ -163,8 +163,6 @@ The **Options** schema allows certain options within the report to be toggled on | SignatureAuthorName | string | empty | Toggle to set signature author name. | | SignatureCompanyName | string | empty | Toggle to set signature company name. | -###### * Note: In order to generate the infrastructure diagram, the Veeam.Diagrammer module requires the following windows application [Graphviz](https://graphviz.org/download/#windows) >= v9.0 - ### InfoLevel The **InfoLevel** schema allows configuration of each section of the report at a granular level. The following sections can be set. From 05931e5f33f3efcbca873f98e91f13b68896a7df Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 19 Jul 2024 20:48:44 -0400 Subject: [PATCH 10/14] Added Tape and Service Provider Support --- Src/Private/Get-AbrVbrDiagram.ps1 | 92 ++++++++++++- Src/Private/Get-AbrVbrDiagramObjects.ps1 | 161 ++++++++++++++++++++++- icons/Tape encrypted.png | Bin 9991 -> 6992 bytes icons/Tape.png | Bin 2593 -> 6592 bytes icons/Veeam_Service_Provider_Server.png | Bin 0 -> 11295 bytes 5 files changed, 246 insertions(+), 7 deletions(-) create mode 100644 icons/Veeam_Service_Provider_Server.png diff --git a/Src/Private/Get-AbrVbrDiagram.ps1 b/Src/Private/Get-AbrVbrDiagram.ps1 index bc721a1..f013722 100644 --- a/Src/Private/Get-AbrVbrDiagram.ps1 +++ b/Src/Private/Get-AbrVbrDiagram.ps1 @@ -44,7 +44,7 @@ function Get-AbrVbrDiagram { Allow the creation of footer signature. AuthorName and CompanyName must be set to use this property. .NOTES - Version: 0.8.6 + Version: 0.8.8 Author(s): Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -215,6 +215,7 @@ function Get-AbrVbrDiagram { 'VBR_Tape_Server' = 'Tape_Server.png' 'VBR_Tape_Library' = 'Tape_Library.png' 'VBR_Tape_Drive' = 'Tape_Drive.png' + 'VBR_Tape_Vaults' = 'Tape encrypted.png' "VBR_Server_DB_PG" = "PostGre_SQL_DB.png" "VBR_LOGO_Footer" = "verified_recoverability.png" "VBR_AGENT_Container" = "Folder.png" @@ -227,6 +228,9 @@ function Get-AbrVbrDiagram { "VBR_AGENT_Server" = "Server_with_Veeam_Agent.png" "VBR_vSphere" = "VMware_vSphere.png" "VBR_HyperV" = "Microsoft_SCVMM.png" + "VBR_Tape" = "Tape.png" + "VBR_Service_Providers" = "Veeam_Service_Provider_Console.png" + "VBR_Service_Providers_Server" = "Veeam_Service_Provider_Server.png" } if (($Format -ne "base64") -and !(Test-Path $OutputFolderPath)) { @@ -443,11 +447,57 @@ function Get-AbrVbrDiagram { } } + # # Tapes Graphviz Cluster + $TapeServerInfo = Get-VbrTapeServersInfo + $TapeLibraryInfo = Get-VbrTapeLibraryInfo + $TapeVaultInfo = Get-VbrTapeVaultInfo + if ($TapeServerInfo) { + SubGraph TapeInfra -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Tape Infrastructure" -IconType "VBR_Tape" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { + SubGraph TapeServers -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Tape Servers" -IconType "VBR_Tape_Server" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { + + Node TapeServer @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject $TapeServerInfo.Name -Align "Center" -iconType "VBR_Tape_Server" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $TapeServerInfo.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } + } + + if ($TapeLibraryInfo) { + SubGraph TapeLibraries -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Tape Library" -IconType "VBR_Tape_Library" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { + + Node TapeLibrary @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject $TapeLibraryInfo.Name -Align "Center" -iconType "VBR_Tape_Library" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $TapeLibraryInfo.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } + } + } + + if ($TapeVaultInfo) { + SubGraph TapeVaults -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Tape Vaults" -IconType "VBR_Tape_Vaults" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { + + Node TapeVault @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject $TapeVaultInfo.Name -Align "Center" -iconType "VBR_Tape_Vaults" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $TapeVaultInfo.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } + } + } + } + } + + $ServiceProviderInfo = Get-VbrServiceProviderInfo + if ($ServiceProviderInfo) { + SubGraph ServiceProviders -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Service Providers" -IconType "VBR_Service_Providers" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { + + Node ServiceProvider @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject $ServiceProviderInfo.Name -Align "Center" -iconType "VBR_Service_Providers_Server" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $ServiceProviderInfo.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } + } + } + # Veeam VBR elements point of connection (Dummy Nodes!) $Node = @('VBRServerPointSpace', 'VBRProxyPoint', 'VBRProxyPointSpace', 'VBRRepoPoint') if ($WanAccels) { $Node += 'VBRWanAccelPoint', 'VBRRepoPointSpace' + } else { + $Node += 'VBRRepoPointSpace' + + } + + if ($TapeServerInfo) { + $Node += 'VBRTapePoint' + } + + if ($ServiceProviderInfo) { + $Node += 'VBRServiceProviderPoint' } Node $Node -NodeScript { $_ } @{Label = { $_ } ; fontcolor = $NodeDebug.color; fillColor = $NodeDebug.style; shape = $NodeDebug.shape } @@ -479,15 +529,19 @@ function Get-AbrVbrDiagram { Edge -From VBRServerPointSpace -To VBRProxyPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VBRProxyPoint -To VBRProxyPointSpace @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VBRProxyPointSpace -To VBRRepoPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + Edge -From VBRRepoPoint -To VBRRepoPointSpace @{minlen = 16; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } # If WanAccels add the VBRWanAccelPoint Dummy Node to the line if ($WanAccels) { - Edge -From VBRRepoPoint -To VBRRepoPointSpace @{minlen = 16; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VBRRepoPointSpace -To VBRWanAccelPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - Edge -From VBRWanAccelPoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - } else { - Edge -From VBRRepoPoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + } + + if ($TapeServerInfo -and $WanAccels) { + Edge -From VBRWanAccelPoint -To VBRTapePoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + + } elseif ($TapeServerInfo -and (-Not $WanAccels)) { + Edge -From VBRRepoPointSpace -To VBRTapePoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } } # Connect Veeam Backup server to the Dummy line @@ -519,6 +573,34 @@ function Get-AbrVbrDiagram { if ($SOBR) { Edge -From VBRRepoPointSpace -To SOBRRepo @{minlen = 2; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } } + + # Connect Veeam Tape Infra to VBRTapePoint Dummy line + if ($TapeServerInfo) { + Edge -From VBRTapePoint -To TapeServer @{minlen = 2; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } + } + + if ($TapeServerInfo -and (-Not $WanAccels)) { + Edge -From VBRTapePoint -To VBREndPointSpace @{minlen = 30; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + } + + if ($WanAccels -and (-Not $TapeServerInfo)) { + Edge -From VBRWanAccelPoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + } + + if ((-Not $TapeServerInfo) -and (-Not $WanAccels)) { + Edge -From VBRRepoPoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + } + + if ($TapeServerInfo -and $WanAccels -and ($TapeLibraryInfo -or $TapeVaultInfo)) { + Edge -From VBRTapePoint -To VBREndPointSpace @{minlen = 30; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + } elseif ($TapeServerInfo -and $WanAccels -and (-Not ($TapeLibraryInfo -or $TapeVaultInfo))) { + Edge -From VBRTapePoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + } + + # Connect Veeam Tape Infra to VBRTapePoint Dummy line + if ($ServiceProviderInfo) { + Edge -From VBRServiceProviderPoint -To ServiceProviders @{minlen = 2; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } + } } } } diff --git a/Src/Private/Get-AbrVbrDiagramObjects.ps1 b/Src/Private/Get-AbrVbrDiagramObjects.ps1 index a1055b4..d99ae38 100644 --- a/Src/Private/Get-AbrVbrDiagramObjects.ps1 +++ b/Src/Private/Get-AbrVbrDiagramObjects.ps1 @@ -520,7 +520,7 @@ function Get-VbrArchObjectRepoInfo { param ( ) - $ArchObjStorages = Get-VBRArchiveObjectStorageRepository + $ArchObjStorages = Get-VBRArchiveObjectStorageRepository | Sort-Object -Property Name if ($ArchObjStorages) { $ArchObjRepositoriesInfo = @() @@ -567,7 +567,7 @@ function Get-VbrSOBRInfo { ) try { Write-PScriboMessage "Collecting Scale-Out Backup Repository information from $VeeamBackupServer." - $SOBR = Get-VBRBackupRepository -ScaleOut + $SOBR = Get-VBRBackupRepository -ScaleOut | Sort-Object -Property Name if ($SOBR) { if ($Options.DiagramObjDebug) { @@ -605,6 +605,163 @@ function Get-VbrSOBRInfo { } +# Tape Servers Graphviz Cluster +function Get-VbrTapeServersInfo { + param ( + ) + try { + Write-PScriboMessage "Collecting Tape Servers information from $VeeamBackupServer." + $TapeServers = Get-VBRTapeServer | Sort-Object -Property Name + + if ($TapeServers) { + + $TapeServernfo = @() + + $TapeServers | ForEach-Object { + $inobj = [ordered] @{ + 'Is Available' = switch ($_.IsAvailable) { + "" { "--" } + $Null { "--" } + "True" { "Yes"; break } + "False" { "No"; break } + default { $_.IsAvailable } + } + } + + $TempTapeServernfo = [PSCustomObject]@{ + Name = $_.Name.split('.')[0] + AditionalInfo = $inobj + } + + $TapeServernfo += $TempTapeServernfo + } + } + + return $TapeServernfo + + } catch { + $_ + } + +} + +# Tape Library Graphviz Cluster +function Get-VbrTapeLibraryInfo { + param ( + ) + try { + Write-PScriboMessage "Collecting Tape Library information from $VeeamBackupServer." + $TapeLibraries = Get-VBRTapeLibrary | Sort-Object -Property Name + + if ($TapeLibraries) { + + $TapeLibrariesInfo = @() + + $TapeLibraries | ForEach-Object { + $inobj = [ordered] @{ + 'State' = $_.State + 'Type' = $_.Type + 'Model' = $_.Model + } + + $TempTapeLibrariesInfo = [PSCustomObject]@{ + Name = $_.Name + AditionalInfo = $inobj + } + + $TapeLibrariesInfo += $TempTapeLibrariesInfo + } + } + + return $TapeLibrariesInfo + + } catch { + $_ + } + +} + +# Tape Library Graphviz Cluster +function Get-VbrTapeVaultInfo { + param ( + ) + try { + Write-PScriboMessage "Collecting Tape Vault information from $VeeamBackupServer." + $TapeVaults = Get-VBRTapeVault | Sort-Object -Property Name + + if ($TapeVaults) { + + $TapeVaultsInfo = @() + + $TapeVaults | ForEach-Object { + $inobj = [ordered] @{ + 'Protect' = Switch ($_.Protect) { + 'True' { 'Yes' } + 'False' { 'No' } + default { 'Unknown' } + } + } + + $TempTapeVaultsInfo = [PSCustomObject]@{ + Name = $_.Name + AditionalInfo = $inobj + } + + $TapeVaultsInfo += $TempTapeVaultsInfo + } + } + + return $TapeVaultsInfo + + } catch { + $_ + } +} + +# Tape Library Graphviz Cluster +function Get-VbrServiceProviderInfo { + param ( + ) + try { + Write-PScriboMessage "Collecting Service Provider information from $VeeamBackupServer." + $ServiceProviders = Get-VBRCloudProvider | Sort-Object -Property 'DNSName' + + if ($ServiceProviders) { + + $ServiceProvidersInfo = @() + + $ServiceProviders | ForEach-Object { + $inobj = [ordered] @{ + 'Cloud Connect Type' = & { + if ($_.ResourcesEnabled -and $_.ReplicationResourcesEnabled) { + 'BaaS & DRaaS' + } elseif ($_.ResourcesEnabled) { + 'BaaS' + } elseif ($_.ReplicationResourcesEnabled) { + 'DRaas' + } elseif ($_.vCDReplicationResources) { + 'vCD' + } else { 'Unknown' } + } + 'Managed By Provider' = ConvertTo-TextYN $_.IsManagedByProvider + } + + $TempServiceProvidersInfo = [PSCustomObject]@{ + Name = $_.DNSName + AditionalInfo = $inobj + } + + $ServiceProvidersInfo += $TempServiceProvidersInfo + } + } + + return $ServiceProvidersInfo + + } catch { + $_ + } +} + function Get-VBRDebugObject { [CmdletBinding()] diff --git a/icons/Tape encrypted.png b/icons/Tape encrypted.png index a294b6620c7f0475b48269c970cd5038e072ee4b..905684ff21ca7b882ffa00e003545e11c201f575 100644 GIT binary patch literal 6992 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 literal 9991 zcmeHtWmJ^iySIRVsDz-Pq@seLfC>yHASF4p5)y*s&@~{fh=2&v9a2LHNDN&93eqhz zq@={qU32!W&+|X;TJQV)Js%Eh&9LUauf6wm{jT172dOH{lAotPf9A{?a(Ovv^)qJ( z7QjdJ93gm8-!7^E{t-B-%SxUp>}Fg9KhBy1KdSHvDi!roMFzzIq{uhpj$t-`Mk^n2qPdBgY`Jps#czE#f-- zcVFj3ex8!N`10IDBb&%d-Tm-SEjl4etoJY*?;cRg+8bRlHdDGDwvq6FK##=a-6fJI z=2Y**-5YH2f+=~cO9Kl@!b3w(Cso8K8TKyfkL&N?mcXCS(PDP$=>wPoN7m5JX0(vB z&aLAlEdI3STa>!4{-rVb^lxW064iBI#bd#P+y67ZaqepgrWZVh)fG5AEoKm0te-mu zZGYnF$KsEd-%@S%Tv$K{e&N=r(T~Tz4Wn1Gskx6PyOHdlYeR>E-N-DxkH$3(vb}Yt zMV0Hv0gCRX!SV|liB$bMaag270#@*qU}aRlYBZ`4ya*l`{O4(SDx3cF`iyUFD&i6!u&G+08jd6_-pFZQ!D(voo7k+ zk{%`rCW#4!e|x;sXqcAwsp%8e0&hJOovdku81>H`kNIt2Bff7`ii45zEvEI|{GA!_ zGlhtXoj99>JqL5ai6ZAwj%1D;wwyC>CHlO^D7O;sSqtvIE_Sx_Hm11S_kG~1_WIu7 zX|RSbP2Zy4V;9M+yu(lND8UwWSLCnVuhCDKMKc~gd~BL;j8t5F3XIwaA+Y-cm)PF5>~2rf^&m3T zeXl(m`lY(TjHxxao7SUH^_OnpmCv3N^YFV4t$73NQ1+E*-C~ayq!dMr7Is(ZMc?G* zTp3cyYWeF2rTSlt<=5&ZI9#_r&G|fp9nOEH6u7whrs(2|TV*!GDe@>a5>F^jFY4%d z9Ca+Q#mFH3ZE=EDf26cLnVnWJS}+YA8BCL$vPdq5+7XFfBqCQRd zA?f%$e6O&u75yEP&@fR+pIm~PuA$bypK7y&IuCStE?Zv2p&$t1*Y3x83-3;#D&)n? z6|SE52mNPyB`z<&iqYxvxDW3Y=%CP2chg1QJztsjDi)Oup!=+yj=NxU=deI3Lw5E$ zY&x=7E$K2&2}8|<+^!G)DQd@}rf})60`SIrjT9UfH+vgbbq>mg*M)BwPjCBkU=ZA` z-&Gt8UT93)Utw%JMNF^Qm7l7K@F!D6=i%2UP4h$6w}Q$pEB}#dw{;4>^+zYbh>^ZvxcjVVI7i`HsQGnFFm^L`ru3_SVOj&7&><;FFDe66@p6FjZBo@rvo?@Kje_XO;ShJ1AFQh(+{=9!MDp`j#8mxV$)> z8d?8Q>?r#^lM%wMB@TPw+HS{utZK!c60B_8?L}mplwYE!7tjg#O3Rn#sWH%07z1nBKZcx6;(`kg{G#Z7qSP zzfVtZr!Y~QCXb1F42e^z&S2x#e_Y&(80WC6k2n(cE?ahZ**ZsMqL!9+zsuv9STgU! zcM1l>f?=s< zL*Nl7Yfgw)&=7~2q^)_As^;XZxYBYZnSdrfpVFO=CE^_I?kP7CwIH3Q4^F&HSv|zo zOB9G|4jv8P>!^Atvx8$;`MiQW&&aA`plvsq#2%TYG!kp`X8}b-#^eouxd%c{9C5IV z4#W{mim&Ulk=lf??2I}i`&eXe-rYRgZWpYV>vPy=NG11jlX=ti$7R*y=lNb9@5w!> zaC%ba5Ki&JI&&gvnJ=#nX(C);tqs9*M_nWjcG1b8#eVXG;)9f6K51fD*9S+R)Bt7XDCL!urN z+i2&Xd>sK!xMK2tN<7h*DM}yyYhKED^;=dOpVz2_@$lW}Pa!al2MtC_pTSaD2VqGT zx}!8Z&qbtPTOt|>48g?r9>*H~2!liMh}s*`;I#h|Q>!pybCsLdRfy=+j1UP&K9m`u zv$R;Utx3w`NrckZ?e#%}FUCQZfxNZZ>Is!rFq{X7KDfuk8M&*(2O~O8%~RZ%=g}Y; zB-KrE|2w4n8Z((?Xu14=$SMJ4M4YbO(4-;HG|_lZ#{|kACdWFe@po!i^lV1oP2CVm z^#NVq-+r;^YE{{;D)i>kOltB#S?23f6#IWjlRKsYWT~A<DWH0PY9nztfnDbEnapQ&(Ocr@=ezF1RX6ii3J?9Rwe8HNU2wX0N zfg>VunDTx00x>+f=z0UOweIzM5zp_&Il0c6;qGJNAO+mWE?+F=-`KAGl)J?bb9g4A zM__TtXz{4xS+BFJ|NJMWLghOQe}tJGgw?g3wl`7~q?4|IIM896eQxFTEu<_`iP%d8 z7x%Wn@&SiHQF+IAO^|NMgwXK4j;{?iX_mT?x4z7k!-UK7E#l=}G{gq~P zJN{?RYV0rBcXs`;`|uIv!0~VK~02#nJe0T!>Akbi{9C~SN8^o@_K^1yag zWMfSDLoRx><(e<@ano)}v`R-xzF^>gGaFNY>P5U-Pe6qWiZLY*Yc5M3I>IGPdo(O$ zKhw0wKs*LF2;+)p z8F95ynk)*skLEFqk4)BbSeLkniGWc2iYmAK)_qQ6w9F*GgZL4Xg>HlZGz7Es!r$O8 zi4tzz6k$br%Pk&j)a-y;pQ|iKK7OOM`^X>JBAjOZC*uDGz9l0^eNzSJMtdWd!y`pf z#5h^CJQH%!wp<%`wv4A6Q{!c>k9YOvvh=;Mm-5R-m@p5bN6b#gi;Z(vs?I0){h93_ zbQxS^V4ta*wXB!;z53W9Dy)t7-^1%rJlOveC|Gh^fJZg@J##tgBbs#A=%H0>V&OZWKBNar64_^!1C){jh0vzQ?WuYq_p^?s!XP^FJ7iE0{$;X zM)`UVp!k(e`gzeC({(5NC0ym<>XN&j$UOopdMc-_t5Ps1)dDF`+U9pkjG}X5R{7w= z%wj?)rouBV%0E_frO~h=%MuunuoB?)ul+c8T%2C?++jJbSt)&=cx2j|@V#Zas;0VU z-SL_|?{&6+ZTDRccZp53o3J4&Me7BP95sAE4v;+@*A;5(lE$P!N_-7mfonld*icB6 zhm=R4=4aUlg236;c4wm9=X(By7i`B6(a;7n*P%CncST4)?6=-m1~3$;+(ZChaC z0VS=oDOjQ8qHl?YL!4f2-lqFzuU;%a8M3Obp%*%cM%p)RRgB{Ac_cPr3jT5HMh%99 zdgdyRS&f2zQq&7nUH|l&|qSTLiPim2Ygag~JRb#jOO(LP`-=<RI>%KqMg1Ahui8Booh_GgnK!YUFJuVi3+%Oh9Dd0k1xc6 zNYfiP<*fOisQ)4FS|aTMQRt|>&J&kp7}qB0m|>=A^PiL-ffec!{32vzfc{0@Ri#V{ zTO7y_F8iB)wAC5r`DR`i*f+fVrar)ELnSXO@?b%jssF+%N^3-dgU%9D4k`0e7E+n_ zNx%Qb_tHh0@auV@NaJo7;SXB3*FZ^WnQ-&Y94pu8v%l%}olw_46s03`k}5Z1lYg-O zr9NERImq+rKezWZH7+CXGvL7BZ+&p2wd}(q^CP`~pn~PM_e2>9@dzlDL@tL1GQ~=T z5e6*R^LLarYu|v|sonmRXBE&CQu68wXtbvlY%FxMS&cBy>vTtR-nzPortl`=_C+rg z)ixXnt<*CHUKX_YU5p?trAF>Fa36)q1o5cLll>E_!VQJI)XUZl?eq%JRQRs=!VA@; zNDI;%ocOXmJICuKIn&aOz>%G}Wq>`buDC0Soa>JIw;GZfi2XsWx|r`WQwt*IWzk@Z z)+Y#V?c!Sv@-t@;0fXjhLQW}`L2Fgkh<;qSsQU^ zFW)qG*GaIvOU zB;(n(8$iZ19fv=#KWvJ!TkfBtxb73day3!#`7}+Nd)8xUlyou{8ntg?J($XUwHklm z#Z7g59*c_;e@J5Q=2LUhgEit&)T}*D>+%Y1J02uP{dzjTqpOdQK;(D1r6SD6)RazS-ogoSOk=dng(eBaJHSt?na^@ z-6wkyEQDTBG`u#VHv68C)h7|914nBT)#=A>5whsvjk}jvcRp3S3(Cr!&j#wepm9XE zw&MPIzsl8~RDYI4h@hDH*R(3`Xm%Gav--lrLc^L>bc#P!OxuFs^=Lp@?z{&U|u7#{FUlvqWn3lwOgq5rU37nuK2k=|{!>sXcAl@@bz_)^ARD*6#S- zRCmWCwy}BEPtO^$E;6H#H0ckEC*h2~h-ZDdNhL&_W)Y-AGrxNYAjhW zwaiSfhf`RnBZxS!-vsA5F*;5R{xG zd8C~3a`O5`D__ndSv2>UUp{ z_XEx7*OyVStigo-!3(}AJFc=M3Ky5l0@p4`iHdukR9)`ViUV7-Rtg#dey1yABd@pC z>OS8_X{Ee+xtJy8RY?{m=|KXm|CRV|%rVrRCRI!7k6M;WIhAnqcGY-9kF z^dt4bE=Kpmxr)Lr1Aq&9v)W+nnx3eW67o9{^nSRmbQ#*u$nwtyGKbVMPafvP_&s%Y z+~ZU!Nz8?F*z^U!3cKU|Pfj-Wn%kD$`_}3o@N#%)Q!CjhSl+EK%kSBanK>RLyIb^q ze-Q}Ids9R)iLDI?4m0o0X)CZQjiuPJd_b2uS$m?SL&OFRqd5f)BRqo@2>Z%~MW}q< zKaE*0#{{qc6%3=@3GZ5l8*&C_1}D=d+qRYxfgS38NwK46cJq&SyQ&s_Ws8H|s$Ki` zS|?+h`(8m(dSQ&185{HNJXmbUIa=e6{zVj{;c!qAp^ zf{mFJkbZG!Gj9T0wGatS_O7RX=q|22^dOg}xU0>!RWYE1Xw>RRW^+b<2;vs<}aUr&mPdj3}(rl1{*lp3#OBC@%KbaF14QfdY7Go zPKRjraC;wEhv!wF);Z~R6Ea{l+jMLCrT0#DX8;nVUMdzwvr2Dww!hkN`NYuqr=A$+ zj1?`6FwK}DG!(u8^SGGG7&-6G;B4Kq!}HU)E#&ujMuWALOC4bMwwZwKrA$VfW&ry8 z#R|)?xU5^_K!ZSEF4Iq&fhR>fUTR{-B(!z`iqn;d0*0)#VFw31EteOgAliJqtICo? zf`F>!OYX-jogqy2;z}R6bPwL#hmaCY5AbgMYBD zzYR3{1XpJjlVxsR5g*YdT))%Tsb;zD&%?A-Iy5I+fps>rXB->JK$27fBYR?Vcp)q_ zp!AYaJj)B|LYMRg{CGG4<}uT62bEQWtdo+Aa^6OO1)ssd)|1`^mq$s-2P6uz;^n>~ zLC(hMhHLx3X1|?0HyMRD0U~t}%OXx~i)JvG0n&;e@0K6CY9GbBuutF=R7hmkCN`WK zhYj{k5E}Hki%4Msc0vXe=F@N zXu!pDQp~+An#hzY5g&dE!j7d8#bgDGbr|{2U;AA@IvsXBf!yCM4(E0j{YJ|kFXm`? z4F7m%=k(I71k>@oGmx5}>rvz2DY36r&~9Sr`+Q9eo;QTqxhEfs)s79L`W;VF)9`f; z%P77MpI>5m{Y*GBk&gJ%6o=McYx`{TFM_AH%nk`-J`R8bmwov~${UHvwsAt0;l7uL zy_43ePUkjbD;zw@{T8jXDU@s^ja$9sEMF3GUCdo5(jH&Y4BJlJ7IUot=Qu5)Gj9{z zDimR!iSgmdSUdWJ17qb7Gt%ewUA^;;f+!4r6`qu+)rN%8bL_sx3)$7dFmvXr{sXi}dX zuYn82quonhSj{E|-bgGZqxNj@BPMyAzo^xvu_*PTN1%qZ+$Ad@zf+ML^Wi63{h)X6 z=ifSpr`Dt`S90bqJT`WRrOlYiUq?!p+n{cOh`Q4S{L-T6i-v_R zYyw`$b#E+3bi+yfOG**tH>*krkpA^LP>jg?741%ZXrbgca2__v8Tf6N3pVqLz-aA0baa9ZO*J`{D)k)<a8lXs z+Y%Bq4Vv4;N>SFOZJWA;%QLt?M#w4x1Pk&puzeLVoT9qA9H>iI5``91LKu#4%!S|+ zgrr6R15&%Es|yh*gNzmlo48fU6r6|T5nLyIhR5`fPAl;^BHji54;{!gk$|r2b_|wJ z^k8lJlnZO8aA_QY`_|U~Q|^J6X$at`4e^oH;b)PIp9dP_G8bChloUcaj_ZFdGjB3NeTssNOat{H^IyQZG_E?JH9`hkt>ItJ! zVv#NFq=5xTU86m6mY^kydbcv$nU$H#?pE?JZ+DC`>L|kGuqu_kM~*i(+!*Nlvnx_G zrfiEI=lQ849h4V3=bag5&2$D<`fp-SJ6V6G5Zr>G83yTE8T*Rd=b4p)YlUJJ~w!H@f1o1@_a$X z4h>7D=?y5_j8(&y9lznW-&$P$GrPnm?_`qu}wK^Mq*sW z6N>6eDuJS;w&8Cr+TnFX-$&`~&jT~J?wDuG#te*mP7RI786V1XynyDw^XGhc?;eM} zzg5EpY82$}AqMAl^M-J^&KfD0+<7uqH8FkB>R9?JN%Cccf)p=QwTrVfvYHIzJgzxb_ zZ^N#x8)f0mWcCq6Y+Tu}O>FZu%z?pJgN%Y9DTsA}y^?9vh>Y7@+2y-_3Kn_+Z>gxs zbnj?NqRK&87#6sWkf?d{Jqe4gX9uU`L4o}ZA`@>OWbdMbc(S%#{yai-eUkeigyuC| zGyyU3(j<$IVFxij1cn}9DOGs^J&JY{RWFqTu5P3*bwq=Q8@f>grlqB?WLwK7V&fyx z1YoJkb8b{7+tOMz2 zfXZ~bBjv5&%w0@9yFI1a+P1`;V(a50nx1dma#b1-dl$B+^3Z|m;e*PF%Az>Zltib! z#zD4Q!eJJ=Pxh^oa&71bNg#AHbfrcwp^)95U=YhpL-g3t`{)7xq5!b2^CuRqG#&7I zx3f)|!LMWWl*2XfSpnp8ht{&^8h;}-w9X&I)Lh3xL&=ZCc0 z5ls_-9$fErQ$NzfJ91cY|1k&oG}8b(T6x_4XCIqnG}{xvb%U^+jfNWiTj&AS$~j8g zjFU!z3&=7E+?<1r@5k{1F$l8h=!;bzpMp+6+s#w*{H2y zl0wj}SrCES5VP5!WGb2q6emfAGTohtJ_xL~9ygKrTl<6Df-ae04AmwtaGf%~jTY8i zFQc4=rTCXS#;&sv13~Pdgn0)3cneUw#Lt{14-ApRX5D>}8ZV3M-N$1TWhU|XVyl{h>^JRs-t3{Jl**2*z^6=&z2fqj6Slb z_A=*C;08)F}%@SmtFq~pzi!^)}lpyq|cSS!olRoNbNaF(%oDSY)G z7MR*rq1M|!BjBIbyME4v5O6w8pZN>4Wsf``kR~sK6tSB9LIA`PDs_4QKlke7bo1r4 zALIFE4Ocl$PhG&}B(fWGPBzmWAa8-hjhTyJ`@J%g@IV0B*b`1g0|{n0NL@?gwGMV0 z^5O<}paBL>ApN~vnd?C+;dFiu-n;x3vJ22j{G#{uX-UoXuz}#!j0TPBrB;6423s1? oNJ^f|1%3Jd^P58aWE+ooWzx%-wL}Ikubq*XQI;;0eDUVL0Qhn(bpQYW diff --git a/icons/Tape.png b/icons/Tape.png index aadd776320003977ed8e97ba29cd8e86408610d6..586714b6a7eccf210db0ff837774254b9b3212db 100644 GIT binary patch literal 6592 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 literal 2593 zcmaJ@cUV)&7QaXp1kKW1x&;9#q5?~iMS%!Gh!G_rkU$m%q$7kTp=?;`MS=uS2}L@D zE?|U&vWrp#DIru*dPi{S?OomX-}~NvcjlbA=bLlR%$)gtzllP?jre)RcmV+5hZ!51 zgL)9`1RgF>@==3@0e~&s$-n>sGcb_x^zv|Uayn(39KNx#kynMT8!` zN2Du7Mn@(gvv`E{sUM5N+HM_X!VE|g6Y_N;68q>9?K;iHh0hmxh>#*RRo%)Ak(AZr$ zCN|bFVCw)qX43T_^tKGep7tBW*BM-mSD=y zmwO8XCU`0k5AVN;L-!z}{U*{3a5hd*sROP0|O zjlF0h-=ZJu8z&^Fpq&u7%`M3=R!PIis(LA99up=_avz0_SE+v!oOCzW6u{F5H{YqA z8s!vIA36NBX1VqFDSxigYBIx|J5LW*_PTlw^0A5^gQ-;uI9WH!#zn!mJ(W z7B;!@CG>f5y}r3(i%FDlPUCEXbfKOW(RC^Y_k^f7QGB;RIkQ7Dy=W7u+qWfI=Fz(x zgQ})cEJC~t{Z``?($QC}l-AV|stM;4uF(bpYLqxVa)+&R>9~}~I@-c!`!^0kb~-gH z-m?%*ywrt!T~zIIk?F65%&7j+zRQjJdHzmsxNNCnK|anN?so#cV?O!MPm_ed++^u2 zY-aS{4&M45g1Wk{ZdpD%b*Fse53ZI(5_O@uy^@QR;q=h?Z}GitzBGH~2W0ic=Ydv( zXO0xGE1J~s=T_D%hYQ-7d~4z+ou;S~%+y;xell3SopeGY?QOeDPvl|ZA&VjuT&tJq zuW7ee`x=8>6&UaT*l&qGM822)D2GkK&joIp_@0sKOE2t+e%4V<2pQbYcC)uV=Z6|9 z{Ti_nH~&{gLc27v9B~nF#4A!jRJk8suHB<^Vy|^B#SqZ^9i~rtjg&fF~w9PbKCL` z-(pRPgk`5MqN&CohG zabxXOd&Hs^wgv-vIjVc!HjGneN%!H~D)p&GR8q+-zMkGDJa&3r9a9eP5ZrHzI4Pl} z<>8}S4347X-6)v3d+%AEO(j&9FK(`KSKPH~J+Ahp5EOO5{Jx`5VO+15yWEQeZF*xH zIBmhDBqm?e?qct z{d#%X-k9PhGYWH+f=2uPW`jF9F4%I6K%&z2pn8n8-i~-e+qb8zV&4wu*OLOlibMj$w72yZr7Gqd z^qszdwcMq$I4uh(b#bCz(f7pn_(?g3Q^q~rx&klwo}oTz=(RoWf`=3MMU^glGah2Y zZ`xAz1<)y3A8GFNy&7`IFwF+OdVy5dM5LBF3RhKIN@p}oMOHMQDMMwvY`BM4B1=57 z*m?p6FeR&aEaWSw046>iNGqTXRkJ z$L9a+tX6q8Xmn93UY`D!Z+`c1(XXo;;NKukxwlm%Ho2Oqup_3DdVVZTOc{M#|1gxk zFJFqV&Q#(&G7LB=X>Yu&%-Od-*=HapWpR{h1m{U^raT zxS{vCmG^0v(tNUu?gF2$LT?Y+t9EyDhU`d*t{`_@1P}UvYPX&nvz;D!A>7B$*>vo% zku3b>tq4I$D?3<}k!?WdLDmdtJU@*D@waJ!#T@B*qDh zuye4AN^^p$*S~t9fshh&*2vlGiD0N|a}Pi{uB!qZ?0{e^PRIGT_I(^ARPj6if#mmt z|Nfs&HACkWTe9v0p;wMOVCx{j+}UG492&_>{@=KP&%FP}b3gbE6kywHK4P;VGtI;z Sb7jGI0sw=;4NLWL#Qy*-yViFA diff --git a/icons/Veeam_Service_Provider_Server.png b/icons/Veeam_Service_Provider_Server.png new file mode 100644 index 0000000000000000000000000000000000000000..71a473b5d7cc2e0d85bcb42dbccaa4c6b774f2a1 GIT binary patch literal 11295 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 Date: Sat, 20 Jul 2024 07:06:16 -0400 Subject: [PATCH 11/14] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29499f7..0b9a7b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added Tape Infrastructure to the diagram + - Tape Server + - Tape Library + - Tape Vault +- Added Service Provider to the diagram + ## [0.8.7] - 2024-05-28 ### Added From c1c4bdbbd07c8fca477ca108281c3c156778710d Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Sat, 20 Jul 2024 07:13:02 -0400 Subject: [PATCH 12/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09a6d48..8b37c1e 100644 --- a/README.md +++ b/README.md @@ -275,4 +275,4 @@ PS C:\> New-AsBuiltReport -Report Veeam.VBR -Target veeam-vbr.pharmax.local -Use - 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. -- This project uses the PScribo module to generate the report. It has been identified that the EvotecIT module `PSWriteWord` uses the same cmdlet names. In order for this report to be generated correctly it is necessary to uninstall the `PSWriteWord` module. +- This project uses the `PScribo` module to generate the report. It has been identified that the `PSWriteWord` module of `EvotecIT` uses the same cmdlet names. For this report to be generated correctly it is required to uninstall the `PSWriteWord` module. From 63aabb277e1f409232a967bdc4d032308a482dde Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 26 Jul 2024 16:36:52 -0400 Subject: [PATCH 13/14] Improved Infrastructure Diagram --- Src/Private/Get-AbrVbrDiagram.ps1 | 89 +++++++++++-------- Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 | 2 +- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/Src/Private/Get-AbrVbrDiagram.ps1 b/Src/Private/Get-AbrVbrDiagram.ps1 index f013722..3f393a7 100644 --- a/Src/Private/Get-AbrVbrDiagram.ps1 +++ b/Src/Private/Get-AbrVbrDiagram.ps1 @@ -392,16 +392,6 @@ function Get-AbrVbrDiagram { } } - # WanAccels Graphviz Cluster - $WanAccels = Get-VbrWanAccelInfo - if ($WanAccels) { - SubGraph WanAccels -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Wan Accelerators" -IconType "VBR_Wan_Accel" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded' } { - - Node WanAccelServer @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject ($WanAccels | ForEach-Object { $_.Name.split('.')[0] }) -Align "Center" -iconType "VBR_Wan_Accel" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $WanAccels.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } - - } - } - # SOBR Graphviz Cluster $SOBR = Get-VbrSOBRInfo if ($SOBR) { @@ -447,6 +437,16 @@ function Get-AbrVbrDiagram { } } + # WanAccels Graphviz Cluster + $WanAccels = Get-VbrWanAccelInfo + if ($WanAccels) { + SubGraph WanAccels -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Wan Accelerators" -IconType "VBR_Wan_Accel" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded' } { + + Node WanAccelServer @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject ($WanAccels | ForEach-Object { $_.Name.split('.')[0] }) -Align "Center" -iconType "VBR_Wan_Accel" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $WanAccels.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } + + } + } + # # Tapes Graphviz Cluster $TapeServerInfo = Get-VbrTapeServersInfo $TapeLibraryInfo = Get-VbrTapeLibraryInfo @@ -476,7 +476,7 @@ function Get-AbrVbrDiagram { $ServiceProviderInfo = Get-VbrServiceProviderInfo if ($ServiceProviderInfo) { - SubGraph ServiceProviders -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Service Providers" -IconType "VBR_Service_Providers" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { + SubGraph ServiceProviders -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label "Service Providers" -IconType "VBR_Service_Providers" -SubgraphLabel -IconDebug $IconDebug); fontsize = 18; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded' } { Node ServiceProvider @{Label = (Get-DiaHTMLNodeTable -ImagesObj $Images -inputObject $ServiceProviderInfo.Name -Align "Center" -iconType "VBR_Service_Providers_Server" -columnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $ServiceProviderInfo.AditionalInfo); shape = 'plain'; fillColor = 'transparent'; fontsize = 14; fontname = "Segoe Ui" } } @@ -531,19 +531,44 @@ function Get-AbrVbrDiagram { Edge -From VBRProxyPointSpace -To VBRRepoPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VBRRepoPoint -To VBRRepoPointSpace @{minlen = 16; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - # If WanAccels add the VBRWanAccelPoint Dummy Node to the line - if ($WanAccels) { + if ($TapeServerInfo -and $WanAccels -and $ServiceProviderInfo) { Edge -From VBRRepoPointSpace -To VBRWanAccelPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - - } - - if ($TapeServerInfo -and $WanAccels) { Edge -From VBRWanAccelPoint -To VBRTapePoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + Edge -From VBRTapePoint -To VBRServiceProviderPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRServiceProviderPoint' - } elseif ($TapeServerInfo -and (-Not $WanAccels)) { + } elseif ($TapeServerInfo -and (-Not $WanAccels) -and $ServiceProviderInfo) { + Edge -From VBRRepoPointSpace -To VBRTapePoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + Edge -From VBRTapePoint -To VBRServiceProviderPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRServiceProviderPoint' + } elseif ($TapeServerInfo -and (-Not $WanAccels) -and (-Not $ServiceProviderInfo)) { Edge -From VBRRepoPointSpace -To VBRTapePoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRTapePoint' + } elseif ((-Not $TapeServerInfo) -and $WanAccels -and $ServiceProviderInfo) { + Edge -From VBRRepoPointSpace -To VBRWanAccelPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + Edge -From VBRWanAccelPoint -To VBRServiceProviderPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRServiceProviderPoint' + } elseif ((-Not $TapeServerInfo) -and (-Not $WanAccels) -and $ServiceProviderInfo) { + Edge -From VBRRepoPointSpace -To VBRServiceProviderPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRServiceProviderPoint' + + } elseif ((-Not $TapeServerInfo) -and $WanAccels -and (-Not $ServiceProviderInfo)) { + Edge -From VBRRepoPointSpace -To VBRWanAccelPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRWanAccelPoint' + } elseif ($TapeServerInfo -and $WanAccels -and (-Not $ServiceProviderInfo)) { + Edge -From VBRRepoPointSpace -To VBRWanAccelPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + Edge -From VBRWanAccelPoint -To VBRTapePoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + $LastPoint = 'VBRTapePoint' + } elseif ((-Not $TapeServerInfo) -and (-Not $WanAccels) -and (-Not $ServiceProviderInfo)) { + $LastPoint = 'VBRRepoPointSpace' } + #################################################################################### + # # + # This section connect the Infrastructure component to the Dummy Points # + # # + #################################################################################### + # Connect Veeam Backup server to the Dummy line Edge -From $BackupServerInfo.Name -To VBRServerPointSpace @{minlen = 2; arrowtail = 'dot'; arrowhead = 'none'; style = 'dashed' } @@ -579,27 +604,19 @@ function Get-AbrVbrDiagram { Edge -From VBRTapePoint -To TapeServer @{minlen = 2; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } } - if ($TapeServerInfo -and (-Not $WanAccels)) { - Edge -From VBRTapePoint -To VBREndPointSpace @{minlen = 30; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - } - - if ($WanAccels -and (-Not $TapeServerInfo)) { - Edge -From VBRWanAccelPoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - } - - if ((-Not $TapeServerInfo) -and (-Not $WanAccels)) { - Edge -From VBRRepoPoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } + # Connect Veeam ServiceProvider Infra to VBRServiceProviderPoint Dummy line + if ($ServiceProviderInfo) { + Edge -From ServiceProvider -To VBRServiceProviderPoint @{minlen = 2; arrowtail = 'dot'; arrowhead = 'none'; style = 'dashed' } } - if ($TapeServerInfo -and $WanAccels -and ($TapeLibraryInfo -or $TapeVaultInfo)) { - Edge -From VBRTapePoint -To VBREndPointSpace @{minlen = 30; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - } elseif ($TapeServerInfo -and $WanAccels -and (-Not ($TapeLibraryInfo -or $TapeVaultInfo))) { - Edge -From VBRTapePoint -To VBREndPointSpace @{minlen = 20; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } - } + #################################################################################### + # # + # This section connect the Last Infrastructure component to VBREndPointSpace # + # # + #################################################################################### - # Connect Veeam Tape Infra to VBRTapePoint Dummy line - if ($ServiceProviderInfo) { - Edge -From VBRServiceProviderPoint -To ServiceProviders @{minlen = 2; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } + if ($LastPoint) { + Edge -From $LastPoint -To VBREndPointSpace @{minlen = 30; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } } } } diff --git a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 index 885ec0d..2570788 100644 --- a/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.Veeam.VBR.ps1 @@ -71,7 +71,7 @@ function Invoke-AsBuiltReport.Veeam.VBR { #region foreach loop foreach ($System in $Target) { - Get-AbrVbrRequiredModule -Name 'Veeam.Backup.PowerShell' -Version '1.0' + Get-AbrVbrRequiredModule -Name 'Veeam.Backup.PowerShell' -Version '12' Get-AbrVbrServerConnection $VeeamBackupServer = ((Get-VBRServerSession).Server).ToString().ToUpper().Split(".")[0] $script:VbrLicenses = Get-VBRInstalledLicense From f4c8d5cdc1036df4b52d77214ac02f5097ee8dd1 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 26 Jul 2024 16:42:52 -0400 Subject: [PATCH 14/14] Update Changelog --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b9a7b7..285e856 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,15 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ##### This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates. -## [0.8.8] - Unreleased +## [0.8.8] - 2024-07-26 ### Added -- Added Tape Infrastructure to the diagram +- Add Tape Infrastructure to the diagram - Tape Server - - Tape Library + - Tape Library - Tape Vault -- Added Service Provider to the diagram +- Add Service Provider to the diagram +- Improve Infrastructure diagram error handling ## [0.8.7] - 2024-05-28