From 9ae4def4d28b42b469b1ff34414997e3b6baa92d Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Sun, 29 Dec 2024 21:43:24 -0400 Subject: [PATCH] Enhance documentation for Get-VbrInfraDiagram and utility functions with detailed descriptions, parameters, examples, and links. --- Src/Private/Get-VbrInfraDiagram.ps1 | 16 +-- Src/Private/SharedUtilsFunctions.ps1 | 160 ++++++++++++++++++++++----- icons/Microsoft_Entra_ID.png | Bin 9239 -> 6970 bytes 3 files changed, 142 insertions(+), 34 deletions(-) diff --git a/Src/Private/Get-VbrInfraDiagram.ps1 b/Src/Private/Get-VbrInfraDiagram.ps1 index 930ac3b..dbf7f65 100644 --- a/Src/Private/Get-VbrInfraDiagram.ps1 +++ b/Src/Private/Get-VbrInfraDiagram.ps1 @@ -1,20 +1,20 @@ function Get-VbrInfraDiagram { <# .SYNOPSIS - Diagram the configuration of Veeam Backup & Replication infrastructure in PDF/SVG/DOT/PNG formats using PSGraph and Graphviz. + Generates a diagram of the Veeam Backup & Replication infrastructure configuration in various formats using PSGraph and Graphviz. .DESCRIPTION - Diagram the configuration of Veeam Backup & Replication infrastructure in PDF/SVG/DOT/PNG formats using PSGraph and Graphviz. + This script creates a visual representation of the Veeam Backup & Replication infrastructure configuration. The output can be generated in PDF, SVG, DOT, or PNG formats. It leverages the PSGraph module for PowerShell and Graphviz for rendering the diagrams. .NOTES Version: 0.6.17 Author(s): Jonathan Colon Twitter: @jcolonfzenpr - Github: rebelinux - Credits: Kevin Marquette (@KevinMarquette) - PSGraph module - Credits: Prateek Singh (@PrateekKumarSingh) - AzViz module + GitHub: rebelinux + Credits: Kevin Marquette (@KevinMarquette) - PSGraph module + Prateek Singh (@PrateekKumarSingh) - AzViz module .LINK - https://github.com/rebelinux/ - https://github.com/KevinMarquette/PSGraph - https://github.com/PrateekKumarSingh/AzViz + GitHub Repository: https://github.com/rebelinux/ + PSGraph Module: https://github.com/KevinMarquette/PSGraph + AzViz Module: https://github.com/PrateekKumarSingh/AzViz #> begin { diff --git a/Src/Private/SharedUtilsFunctions.ps1 b/Src/Private/SharedUtilsFunctions.ps1 index d9be9b1..affaee2 100644 --- a/Src/Private/SharedUtilsFunctions.ps1 +++ b/Src/Private/SharedUtilsFunctions.ps1 @@ -1,13 +1,52 @@ function Get-IconType { <# .SYNOPSIS - Used by Veeam.Diagrammer to translate repository type to icon type object. + Translates repository type to icon type object for Veeam.Diagrammer. + .DESCRIPTION - .NOTES - Version: 0.6.5 - Author: Jonathan Colon + The Get-IconType function takes a repository type as input and returns the corresponding icon type object. + This is used by Veeam.Diagrammer to map different repository types to their respective icons. + + .PARAMETER String + The repository type as a string. Possible values include: + - LinuxLocal + - Hardened + - LinuxHardened + - WinLocal + - Cloud + - GoogleCloudStorage + - AmazonS3Compatible + - AmazonS3Glacier + - AmazonS3 + - AzureArchive + - AzureBlob + - DDBoost + - HPStoreOnceIntegration + - ExaGrid + - SanSnapshotOnly + - Proxy + - ProxyServer + - ESXi + - HyperVHost + - ManuallyDeployed + - IndividualComputers + - ActiveDirectory + - CSV + - CifsShare + - Nfs + - Netapp + - Dell + - VirtualLab + - ApplicationGroups + .EXAMPLE + PS C:\> Get-IconType -String 'LinuxLocal' + VBR_Linux_Repository + + This example translates the 'LinuxLocal' repository type to its corresponding icon type 'VBR_Linux_Repository'. + .LINK + https://github.com/jocolon/Veeam.Diagrammer #> param( [string]$String @@ -52,17 +91,59 @@ function Get-IconType { function Get-RoleType { <# .SYNOPSIS - Used by Veeam.Diagrammer to translate role type to function type object. + Translates a role type string to a function type object. + .DESCRIPTION + The Get-RoleType function takes a string input representing a role type and translates it into a more descriptive function type object. This is used by Veeam.Diagrammer to provide meaningful role descriptions. + + .PARAMETER String + The role type string to be translated. Possible values include: + - LinuxLocal + - LinuxHardened + - WinLocal + - DDBoost + - HPStoreOnceIntegration + - ExaGrid + - InfiniGuard + - Cloud + - SanSnapshotOnly + - vmware + - hyperv + - agent + - nas + - CifsShare + - Nfs + + .RETURNS + A string representing the translated function type object. Possible return values include: + - Linux Local + - Linux Hardened + - Windows Local + - Dedup Appliances + - Cloud + - SAN + - VMware Backup Proxy + - HyperV Backup Proxy + - Agent and Files Backup Proxy + - NAS Backup Proxy + - SMB Share + - NFS Share + - Unknown + .NOTES - Version: 0.6.5 - Author: Jonathan Colon + Version: 0.6.5 + Author: Jonathan Colon + .EXAMPLE + PS C:\> Get-RoleType -String 'LinuxLocal' + Linux Local + + PS C:\> Get-RoleType -String 'vmware' + VMware Backup Proxy + .LINK + https://github.com/veeam/veeam-diagrammer #> - param( - [string]$String - ) $RoleType = Switch ($String) { 'LinuxLocal' { 'Linux Local' } @@ -87,19 +168,45 @@ function Get-RoleType { function ConvertTo-TextYN { <# .SYNOPSIS - Used by As Built Report to convert true or false automatically to Yes or No. + Converts a boolean string representation to "Yes" or "No". + .DESCRIPTION + This function is used to convert boolean string values ("True" or "False") to their corresponding + textual representations ("Yes" or "No"). If the input is an empty string, a space, or null, it returns "--". + Any other input is returned as-is. + + .PARAMETER TEXT + The string value to be converted. It can be "True", "False", an empty string, a space, or null. + + .OUTPUTS + [String] The converted string value. .NOTES - Version: 0.3.0 - Author: LEE DAILEY + Version: 0.3.0 + Author: LEE DAILEY .EXAMPLE + PS C:\> ConvertTo-TextYN -TEXT "True" + Yes - .LINK + PS C:\> ConvertTo-TextYN -TEXT "False" + No + + PS C:\> ConvertTo-TextYN -TEXT "" + -- + + PS C:\> ConvertTo-TextYN -TEXT " " + -- + PS C:\> ConvertTo-TextYN -TEXT $Null + -- + + PS C:\> ConvertTo-TextYN -TEXT "Maybe" + Maybe + + .LINK + https://github.com/AsBuiltReport/AsBuiltReport #> - [CmdletBinding()] [OutputType([String])] Param ( [Parameter ( @@ -122,24 +229,25 @@ function ConvertTo-TextYN { function ConvertTo-FileSizeString { <# .SYNOPSIS - Used by As Built Report to convert bytes automatically to GB or TB based on size. + Converts a size in bytes to a human-readable string representation in KB, MB, GB, TB, or PB. .DESCRIPTION + This function takes a size in bytes and converts it to a more readable format by automatically + selecting the appropriate unit (KB, MB, GB, TB, or PB) based on the size. The result is a string + that includes the rounded size and the unit. + .PARAMETER Size + The size in bytes to be converted. This parameter is mandatory and must be a 64-bit integer. + .OUTPUTS + [String] + A string representing the size in the most appropriate unit. .NOTES Version: 0.1.0 Author: Jonathan Colon .EXAMPLE + PS> ConvertTo-FileSizeString -Size 1073741824 + 1 GB .LINK + https://github.com/your-repository-link #> - [CmdletBinding()] - [OutputType([String])] - Param - ( - [Parameter ( - Position = 0, - Mandatory)] - [int64] - $Size - ) $Unit = Switch ($Size) { { $Size -gt 1PB } { 'PB' ; Break } diff --git a/icons/Microsoft_Entra_ID.png b/icons/Microsoft_Entra_ID.png index baa481f520d3c58efc988c24c29ef4cd41c64c20..617ae9ea1404a90923398120e920369e4462ff7d 100644 GIT binary patch delta 3232 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 Ibu0Y807v`;ZvX%Q delta 5695 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 I4PqDdKP(s2h5!Hn