PowerValidatedSolutions.psm1

# Copyright 2023-2024 Broadcom. All Rights Reserved.
# SPDX-License-Identifier: BSD-2

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# Enable communication with self-signed certificates when using Powershell Core. If you require all communications
# to be secure and do not wish to allow communication with self-signed certificates, remove lines 17-36 before
# importing the module.

if ($PSEdition -eq 'Core') {
    $PSDefaultParameterValues.Add("Invoke-RestMethod:SkipCertificateCheck", $true)
}

if ($PSEdition -eq 'Desktop') {
    # Enable communication with self signed certs when using Windows Powershell
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;

    if ("TrustAllCertificatePolicy" -as [type]) {} else {
        Add-Type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertificatePolicy : ICertificatePolicy {
        public TrustAllCertificatePolicy() {}
        public bool CheckValidationResult(
            ServicePoint sPoint, X509Certificate certificate,
            WebRequest wRequest, int certificateProblem) {
            return true;
        }
    }
"@

        [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertificatePolicy
    }
}

#######################################################################################################################
#Region I D E N T I T Y A N D A C C E S S M A N A G E M E N T F U N C T I O N S ###########

Function Export-IamJsonSpec {
    <#
        .SYNOPSIS
        Create JSON specification for Identity and Access Management.

        .DESCRIPTION
        The Export-IamJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation workbook
        to deploy the Identity and Access Management for VMware Cloud Foundation validated solution:
        - Validates that the Planning and Preparation is available
        - Generates the JSON specification file using the Planning and Preparation workbook

        .EXAMPLE
        Export-IamJsonSpec -workbook .\pnp-workbook.xlsx -jsonFile .\iamDeploySpec.json
        This example creates a JSON specification for Identity and Access Management using the Planning and Preparation workbook.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER jsonFile
        The path to the JSON specification file to be created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        }
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Generation of Identity and Access Management (.json) Specification File"
        if (Test-Path -Path $workbook) {
            $pnpWorkbook = Open-ExcelPackage -Path $Workbook
            $jsonObject = @()
            $jsonObject += [pscustomobject]@{
                'sddcManagerFqdn'               = $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value
                'sddcManagerUser'               = $pnpWorkbook.Workbook.Names["sso_default_admin"].Value
                'sddcManagerPass'               = $pnpWorkbook.Workbook.Names["administrator_vsphere_local_password"].Value
                'mgmtSddcDomainName'            = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value
                'domainFqdn'                    = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'domainBindUserVsphere'         = ($pnpWorkbook.Workbook.Names["iam_vsphere_ad_bind_username"].Value -Split ("@"))[0]
                'domainBindPassVsphere'         = $pnpWorkbook.Workbook.Names["iam_vsphere_ad_bind_password"].Value
                'domainBindUserNsx'             = ($pnpWorkbook.Workbook.Names["iam_nsx_ad_bind_username"].Value -Split ("@"))[0]
                'domainBindPassNsx'             = $pnpWorkbook.Workbook.Names["iam_nsx_ad_bind_password"].Value
                'domainControllerMachineName'   = $pnpWorkbook.Workbook.Names["domain_controller_hostname"].Value
                'baseDn'                        = "dc=" + ($pnpWorkbook.Workbook.Names["child_ad_users_ou"].Value -Split (',dc='),2)[-1]
                'baseGroupDn'                   = $pnpWorkbook.Workbook.Names["child_ad_groups_ou"].Value
                'baseUserDn'                    = $pnpWorkbook.Workbook.Names["child_ad_users_ou"].Value
                'vcenterAdConnectionType'       = (($pnpWorkbook.Workbook.Names["iam_ad_connection_type"].Value -Split ("://"))[0]).ToUpper()
                'vcenterAdminGroup'             = $pnpWorkbook.Workbook.Names["group_gg_vc_admins"].Value
                'vcenterReadOnlyGroup'          = $pnpWorkbook.Workbook.Names["group_gg_vc_read_only"].Value
                'ssoAdminGroup'                 = $pnpWorkbook.Workbook.Names["group_gg_sso_admins"].Value
                'vcfAdminGroup'                 = $pnpWorkbook.Workbook.Names["group_gg_vcf_admins"].Value
                'vcfOperatorGroup'              = $pnpWorkbook.Workbook.Names["group_gg_vcf_operators"].Value
                'vcfViewerGroup'                = $pnpWorkbook.Workbook.Names["group_gg_vcf_viewers"].Value
                'nsxEnterpriseAdminGroup'       = $pnpWorkbook.Workbook.Names["group_gg_nsx_enterprise_admins"].Value + "@" + $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'nsxNetworkAdminsGroup'         = $pnpWorkbook.Workbook.Names["group_gg_nsx_network_admins"].Value + "@" + $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'nsxAuditorGroup'               = $pnpWorkbook.Workbook.Names["group_gg_nsx_auditors"].Value + "@" + $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'nsxAdGroups'                   = "$($pnpWorkbook.Workbook.Names["group_gg_nsx_enterprise_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_nsx_network_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_nsx_auditors"].Value)"
                'vsphereRoleName'               = $pnpWorkbook.Workbook.Names["nsxt_vsphere_role_name"].Value
            }
            Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
            $jsonObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonFile
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            Foreach ($jsonValue in $jsonInput.psobject.properties) {
                if ($jsonValue.value -eq "Value Missing" -or $null -eq $jsonValue.value ) {
                    $issueWithJson = $true
                }
            }
            if ($issueWithJson) {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Creation of JSON Specification file for Identity and Access Management, missing data: POST_VALIDATION_FAILED"
            } else { 
                Show-PowerValidatedSolutionsOutput -message "Creation of JSON Specification file for Identity and Access Management: SUCCESSFUL"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-IamJsonSpec

Function Invoke-IamDeployment {
    <#
        .SYNOPSIS
        End-to-end Deployment of Identity and Access Management

        .DESCRIPTION
        The Invoke-IamDeployment cmdlet is a single function to implement the configuration of the Identity and Access
        Management for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-IamDeployment -jsonFile .\iamDeploySpec.json -certificates ".\certificates\"
        This example configures Identity and Access Management for VMware Cloud Foundation using the JSON spec supplied.

        .PARAMETER jsonFile
        The path to the JSON specification file to be used.

        .PARAMETER certificates
        The path to the directory containing the certificates to be used.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificates
    )

    $solutionName = "Identity and Access Management for VMware Cloud Foundation"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Deployment of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            $rootCertificate = $certificates + "Root64.cer"
            if (Test-Path -Path $rootCertificate) {
                if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn ) {
                    if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                        $allWorkloadDomains     = Get-VCFWorkloadDomain
                        $pvsModulePath          = (Get-InstalledModule -Name PowerValidatedSolutions).InstalledLocation
                        $nsxVsphereTemplate     = $pvsModulePath + "\vSphereRoles\" + "nsx-vsphere-integration.role"

                        Show-PowerValidatedSolutionsOutput -message "Adding Active Directory as an Identity Provider in vCenter Server"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                if ($jsonInput.vcenterAdConnectionType -eq "LDAPS") {
                                    $StatusMsg = Add-IdentitySource -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -dcMachineName $jsonInput.domainControllerMachineName -baseGroupDn $jsonInput.baseGroupDn -baseUserDn $jsonInput.baseUserDn -protocol ldaps -certificate $rootCertificate -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                } else {
                                    $StatusMsg = Add-IdentitySource -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -dcMachineName $jsonInput.domainControllerMachineName -baseGroupDn $jsonInput.baseGroupDn -baseUserDn $jsonInput.baseUserDn -protocol ldap -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Configuring an LDAP Identity Source in NSX Manager"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                $StatusMsg = Add-NsxtIdentitySource -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserNsx -domainBindPass $jsonInput.domainBindPassNsx -dcMachineName $jsonInput.domainControllerMachineName -baseDn $jsonInput.baseDn -protocol ldaps -certificate $rootCertificate -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }
                        
                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Assigning vCenter Server Roles to Active Directory Groups"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                    $StatusMsg = Add-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -principal $jsonInput.vcenterAdminGroup -role Admin -propagate true -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Add-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -principal $jsonInput.vcenterReadOnlyGroup -role ReadOnly -propagate true -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Assigning vCenter Single Sign-On Roles to Active Directory Groups"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                    $StatusMsg = Add-SsoPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -principal $jsonInput.ssoAdminGroup -ssoGroup "Administrators" -type group -source external -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Assigning SDDC Manager Roles to Active Directory Groups"
                            $StatusMsg = Add-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -principal $jsonInput.vcfAdminGroup -role ADMIN -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            $StatusMsg = Add-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere $jsonInput.vcfOperatorGroup -role OPERATOR -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            $StatusMsg = Add-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere $jsonInput.vcfViewerGroup -role VIEWER -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message  "Defining a Custom Role in vSphere for the NSX Service Accounts"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                    $StatusMsg = Add-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -roleName $jsonInput.vsphereRoleName -template $nsxVsphereTemplate -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Assigning NSX Manager Roles to Active Directory Groups"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                $StatusMsg = Add-NsxtLdapRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -type group -principal $jsonInput.nsxEnterpriseAdminGroup -role enterprise_admin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                $StatusMsg = Add-NsxtLdapRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -type group -principal $jsonInput.nsxNetworkAdminsGroup -role network_engineer -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                $StatusMsg = Add-NsxtLdapRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -type group -principal $jsonInput.nsxAuditorGroup -role auditor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Adding NSX Service Accounts to the vCenter Single Sign-On License Administrators Group"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                $serviceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $sddcDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                                $StatusMsg = Add-SsoPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $sddcDomain.ssoName -principal $serviceAccount -ssoGroup "LicenseService.Administrators" -type user -source local -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Reconfiguring the vSphere Role and Permissions Scope for NSX Service Accounts"
                            foreach ($sddcDomain in $allWorkloadDomains) {
                                $serviceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $sddcDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                                $StatusMsg = Add-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $sddcDomain.ssoName -principal $serviceAccount -role $jsonInput.vsphereRoleName -propagate true -type user -localdomain -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg; $ErrorMsg = $null } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                if ($sddcDomain.type -eq "MANAGEMENT") {
                                    $viWorkloadDomains = Get-VCFWorkloadDomain | Where-Object {$_.type -eq "VI"}
                                    foreach ($viDomain in $viWorkloadDomains) {
                                        $viServiceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $viDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                                        $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.ssoName -workloadDomain $sddcDomain.name -principal $viServiceAccount -role "NoAccess" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg; $ErrorMsg = $null } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }
                                if ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -eq "vsphere.local") {
                                    $mgmtWorkloadDomain = Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}
                                    $mgmtServiceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $mgmtWorkloadDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.ssoName -workloadDomain $sddcDomain.name -principal $mgmtServiceAccount -role "NoAccess" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }
                    }
                }
            } else {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Certificate (.cer) for Root Certificate Authority ($rootCertificate): File Not Found"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for Identity and Access Management ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-IamDeployment

Function Invoke-UndoIamDeployment {
    <#
        .SYNOPSIS
        End-to-end removal of Identity and Access Management

        .DESCRIPTION
        The Invoke-UndoIamDeployment cmdlet is a single function to remove the configuration of the Identity and Access
        Management for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-UndoIamDeployment -jsonFile .\iamDeploySpec.json
        This example removes the Identity and Access Management for VMware Cloud Foundation using the JSON spec supplied.

        .PARAMETER jsonFile
        The path to the JSON specification file to be used.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    $solutionName = "Identity and Access Management for VMware Cloud Foundation"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Removal of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn ) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    $allWorkloadDomains     = Get-VCFWorkloadDomain

                    Show-PowerValidatedSolutionsOutput -message "Reconfiguring the vSphere Role and Permissions Scope for NSX Service Accounts"
                    foreach ($sddcDomain in $allWorkloadDomains) {
                        if ($sddcDomain.type -eq "MANAGEMENT") {
                            $viWorkloadDomains = Get-VCFWorkloadDomain | Where-Object {$_.type -eq "VI"}
                            foreach ($viDomain in $viWorkloadDomains) {
                                $viServiceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $viDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                                $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.ssoName -workloadDomain $sddcDomain.name -principal $viServiceAccount -role "Admin" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }
                        if ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -eq "vsphere.local") {
                            $mgmtWorkloadDomain = Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}
                            $mgmtServiceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $mgmtWorkloadDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                            $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.ssoName -workloadDomain $sddcDomain.name -principal $mgmtServiceAccount -role "Admin" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message  "Removing NSX Service Accounts from the vCenter Single Sign-On License Administrators Group"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            $serviceAccount = (Get-VCFCredential | Where-Object {$_.accountType -eq "SERVICE" -and $_.resource.domainName -eq $sddcDomain.name -and $_.resource.resourceType -eq "VCENTER"}).username.Split("@")[-0]
                            $StatusMsg = Undo-SsoPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $sddcDomain.ssoName -principal $serviceAccount -ssoGroup "LicenseService.Administrators" -type user -source local -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing NSX Manager Roles from Active Directory Groups"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            $StatusMsg = Undo-NsxtLdapRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -principal $jsonInput.nsxEnterpriseAdminGroup -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            $StatusMsg = Undo-NsxtLdapRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -principal $jsonInput.nsxNetworkAdminsGroup -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            $StatusMsg = Undo-NsxtLdapRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -principal $jsonInput.nsxAuditorGroup -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing LDAP Identity Source from NSX Manager"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            $StatusMsg = Undo-NsxtIdentitySource -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing the Custom Role in vSphere for the NSX Service Accounts"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                $StatusMsg = Undo-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -roleName $jsonInput.vsphereRoleName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing SDDC Manager Roles from Active Directory Groups"
                        $StatusMsg = Undo-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -principal $jsonInput.vcfAdminGroup -type GROUP -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        $StatusMsg = Undo-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -principal $jsonInput.vcfOperatorGroup -type GROUP -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        $StatusMsg = Undo-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -principal $jsonInput.vcfViewerGroup -type GROUP -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing vCenter Single Sign-On Roles from Active Directory Groups"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                $StatusMsg = Undo-SsoPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -principal $jsonInput.ssoAdminGroup -ssoGroup "Administrators" -type group -source external -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg}
                            }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing vCenter Server Roles from Active Directory Groups"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                $StatusMsg = Undo-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -principal $jsonInput.vcenterAdminGroup -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                $StatusMsg = Undo-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -principal $jsonInput.vcenterReadOnlyGroup -type group -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Removing Active Directory as Identity Provider from vCenter Server"
                        foreach ($sddcDomain in $allWorkloadDomains) {
                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                $StatusMsg = Undo-IdentitySource -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                            }
                        }
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for Identity and Access Management ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-UndoIamDeployment

Function Add-IdentitySource {
    <#
        .SYNOPSIS
        Add Active Directory over LDAP/LDAPS as an Identity Provider to vCenter Server.

        .DESCRIPTION
        The Add-IdentitySource cmdlets adds Active Directory over LDAP/LDAPS as an Identity Provider to the vCenter
        Server and configures is as the default provider. The cmdlet connects to SDDC Manager using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Verifies a connection to the Active Directory Domain Controller using the -domain and -dcMachineName values
        - Adds the Active Directory Domain as an Identity Provider if not already present
        - Configures the new LDAP/LDAPs Identity Provider as the default

        .EXAMPLE
        Add-IdentitySource -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -dcMachineName sfo-ad01 -baseGroupDn "ou=Security Groups,dc=sfo,dc=rainpole,dc=io" -baseUserDn "ou=Security Users,dc=sfo,dc=rainpole,dc=io" -protocol ldap
        This example adds the sfo.rainpole.io domain as the default Identity Provider to vCenter Server using LDAP

        .EXAMPLE
        Add-IdentitySource -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -dcMachineName sfo-ad01 -baseGroupDn "ou=Security Groups,dc=sfo,dc=rainpole,dc=io" -baseUserDn "ou=Security Users,dc=sfo,dc=rainpole,dc=io" -protocol ldaps -certificate F:\certificates\Root64.cer
        This example adds the sfo.rainpole.io domain as the default Identity Provider to vCenter Server using LDAPS.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the workload domain to run against.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER domainBindUser
        The Active Directory bind user.

        .PARAMETER domainBindPass
        The Active Directory bind user password.

        .PARAMETER dcMachineName
        The Active Directory Domain Controller machine name.

        .PARAMETER baseGroupDn
        The Active Directory base group DN.

        .PARAMETER baseUserDn
        The Active Directory base user DN.

        .PARAMETER protocol
        The protocol to use for communication with Active Directory (ldap or ldaps).

        .PARAMETER certificate
        The certificate to use for communication with Active Directory (ldaps only).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$dcMachineName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseGroupDn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseUserDn,
        [Parameter (Mandatory = $true)] [ValidateSet("ldap", "ldaps")] [String]$protocol,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificate
    )

    if (!$PsBoundParameters.ContainsKey("certificate") -and ($protocol -eq "ldaps")) {
        $certificate = Get-ExternalFileName -title "Select the Root CA Certificate File (.cer)" -fileType "cer" -location "default"
    } elseif ($protocol -eq "ldaps") {
        if (!(Test-Path -Path $certificate)) {
            Write-Error  "Certificate (cer) for Root Certificate Authority '$certificate' File Not Found"
            Break
        }
    }

    $domainAlias = ($domain.Split("."))[0].ToUpper()
    $bindUser = $domainBindUser + '@' + ($domain.Split("."))[0].ToLower()
    if ($protocol -eq "ldaps") {
        $primaryUrl = 'ldaps://' + $dcMachineName + '.' + $domain + ':636'
    } elseif ($protocol -eq "ldap") {
        $primaryUrl = 'ldap://' + $dcMachineName + '.' + $domain + ':389'
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (!(Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain })) {
                                if (Test-Connection -ComputerName ($dcMachineName + "." + $domain) -Quiet -Count 1) {
                                    if ($protocol -eq "ldaps") {
                                        Add-LDAPIdentitySource -ServerType ActiveDirectory -Name $domain -DomainName $domain -DomainAlias $domainAlias -PrimaryUrl $primaryUrl -BaseDNUsers $baseUserDn -BaseDNGroups $baseGroupDn -Username $bindUser -Password $domainBindPass -Certificate $certificate
                                    } else {
                                        Add-LDAPIdentitySource -ServerType ActiveDirectory -Name $domain -DomainName $domain -DomainAlias $domainAlias -PrimaryUrl $primaryUrl -BaseDNUsers $baseUserDn -BaseDNGroups $baseGroupDn -Username $bindUser -Password $domainBindPass
                                    }
                                    $managementVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT
                                    if (Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain }) {
                                        if (Test-VsphereConnection -server $($managementVcenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $managementVcenterDetails.fqdn -user $managementVcenterDetails.ssoAdmin -pass $managementVcenterDetails.ssoAdminPass) {
                                                $scriptCommand = '/opt/vmware/bin/sso-config.sh -set_default_identity_sources -i ' + $domain + ''
                                                Invoke-VMScript -VM $vcfVcenterDetails.vmName -ScriptText $scriptCommand -GuestUser $vcfVcenterDetails.root -GuestPassword $vcfVcenterDetails.rootPass | Out-Null
                                                Write-Output "Adding Identity Source to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): SUCCESSFUL"
                                            }
                                        }
                                    } else {
                                        Write-Error "Adding Identity Source to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): POST_VALIDATION_FAILED"
                                    }
                                    Disconnect-VIServer -Server $managementVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue | Out-Null
                                } else {
                                    Write-Error "Unable to communicate with Active Directory Domain Controller ($dcMachineName), check details: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding Identity Source to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain), already exists: SKIPPED"
                            }
                        }
                        Disconnect-SsoAdminServer * -WarningAction SilentlyContinue; $DefaultSsoAdminServers = $null
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-IdentitySource

Function Undo-IdentitySource {
    <#
        .SYNOPSIS
        Removes Active Directory over LDAP/LDAPS as an Identity Provider from vCenter Server.

        .DESCRIPTION
        The Undo-IdentitySource cmdlets removes Active Directory over LDAP/LDAPS as an Identity Provider from the
        vCenter Server. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Removes the Active Directory Domain as an Identity Provider if its present

        .EXAMPLE
        Undo-IdentitySource -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io
        This example removes the sfo.rainpole.io domain as an Identity Provider from vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the workload domain to run against.

        .PARAMETER domain
        The Active Directory domain name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain }) {
                                Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain } | Remove-IdentitySource | Out-Null
                                if (!(Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain })) {
                                    Write-Output "Removing Identity Source from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing Identity Source from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): POST_VALIDATION_FAILED"
                                }                                
                            } else {
                                Write-Warning "Removing Identity Source from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain), does not exist: SKIPPED"
                            }
                        }
                        Disconnect-SsoAdminServer * -WarningAction SilentlyContinue; $DefaultSsoAdminServers = $null
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-IdentitySource

Function Add-SddcManagerRole {
    <#
        .SYNOPSIS
        Assign SDDC Manager roles to a user/group.

        .DESCRIPTION
        The Add-SddcManagerRole cmdlet assigns an SDDC Manager role to the user or group provided. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Verifies that the bind credetials are valid
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Verifies that the domain is present in vCenter Server as an Identity Provider
        - Verifies the user or group exists in Active Directory
        - Assigns the user or group to the SDDC Manager role

        .EXAMPLE
        Add-SddcManagerRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -principal gg-vcf-admins -role ADMIN -type group
        This example assigns the group gg-vcf-admins from domain sfo.rainpole.io the SDDC Manager role ADMIN

        .EXAMPLE
        Add-SddcManagerRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -principal compliance -role OPERATOR -type user
        This example assigns the user compliance from domain sfo.rainpole.io the SDDC Manager role OPERATOR.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER domainBindUser
        The Active Directory bind user.

        .PARAMETER domainBindPass
        The Active Directory bind user password.

        .PARAMETER principal
        The user or group to assign the role to.

        .PARAMETER role
        The role to assign to the user or group.

        .PARAMETER type
        The type of user or group to assign the role to (group or user).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("ADMIN", "OPERATOR", "VIEWER")] [String]$role,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type
    )

    Try {
        $checkAdAuthentication = Test-ADAuthentication -user $domainBindUser -pass $domainBindPass -server $domain -domain $domain -ErrorAction SilentlyContinue
        if ($checkAdAuthentication[1] -match "Authentication Successful") {
            $securePass = ConvertTo-SecureString -String $domainBindPass -AsPlainText -Force
            $domainCreds = New-Object System.Management.Automation.PSCredential ($domainBindUser, $securePass)
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                        if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain }) {
                                    if ($type -eq "group") { $adObjectCheck = (Get-ADGroup -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal }) }
                                    elseif ($type -eq "user") { $adObjectCheck = (Get-ADUser -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal }) }
                                    if ($adObjectCheck) {
                                        if ($type -eq "group") {
                                            $vcfCheck = Get-VCFUser | Where-Object { $_.name -eq $($domain.ToUpper() + "\" + $principal) }
                                            if ($vcfCheck.name -eq $($domain.ToUpper() + "\" + $principal)) {
                                                Write-Warning "Assigning the role ($role) in SDDC Manager ($server) to Active Directory $type ($principal), already assigned: SKIPPED"
                                            } else {
                                                New-VCFGroup -group $principal -domain $domain -role $role | Out-Null
                                                $vcfCheck = Get-VCFUser | Where-Object { $_.name -eq $($domain.ToUpper() + "\" + $principal) }
                                                if ($vcfCheck.name -eq $($domain.ToUpper() + "\" + $principal)) {
                                                    Write-Output "Assigning the role ($role) in SDDC Manager ($server) to Active Directory $type ($principal): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Assigning the role ($role) in SDDC Manager ($server) to Active Directory $type ($principal): POST_VALIDATION_FAILED"
                                                }
                                            }
                                        } elseif ($type -eq "user") {
                                            $vcfCheck = Get-VCFUser | Where-Object { $_.name -eq $($principal + "@" + $domain.ToUpper()) }
                                            if ($vcfCheck.name -eq $($principal + "@" + $domain.ToUpper())) {
                                                Write-Warning "Assigning the role ($role) in SDDC Manager ($server) to Active Directory $type ($principal), already assigned: SKIPPED"
                                            } else {
                                                New-VCFUser -user ($principal + "@" + $domain.ToUpper()) -role $role | Out-Null
                                                $vcfCheck = Get-VCFUser | Where-Object { $_.name -eq $($principal + "@" + $domain.ToUpper()) }
                                                if ($vcfCheck.name -eq $($principal + "@" + $domain.ToUpper())) {
                                                    Write-Output "Assigning the role ($role) in SDDC Manager ($server) to Active Directory $type ($principal): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Assigning the role ($role) in SDDC Manager ($server) to Active Directory $type ($principal): POST_VALIDATION_FAILED"
                                                }
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to find $type ($principal) in the Active Directory Domain: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find Identity Source in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Write-Error  "Unable to authenticate to Active Directory with user ($domainBindUser) and password ($domainBindPass), check details: PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-SddcManagerRole

Function Undo-SddcManagerRole {
    <#
        .SYNOPSIS
        Remove access for a user/group in SDDC Manager.

        .DESCRIPTION
        The Undo-SddcManagerRole cmdlet removes access for a user or group in SDDC Manager. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Removes the user or group from SDDC Manager if present

        .EXAMPLE
        Undo-SddcManagerRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -principal gg-vcf-admins -type GROUP
        This example removes access for the group gg-vcf-admins from SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER principal
        The user or group to remove access for.

        .PARAMETER type
        The type of user or group to remove access for (group or user).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("GROUP","USER")] [String]$type
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFUser -type $type | Where-Object {$_.name -match $principal}) {
                    Remove-VCFUser -id (Get-VCFUser -type $type | Where-Object {$_.name -match $principal}).id | Out-Null
                    if (!(Get-VCFUser -type $type | Where-Object {$_.name -match $principal})) { 
                        Write-Output "Removing $type from SDDC Manager ($server) named ($principal): SUCCESSFUL"
                    } else {
                        Write-Error "Removing $type from SDDC Manager ($server) named ($principal): POST_VALIDATION_FAILED"
                    }
                } else {
                    Write-Warning "Removing $type from SDDC Manager ($server) named ($principal), not assigned: SKIPPED"
                }                                 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SddcManagerRole

Function Install-WorkspaceOne {
    <#
        .SYNOPSIS
        Deploy Workspace ONE Access Virtual Appliance.

        .DESCRIPTION
        The Install-WorkspaceOne cmdlet deploys the Workspace ONE Access Virtual Appliance OVA. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Gathers DNS and NTP configuration from SDDC Manager
        - Deploys the Workspace ONE Access Virtual Appliance to the Management Domain vCenter Server

        .EXAMPLE
        Install-WorkspaceOne -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -wsaIpAddress 192.168.31.60 -wsaGateway 192.168.31.1 -wsaSubnetMask 255.255.255.0 -wsaOvaPath F:\identity-manager.ova -wsaFolder sfo-m01-fd-wsa
        This example deploys the Workspace ONE Access Virtual Appliance named sfo-wsa01.sfo.rainpole.io into the sfo-m01-fd-wsa folder of the management domain
    
        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaIpAddress
        The IP Address of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaGateway
        The Gateway of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaSubnetMask
        The Subnet Mask of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaOvaPath
        The path to the Workspace ONE Access Virtual Appliance OVA file.

        .PARAMETER wsaFolder
        The folder to deploy the Workspace ONE Access Virtual Appliance to.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaIpAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaGateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaSubnetMask,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFolder,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$wsaOvaPath
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("wsaOvaPath")) {
            $wsaOvaPath = Get-ExternalFileName -title "Select the Workspace ONE Access OVA file (.ova)" -fileType "ova" -location "default"
        } else {
            if (!(Test-Path -Path $wsaOvaPath)) {
                Write-Error  "Workspace ONE Access OVA '$wsaOvaPath' File Not Found"
                Break
            }
        }
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $wsaHostname = $wsaFqdn.Split(".")[0]
                            if (Get-VM -Name $wsaHostname -ErrorAction Ignore) {
                                Write-Warning "Deploying a virtual machine in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($wsaHostname), already exists: SKIPPED"
                            } else {
                                $dnsServer1 = (Get-VCFConfigurationDNS | Where-Object { $_.isPrimary -Match "True" }).ipAddress
                                $dnsServer2 = (Get-VCFConfigurationDNS | Where-Object { $_.isPrimary -Match "False" }).ipAddress
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.type -eq "MANAGEMENT" }).clusters.id) }).Name
                                $datastore = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.type -eq "MANAGEMENT" }).clusters.id) }).primaryDatastoreName
                                $datacenter = (Get-Datacenter -Cluster $cluster).Name
                                $avnCheck = (Get-VCFApplicationVirtualNetwork | Where-Object { $_.regionType -eq "REGION_A" }).name
                                if ($avnCheck) {
                                    $regionaPortgroup = (Get-VCFApplicationVirtualNetwork | Where-Object { $_.regionType -eq "REGION_A" }).name
                                    $domain = (Get-VCFApplicationVirtualNetwork | Where-Object { $_.regionType -eq "REGION_A" }).domainName
                                    $command = '"C:\Program Files\VMware\VMware OVF Tool\ovftool.exe" --noSSLVerify --acceptAllEulas --allowAllExtraConfig --diskMode=thin --powerOn --name=' + $wsaHostname + ' --ipProtocol="IPv4" --ipAllocationPolicy="fixedAllocatedPolicy" --vmFolder=' + $wsaFolder + ' --net:"Network 1"=' + $regionaPortgroup + ' --datastore=' + $datastore + ' --X:injectOvfEnv --prop:vamitimezone=' + $timezone + ' --prop:vami.ip0.IdentityManager=' + $wsaIpAddress + ' --prop:vami.netmask0.IdentityManager=' + $wsaSubnetMask + ' --prop:vami.hostname=' + $wsaFqdn + ' --prop:vami.gateway.IdentityManager=' + $wsaGateway + ' --prop:vami.domain.IdentityManager=' + $domain + ' --prop:vami.searchpath.IdentityManager=' + $domain + ' --prop:vami.DNS.IdentityManager=' + $dnsServer1 + ',' + $dnsServer2 + ' "' + $wsaOvaPath + '" "vi://' + $vcfVcenterDetails.ssoAdmin + ':' + $vcfVcenterDetails.ssoAdminPass + '@' + $vcfVcenterDetails.fqdn + '/' + $datacenter + '/host/' + $cluster + '/"'
                                    Invoke-Expression "& $command" -ErrorAction Ignore
                                    if (Get-VM -Name $wsaHostname -ErrorAction Ignore) {
                                        $Timeout = 900  ## seconds
                                        $CheckEvery = 15  ## seconds
                                        Try {
                                            $timer = [Diagnostics.Stopwatch]::StartNew()  ## Start the timer
                                            Write-Output "Waiting for $wsaIpAddress to become pingable."
                                            While (-not (Test-Connection -ComputerName $wsaIpAddress -Quiet -Count 1)) {
                                                ## If the timer has waited greater than or equal to the timeout, throw an exception exiting the loop
                                                if ($timer.Elapsed.TotalSeconds -ge $Timeout) {
                                                    Throw "Timeout Exceeded. Giving up on ping availability to $wsaIpAddress"
                                                }
                                                Start-Sleep -Seconds $CheckEvery  ## Stop the loop every $CheckEvery seconds
                                            }
                                        } Catch {
                                            Write-Error "Failed to get a Response from Workspace ONE Access Instance ($wsaFqdn): POST_VALIDATION_FAILURE"
                                        } Finally {                                   
                                            $timer.Stop()  ## Stop the timer
                                        }
                                        $Timeout = 900  ## seconds
                                        $CheckEvery = 5  ## seconds
                                        Try {
                                            $timer = [Diagnostics.Stopwatch]::StartNew()  ## Start the timer
                                            $uri = "https://" + $wsaFqdn + "/SAAS/jersey/manager/api/system/health"
                                            Write-Output "Initial connection made, waiting for ($wsaFqdn) to fully boot and services to start. Be warned, this takes a long time."
                                            While ($timer.Elapsed.TotalSeconds -lt $Timeout) {
                                                ## If the timer has waited greater than or equal to the timeout, throw an exception exiting the loop
                                                Try {
                                                    $response = Invoke-RestMethod $uri -Method 'GET' -SessionVariable webSession -ErrorAction Ignore
                                                    if ($response.AllOk -eq "true") {
                                                        Write-Output "Deploying Workspace ONE Access Instance ($wsaFqdn) using ($wsaOvaPath): SUCCESSFUL"
                                                        break
                                                    }
                                                } Catch {
                                                    Write-Output "Waiting for ($wsaFqdn) to fully boot up. Checking every $CheckEvery seconds"
                                                }
                                                Start-Sleep -Seconds $CheckEvery  ## Stop the loop every $CheckEvery seconds
                                            }
                                            if ($timer.Elapsed.TotalSeconds -ge $Timeout) {
                                                Write-Error "Workspace ONE Access Instance ($wsaFqdn) failed to initialize properly. Please delete the VM from vCenter Server ($($vcfVcenterDetails.fqdn)) and retry: POST_VAIDATION_FAILED"
                                            }
                                        } Catch {
                                            Debug-ExceptionWriter -object $_
                                        } Finally {
                                            $timer.Stop()  ## Stop the timer
                                        }
                                    } else {
                                        Write-Error "Deployment of Workspace ONE Access Instance ($wsaFqdn): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error  "Application Virtual Networks have not been configured in SDDC Manager ($server), unable to find REGION_A details. Deploy and try again: PRE_VALIDATION_FAILED"
                                }
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-WorkspaceOne

Function Undo-WorkspaceOne {
    <#
        .SYNOPSIS
        Remove Workspace ONE Access Virtual Appliance.

        .DESCRIPTION
        The Undo-WorkspaceOne cmdlet removes the Workspace ONE Access Virtual Appliance. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Removes the Workspace ONE Access Virtual Appliance from the Management Domain vCenter Server

        .EXAMPLE
        Undo-WorkspaceOne -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaHostname sfo-wsa01
        This example removes the Workspace ONE Access Virtual Appliance named sfo-wsa01 from the Management Domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER wsaHostname
        The hostname of the Workspace ONE Access Virtual Appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaHostname
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VM -Name $wsaHostname -ErrorAction Ignore) {
                                if ((Get-VM -Name $wsaHostname).PowerState -ne "PoweredOff") {
                                    Stop-VM -VM $wsaHostname -Kill -Confirm:$false | Out-Null
                                    if ((Get-VM -Name $wsaHostname).PowerState -ne "PoweredOff") {
                                        Write-Error "Unable to Power Off virtual machine: PRE_VALIDATION_FAILED"
                                        Break
                                    }
                                }
                                Remove-VM $wsaHostname -DeletePermanently -Confirm:$false | Out-null
                                if (!(Get-VM -Name $wsaHostname -ErrorAction Ignore)) {
                                    Write-Output "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($wsaHostname): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($wsaHostname): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($wsaHostname), already removed: SKIPPED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-WorkspaceOne

Function Initialize-WorkspaceOne {
    <#
        .SYNOPSIS
        Initalize Workspace ONE Access Virtual Appliance.

        .DESCRIPTION
        The Initialize-WorkspaceOne cmdlet performs the initial configuration of Workspace ONE Access Virtual Appliance.
        - Validates that network connectivity is possible to Workspace ONE Access
        - Sets the default password for the admin, root and SSH Users
        - Initializes the internal PostgrsSQL database
        - Activates the default connector

        .EXAMPLE
        Initialize-WorkspaceOne -wsaFqdn sfo-wsa01.sfo.rainpole.io -adminPass VMw@re1! -rootPass VMw@re1! -sshUserPass VMw@re1!
        This example initialzes the Workspace ONE Access Virtual Appliance sfo-wsa01.sfo.rainpole.io and sets the default passwords for admin, root and SSH User.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER adminPass
        The default password for the admin user.

        .PARAMETER rootPass
        The default password for the root user.

        .PARAMETER sshUserPass
        The default password for the SSH User.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adminPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sshUserPass
    )

    Try {
        if (Test-WSAConnection -server $wsaFqdn) {
            if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)
{
                $certCallback = @"
    using System;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    public class ServerCertificateValidationCallback
    {
        public static void Ignore()
        {
            if(ServicePointManager.ServerCertificateValidationCallback ==null)
            {
                ServicePointManager.ServerCertificateValidationCallback +=
                    delegate
                    (
                        Object obj,
                        X509Certificate certificate,
                        X509Chain chain,
                        SslPolicyErrors errors
                    )
                    {
                        return true;
                    };
            }
        }
    }
"@

                Add-Type $certCallback
            }

            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
            [ServerCertificateValidationCallback]::Ignore()
            $loginUri = "https://" + $wsaFqdn + "/SAAS/auth/login"
            $response = Invoke-RestMethod $loginUri -Method 'GET' -SessionVariable webSession -UseBasicParsing
            $response | Out-File wsaResponse.txt
            $tokenSource = (Select-String -Path wsaResponse.txt -Pattern 'window.ec_wiz.vk =')
            $token = ($tokenSource -Split ("'"))[1]
            Remove-Item wsaResponse.txt
            $baseUri = "https://" + $wsaFqdn + ":8443"
            if ($token) {
                $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
                $headers.Add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                $headers.Add("X-Vk", "$token")
                $headers.Add("Accept", "application/json")
                # Set the Admin Password
                $body = "password=" + $adminPass + "&confpassword=" + $adminPass
                $uri = $baseUri + "/cfg/changePassword"
                Invoke-RestMethod $uri -Method 'POST' -Headers $headers -Body $body -WebSession $webSession | Out-Null
                # Set the root and SSHUser Passwords
                $body = "rootPassword=" + $rootPass + "&sshuserPassword=" + $sshUserPass
                $uri = $baseUri + "/cfg/system"
                Invoke-RestMethod $uri -Method 'POST' -Headers $headers -Body $body -WebSession $webSession  | Out-Null
                # Initalize the Internal Database
                $uri = $baseUri + "/cfg/setup/initialize"
                Invoke-RestMethod $uri -Method 'POST' -Headers $headers -WebSession $webSession  | Out-Null
                # Activate the default connector
                $uri = $baseUri + "/cfg/setup/activateConnector"
                Invoke-RestMethod $uri -Method 'POST' -Headers $headers -WebSession $webSession  | Out-Null
                Write-Output "Initial Configuration of Workspace ONE Access Instance ($wsaFqdn): SUCCESSFUL"
            } else {
                Write-Warning "Initial Configuration of Workspace ONE Access Instance ($wsaFqdn), already performed: SKIPPED"
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Initialize-WorkspaceOne

Function Set-WorkspaceOneNtpConfig {
    <#
        .SYNOPSIS
        Configure NTP Server on Workspace ONE Access Appliance.

        .DESCRIPTION
        The Set-WorkspaceOneNtpConfig cmdlet configures the NTP Server details of the Workspace ONE Access Appliance
        using the primary NTP Server configured on SDDC Manager if no NTP Server is provided. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Gathers the NTP configuration details from SDDC Manager
        - Configures Workspace ONE Access NTP configuration

        .EXAMPLE
        Set-WorkspaceOneNtpConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -rootPass VMw@re1!
        This example configures the Workspace ONE Access Virtual Appliance sfo-wsa01.sfo.rainpole.io with the primary NTP server defined in SDDC Manager

        .EXAMPLE
        Set-WorkspaceOneNtpConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -rootPass VMw@re1! -ntpServer ntp.lax.rainpole.io
        This example adds the NTP server ntp.lax.rainpole.io to the Workspace ONE Access Virtual Appliance sfo-wsa01.sfo.rainpole.io

        .EXAMPLE
        Set-WorkspaceOneNtpConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -rootPass VMw@re1! -vrslcmIntegrated -ntpServer ntp.lax.rainpole.io
        This example adds the NTP server ntp.lax.rainpole.io to the VMware Aria Suite Lifecycle integrated Workspace ONE Access nodes

        .EXAMPLE
        Set-WorkspaceOneNtpConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vrslcmIntegrated
        This example adds the primary NTP server defined in SDDC Manager to the VMware Aria Suite Lifecycle integrated Workspace ONE Access nodes
    
        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER rootPass
        The root password of the Workspace ONE Access Virtual Appliance.

        .PARAMETER ntpServer
        The NTP Server to configure on the Workspace ONE Access Virtual Appliance.

        .PARAMETER vrslcmIntegrated
        Flag to indicate if the Workspace ONE Access Virtual Appliance is integrated with VMware Aria Suite Lifecycle Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false, ParameterSetName = 'standaloneWsa')] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $false, ParameterSetName = 'standaloneWsa')] [ValidateNotNullOrEmpty()] [String]$rootPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ntpServer,
        [Parameter (Mandatory = $false, ParameterSetName = 'vrslcmIntegrated')] [ValidateNotNullOrEmpty()] [Switch]$vrslcmIntegrated
    )
    
    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($ntpServer) {
                                if ((Test-NtpServer -Server $ntpServer) -eq $false) {
                                    Write-Error "Unable to confirm NTP server $ntpServer is valid: PRE_VALIDATION_FAILED"
                                    Break
                                }
                            } else {
                                $ntpServer = (Get-VCFConfigurationNTP).ipAddress[0]
                            }
                            if ($vrslcmIntegrated) {
                                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                                    if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                        $wsaVms = Get-vRSLCMProductNode -environmentName globalenvironment -product vidm
                                        foreach ($wsaVm in $wsaVms) {
                                            $wsaRootPass = (Get-VCFCredential | Where-Object {$_.resource.resourceName -eq $wsaVm.hostname -and $_.username -eq "root"}).password
                                            if (Test-WSAConnection -server $wsaVm.hostname) {
                                                if ((Get-VM -Name $wsaVm.vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                                    Set-WorkspaceOneApplianceNtpConfig -vmName $wsaVm.vmName -rootPass $wsaRootPass -ntpServer $ntpServer
                                                } else {
                                                    Write-Error "Unable to locate a virtual machine named ($($wsaVm.vmName)) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                                }
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to connect to VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn) to gather Workspace ONE Access appliance inventory: PRE_VALIDATION_FAILED"
                                    }
                                    Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                }
                            } else {
                                if (!$wsaFqdn) {
                                    Write-Error "The FQDN parameter (-wsaFqdn) is required for a standalone Workspace ONE Access instance: PRE_VALIDATION_FAILED"
                                }
                                $vmName = $wsaFqdn.Split(".")[0]
                                if (Test-WSAConnection -server $wsaFqdn) {
                                    if ((Get-VM -Name $vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                        Set-WorkspaceOneApplianceNtpConfig -vmName $vmName -rootPass $rootPass -ntpServer $ntpServer
                                    } else {
                                        Write-Error  "Unable to locate a virtual machine named ($vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                    }
                                    Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-WorkspaceOneNtpConfig

Function Install-WorkspaceOneCertificate {
    <#
        .SYNOPSIS
        Install a Signed Certificate on Workspace ONE Access Appliance.

        .DESCRIPTION
        The Install-WorkspaceOneCertificate cmdlet replaces the certificate on the Workspace ONE Access. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Copies over the certificate files to the Workspace ONE Access appliance and installs the certificate

        .EXAMPLE
        Install-WorkspaceOneCertificate -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -rootPass VMw@re1! -sshUserPass VMw@re1!
        This example install the Workspace ONE Access Virtual Appliance sfo-wsa01.sfo.rainpole.io with a the signed certificate provided.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER rootPass
        The root password of the Workspace ONE Access Virtual Appliance.

        .PARAMETER sshUserPass
        The SSH User password of the Workspace ONE Access Virtual Appliance.

        .PARAMETER rootCa
        The Root Certificate Authority certificate file (.cer).

        .PARAMETER wsaCertKey
        The Workspace ONE Access certificate key file (.key).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sshUserPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$rootCa,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$wsaCertKey,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$wsaCert
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("rootCa")) {
            $rootCa = Get-ExternalFileName -title "Select the Root CA Certificate File (.cer)" -fileType "cer" -location "default"
        } elseif ($PsBoundParameters.ContainsKey("rootCa")) {
            if (!(Test-Path -Path $rootCa)) {
                Write-Error  "Certificate (.cer) for Root Certificate Authority ($rootCa) File Not Found"
                Break
            }
        }
        if (!$PsBoundParameters.ContainsKey("wsaCertKey")) {
            $wsaCertKey = Get-ExternalFileName -title "Select the Workspace ONE Access Certificate Key (.key)" -fileType "key" -locaion "default"
        } elseif ($PsBoundParameters.ContainsKey("wsaCertKey")) {
            if (!(Test-Path -Path $wsaCertKey)) {
                Write-Error  "Certificate Key (.key) for Workspace ONE Access ($wsaCertKey) File Not Found"
                Break
            }
        }
        if (!$PsBoundParameters.ContainsKey("wsaCert")) {
            $wsaCert = Get-ExternalFileName -title "Select the Workspace ONE Access Certificate File (.cer)" -fileType "cer" -location "default"
        } elseif ($PsBoundParameters.ContainsKey("wsaCert")) {
            if (!(Test-Path -Path $wsaCert)) {
                Write-Error  "Certificate (.cer) for Workspace ONE Access ($wsaCert) File Not Found"
                Break
            }
        }
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Test-WSAConnection -server $wsaFqdn) {
                                $vmName = $wsaFqdn.Split(".")[0]
                                Get-Item $rootCa | Copy-VMGuestFile -Destination '/tmp' -VM $vmName -LocalToGuest -GuestUser root -GuestPassword $rootPass -Force
                                Get-Item $wsaCertKey | Copy-VMGuestFile -Destination '/tmp' -VM $vmName -LocalToGuest -GuestUser root -GuestPassword $rootPass -Force
                                Get-Item $wsaCert | Copy-VMGuestFile -Destination '/tmp' -VM $vmName -LocalToGuest -GuestUser root -GuestPassword $rootPass -Force
                                $scriptCommand = 'echo "yes" | /usr/local/horizon/scripts/installExternalCertificate.hzn --ca /tmp/' + (Split-Path -Leaf $rootCa) + ' --cert /tmp/' + (Split-Path -Leaf $wsaCert) + ' --key /tmp/' + (Split-Path -Leaf $wsaCertKey)
                                $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcenter.fqdn
                                Write-Output "Installing Signed Certifcate on Workspace ONE Access Instance ($wsaFqdn) using ($wsaCert): SUCCESSFUL"
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-WorkspaceOneCertificate

Function Set-WorkspaceOneSmtpConfig {
    <#
        .SYNOPSIS
        Configure SMTP Server on Workspace ONE Access Appliance
        
        .DESCRIPTION
        The Set-WorkspaceOneSmtpConfig cmdlet configures the SMTP Server details of the Workspace ONE Access Appliance.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to Workspace ONE Access
        - Configures the SMTP Server settings

        .EXAMPLE
        Set-WorkspaceOneSmtpConfig -server sfo-wsa01.sfo.rainpole.io -user admin -pass VMw@re1! -smtpFqdn smtp.sfo.rainpole.io -smtpPort 25 -smtpEmail sfo-wsa@rainpole.io
        This example configures the Workspace ONE Access Virtual Appliance sfo-wsa01.sfo.rainpole.io with the SMTP Server details.

        .PARAMETER server
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER user
        The admin username of the Workspace ONE Access Virtual Appliance.

        .PARAMETER pass
        The admin password of the Workspace ONE Access Virtual Appliance.

        .PARAMETER smtpFqdn
        The FQDN of the SMTP Server.

        .PARAMETER smtpPort
        The port of the SMTP Server.

        .PARAMETER smtpEmail
        The email address to send emails from.

        .PARAMETER smtpEmailPassword
        The password of the email address to send emails from.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpPort,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpEmail,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$smtpEmailPassword
    )

    Try {
        if (Test-WSAConnection -server $server) {
            if (Test-WSAAuthentication -server $server -user $user -pass $pass) {
                if (!(Get-WSASmtpConfiguration | Where-Object {$_.host -eq $smtpFqdn})) {
                    if (-not $PsBoundParameters.ContainsKey("smtpEmailPassword")) {
                        Set-WSASmtpConfiguration -fqdn $smtpFqdn -port $smtpPort -user $smtpEmail | Out-Null
                    }
                    if ($PsBoundParameters.ContainsKey("smtpEmailPassword")) {
                        Set-WSASmtpConfiguration -fqdn $smtpFqdn -port $smtpPort -user $smtpEmail -pass $smtpEmailPassword | Out-Null
                    }
                    if (Get-WSASmtpConfiguration | Where-Object {$_.host -eq $smtpFqdn}) {
                        Write-Output "Configuring SMTP Server for Workspace ONE Access Instance ($server) with SMTP Server ($smtpFqdn): SUCCESSFUL"
                    } else {
                        Write-Error "Configuring SMTP Server for Workspace ONE Access Instance ($server) with SMTP Server ($smtpFqdn): POST_VALIDATION_FAILED"
                    }
                } else {
                    Write-Warning "Configuring SMTP Server for Workspace ONE Access Instance ($server) with SMTP Server ($smtpFqdn), already exists: SKIPPED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-WorkspaceOneSmtpConfig

Function Add-WorkspaceOneDirectory {
    <#
        .SYNOPSIS
        Configure Active Directory LDAP Directory in Workspace ONE Access Appliance.

        .DESCRIPTION
        The Add-WorkspaceOneDirectory cmdlet configures Active Directory LDAP Directory in Workspace ONE Access
        Appliance. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to Workspace ONE Access
        - Validates that the bind user can authenticate to the domain
        - Creates an identity provider within Workspace ONE Access

        .EXAMPLE
        Add-WorkspaceOneDirectory -server sfo-wsa01.sfo.rainpole.io -user admin -pass VMw@re1! -domain sfo.rainpole.io -baseDnUser "OU=Security Users,DC=sfo,DC=rainpole,DC=io" -baseDnGroup "OU=Security Groups,DC=sfo,DC=rainpole,DC=io" -bindUserDn "CN=svc-wsa-ad,OU=Security Users,DC=sfo,DC=rainpole,DC=io" -bindUserPass VMw@re1! -adGroups "gg-nsx-enterprise-admins","gg-nsx-network-admins","gg-nsx-auditors","gg-wsa-admins","gg-wsa-directory-admins","gg-wsa-read-only" -protocol "ldaps" -certificate "F:\platformtools-l1-dev\certificates\Root64.pem"
        This example configures the domain sfo.rainpole.io as a directory source in Workspace ONE Access Virtual Appliance and syncronises the groups provided
    
        .PARAMETER server
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER user
        The admin username of the Workspace ONE Access Virtual Appliance.

        .PARAMETER pass
        The admin password of the Workspace ONE Access Virtual Appliance.

        .PARAMETER domain
        The domain name of the Active Directory Domain.

        .PARAMETER baseDnUser
        The base DN of the Active Directory Users.

        .PARAMETER baseDnGroup
        The base DN of the Active Directory Groups.

        .PARAMETER bindUserDn
        The bind user DN of the Active Directory Domain.

        .PARAMETER bindUserPass
        The bind user password of the Active Directory Domain.

        .PARAMETER adGroups
        The Active Directory Groups to synchronize.

        .PARAMETER protocol
        The protocol to use for the connection to the Active Directory Domain.

        .PARAMETER certificate
        The Root Certificate Authority certificate file (.cer).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDnUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDnGroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUserDn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUserPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$adGroups,
        [Parameter (Mandatory = $true)] [ValidateSet("ldap", "ldaps")] [String]$protocol,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificate
    )

    if (!$PsBoundParameters.ContainsKey("certificate") -and ($protocol -eq "ldaps")) {
        $certificate = Get-ExternalFileName -title "Select the Root CA Certificate File (.pem)" -fileType "pem" -location "default"
    } elseif ($protocol -eq "ldaps") {
        if (!(Test-Path -Path $certificate)) {
            Write-Error  "Certificate (cer) for Root Certificate Authority ($certificate') File Not Found"
            Break
        }
    }

    Try {
        if (Test-WSAConnection -server $server) {
            if (Test-WSAAuthentication -server $server -user $user -pass $pass) {
                $checkAdAuthentication = Test-ADAuthentication -user ($bindUserDn.Split(",")[0]).Split("=")[1] -pass $bindUserPass -server $domain -domain $domain -ErrorAction SilentlyContinue
                if ($checkAdAuthentication[1] -match "Authentication Successful") {
                    if (!(Get-WSADirectory | Where-Object { ($_.name -eq $domain) })) {
                        if ($protocol -eq "ldaps") {
                            $directory = Add-WSALdapDirectory -domainName $domain -baseDn $baseDnUser -bindDn $bindUserDn -certificate $certificate
                        } else{
                            $directory = Add-WSALdapDirectory -domainName $domain -baseDn $baseDnUser -bindDn $bindUserDn
                        }
                        $connector = Get-WSAConnector | Where-Object {$_.host -eq $server}
                        Set-WSABindPassword -directoryId $directory.directoryConfigId -connectorId $connector.instanceId -pass $bindUserPass | Out-Null
                        $adUserJson = '{ "identityUserInfo": { "' + $bindUserDn + '": { "selected": true }, "' + $baseDnUser + '": { "selected": true }}}'
                        $mappedGroupObject = @()
                        foreach ($group in $adGroups) {
                            $adGroupDetails = Get-ADPrincipalGuid -domain $domain -user ($bindUserDn.Split(',')[0]).Split('=')[1] -pass $bindUserPass -principal $group
                            if ($adGroupDetails) {
                                $groupsObject = @()
                                $groupsObject += [pscustomobject]@{
                                    'horizonName' = $adGroupDetails.Name
                                    'dn'          = $adGroupDetails.DistinguishedName
                                    'objectGuid'  = $adGroupDetails.ObjectGuid
                                    'groupBaseDN' = $baseDnGroup
                                    'source'      = "DIRECTORY"
                                }
                                $mappedGroupObject += [pscustomobject]@{
                                    'mappedGroup' = ($groupsObject | Select-Object -Skip 0)
                                    'selected'    = $true
                                }
                            } else {
                                Write-Error "Group $group is not available in Active Directory Domain: PRE_VALIDATION_FAILED"
                            }
                        }
                        $mappedGroupObjectData = @()
                        $mappedGroupObjectData += [pscustomobject]@{
                            'mappedGroupData' = $mappedGroupObject
                            'selected'        = $false
                        }
                        $identityGroupObject = @()
                        $identityGroupObject += [pscustomobject]@{
                            $baseDnGroup = ($mappedGroupObjectData | Select-Object -Skip 0)
                        }
                        $adGroupObject = @()
                        $adGroupObject += [pscustomobject]@{
                            'identityGroupInfo'         = ($identityGroupObject | Select-Object -Skip 0)
                            'excludeNestedGroupMembers' = $false
                        }
                        $adGroupJson = $adGroupObject | ConvertTo-Json -Depth 10
                        Set-WSADirectoryUser -directoryId $directory.directoryConfigId -json $adUserJson | Out-Null
                        Set-WSADirectoryGroup -directoryId $directory.directoryConfigId -json $adGroupJson | Out-Null
                        Set-WSASyncSetting -directoryId $directory.directoryConfigId | Out-Null
                        Start-WSADirectorySync -directoryId $directory.directoryConfigId | Out-Null
                        Write-Output "Creating Active Directory ($($protocol.ToUpper())) Directory in Workspace ONE Access Instance ($server) named ($domain): SUCCESSFUL"
                    } else {
                        Write-Warning "Creating Active Directory ($($protocol.ToUpper())) Directory in Workspace ONE Access Instance ($server) named ($domain), already exists: SKIPPED"
                    }
                } else {
                    Write-Error "Authenticating as Active Directory Domain User ($(($bindUserDn.Split(",")[0]).Split("=")[1])): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-WorkspaceOneDirectory

Function Set-WorkspaceOneNsxtIntegration {
    <#
        .SYNOPSIS
        Integrate NSX Manager with Workspace ONE Access.

        .DESCRIPTION
        The Set-WorkspaceOneNsxtIntegration cmdlet configures integration between NSX Manager and Workspace ONE Access.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Validates that network connectivity and authentication is possible to Workspace ONE Access
        - Creates a service client within Workspace ONE Access
        - Enables the integration between NSX Manager and Workspace ONE Access

        .EXAMPLE
        Set-WorkspaceOneNsxtIntegration -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -wsaFqdn sfo-wsa01.sfo.rainpole.io -wsaUser admin -wsaPass VMw@re1!
        This example integrates the Management Domain NSX Manager instance with Workspace ONE Access.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaUser
        The admin username of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaPass
        The admin password of the Workspace ONE Access Virtual Appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if (Test-WSAConnection -server $wsaFqdn) {
                                    if (Test-WSAAuthentication -server $wsaFqdn -user $wsaUser -pass $wsaPass) {
                                        $clientId = $vcfNsxDetails.fqdn.Split(".")[0] + "-oauth"
                                        $command = 'openssl s_client -connect ' + $wsaFqdn + ':443 2>&1 | openssl x509 -sha256 -fingerprint -noout'
                                        $wsaThumbprint = (Invoke-Expression "& $command").Split("=")[1]
                                        if (!$wsaThumbprint) {
                                            Write-Error "Obtaining SSL Thumbprint for Workspace ONE Access Instance ($wsaFqdn): FAILED"
                                            Break
                                        }
                                        $sharedSecret = (Get-WSAOAuthToken).message
                                        if (!(Get-WSAClient | Where-Object { $_.clientId -eq $clientId })) {
                                            Add-WSAClient -clientId $clientId -sharedSecret $sharedSecret | Out-Null
                                            if (Get-WSAClient | Where-Object { $_.clientId -eq $clientId }) {
                                                Write-Output "Creating Service Client in Workspace ONE Access Instance ($wsaFqdn) named ($clientId): SUCCESSFUL"
                                            } else {
                                                Write-Error "Creating Service Client in Workspace ONE Access Instance ($wsaFqdn) named ($clientId): POST_VALIDATION_FAILED"
                                                Break
                                            }
                                        } else {
                                            Write-Warning "Creating Service Client in Workspace ONE Access Instance ($wsaFqdn) named ($clientId), already exists: SKIPPED"
                                        }
                                        if (Get-NsxtVidm) {
                                            $clientIdSecret = (Get-WSAClient -clientId $clientId).secret
                                            Set-NsxtVidm -wsaHostname $wsaFqdn -thumbprint $wsaThumbprint -clientId $clientId -sharedSecret $clientIdSecret -nsxHostname $vcfNsxDetails.fqdn | Out-Null
                                            Write-Output "Updating integration between NSX Manager ($($vcfNsxDetails.fqdn)) and Workspace ONE Acccess Instance ($wsaFqdn): SUCCESSFUL"
                                        } else {
                                            Set-NsxtVidm -wsaHostname $wsaFqdn -thumbprint $wsaThumbprint -clientId $clientId -sharedSecret $sharedSecret -nsxHostname $vcfNsxDetails.fqdn | Out-Null
                                            Write-Output "Creating integration between NSX Manager ($($vcfNsxDetails.fqdn)) and Workspace ONE Acccess Instance ($wsaFqdn): SUCCESSFUL"
                                        }
                                    }
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-WorkspaceOneNsxtIntegration

Function Undo-WorkspaceOneNsxtIntegration {
    <#
        .SYNOPSIS
        Disables the integrate between NSX Manager with Workspace ONE Access.

        .DESCRIPTION
        The Undo-WorkspaceOneNsxtIntegration cmdlet disables integration between NSX Manager and Workspace ONE Access.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Disables the integration between NSX Manager and Workspace ONE Access

        .EXAMPLE
        Undo-WorkspaceOneNsxtIntegration -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -wsaFqdn sfo-wsa01.sfo.rainpole.io -wsaUser admin -wsaPass VMw@re1!
        This example disables the integration between NSX Manager with Workspace ONE Access.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaUser
        The admin username of the Workspace ONE Access Virtual Appliance.

        .PARAMETER wsaPass
        The admin password of the Workspace ONE Access Virtual Appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if (Test-WSAConnection -server $wsaFqdn) {
                                    if (Test-WSAAuthentication -server $wsaFqdn -user $wsaUser -pass $wsaPass) {
                                        if ((Get-NsxtVidm).vidm_enable -match "True") {
                                            $clientId = $vcfNsxDetails.fqdn.Split(".")[0] + "-oauth"
                                            $command = 'openssl s_client -connect ' + $wsaFqdn + ':443 2>&1 | openssl x509 -sha256 -fingerprint -noout'
                                            $wsaThumbprint = (Invoke-Expression "& $command").Split("=")[1]
                                            if (!$wsaThumbprint) {
                                                Write-Error "Obtaining SSL Thumbprint for Workspace ONE Access Instance ($wsaFqdn): FAILED"
                                                Break
                                            }
                                            $clientIdSecret = (Get-WSAClient -clientId $clientId).secret
                                            Set-NsxtVidm -wsaHostname $wsaFqdn -thumbprint $wsaThumbprint -clientId $clientId -sharedSecret $clientIdSecret -nsxHostname $vcfNsxDetails.fqdn -disable | Out-Null
                                            if ((Get-NsxtVidm).vidm_enable -match "False") {
                                                Write-Output "Disabling integration between NSX Manager ($($vcfNsxDetails.fqdn)) and Workspace ONE Acccess Instance ($wsaFqdn): SUCCESSFUL"
                                            } else {
                                                Write-Error "Disabling integration between NSX Manager ($($vcfNsxDetails.fqdn)) and Workspace ONE Acccess Instance ($wsaFqdn): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Disabling integration between NSX Manager ($($vcfNsxDetails.fqdn)) and Workspace ONE Acccess Instance ($wsaFqdn), already disabled: SKIPPED"
                                        }
                                    }
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-WorkspaceOneNsxtIntegration

Function Add-NsxtVidmRole {
    <#
        .SYNOPSIS
        Configure Role-Based Access Control for NSX Manager.

        .DESCRIPTION
        The Add-NsxtVidmRole cmdlet configures role assignments in NSX Manager. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Assigns Active Directory users or groups to NSX Manager roles based on the -type, -principal, and -role values.

        .EXAMPLE
        Add-NsxtVidmRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -type group -principal "gg-nsx-enterprise-admins@sfo.rainpole.io" -role enterprise_admin
        This example assigns the group gg-nsx-enterprise-admins@sfo.rainpole.io with the enterprise_admin role in NSX Manager

        .EXAMPLE
        Add-NsxtVidmRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -type user -principal "svc-vra-nsx@rainpole.io" -role enterprise_admin
        This example assigns the user svc-vra-nsx@rainpole.io with the enterprise_admin role in NSX Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER type
        The type of principal to assign the role to.

        .PARAMETER principal
        The principal to assign the role to.

        .PARAMETER role
        The role to assign to the principal.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateSet("auditor", "enterprise_admin", "gi_partner_admin", "lb_admin", "lb_auditor", "network_engineer", "network_op", "netx_partner_admin", "security_engineer", "security_op", "vpn_admin")] [string]$role
    )
    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if ((Invoke-Expression "Get-NsxtVidm$type -searchString $principal" | Where-Object { $_.name -eq $principal })) {
                                    if (!(Get-NsxtUser | Where-Object { $_.name -eq $principal })) {
                                        Invoke-Expression "Set-NsxtRole -principal $principal -type remote_$type -role $role -identitySource VIDM | Out-Null"
                                        if (Get-NsxtUser | Where-Object { $_.name -eq $principal }) {
                                            Write-Output "Assigning $type ($principal) the role ($role) in NSX for Workload Domain ($domain): SUCCESSFUL"
                                        } else {
                                            Write-Error "Assigning $type ($principal) the role ($role) in NSX for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Assigning $type ($principal) the role ($role) in NSX for Workload Domain ($domain), already exists: SKIPPED"
                                    }    
                                } else {
                                    Write-Error "Unable to find $type ($principal) in Workspace ONE Access for NSX, check $type synchronization: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NsxtVidmRole

Function Undo-NsxtVidmRole {
    <#
        .SYNOPSIS
        Remove Role-Based Access Control from NSX Manager.

        .DESCRIPTION
        The Undo-NsxtVidmRole cmdlet removes role assignments in NSX Manager. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Removes user or group's from NSX Manager roles based on the -principal

        .EXAMPLE
        Undo-NsxtVidmRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -principal "gg-nsx-enterprise-admins@sfo.rainpole.io"
        This example removes the group gg-nsx-enterprise-admins@sfo.rainpole.io from NSX Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER principal
        The principal to remove the role from.

        .PARAMETER role
        The role to remove from the principal.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if (Get-NsxtUser | Where-Object { $_.name -eq $principal }) {
                                    Remove-NsxtRole -id (Get-NsxtUser | Where-Object { $_.name -eq $principal }).id
                                    if (!(Get-NsxtUser | Where-Object { $_.name -eq $principal })) {
                                        Write-Output "Removing access for ($principal) from NSX for Workload Domain ($domain): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing access for ($principal) from NSX for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing access for ($principal) from NSX for Workload Domain ($domain), already removed: SKIPPED"
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NsxtVidmRole

Function Add-NsxtLdapRole {
    <#
        .SYNOPSIS
        Assign an LDAP user/group with role-based access control in NSX Manager.

        .DESCRIPTION
        The Add-NsxtLdapRole cmdlet asignes role assignments in NSX Manager for LDAP users/groups. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Assigns Active Directory of LDAP users or groups to NSX Manager roles based on the -type, -principal, and -role values.

        .EXAMPLE
        Add-NsxtLdapRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -type group -principal "gg-nsx-enterprise-admins@sfo.rainpole.io" -role enterprise_admin
        This example assigns the LDAP group gg-nsx-enterprise-admins@sfo.rainpole.io with the enterprise_admin role in NSX Manager

        .EXAMPLE
        Add-NsxtLdapRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -type user -principal "svc-vcf-ca@sfo.rainpole.io" -role enterprise_admin
        This example assigns the LDAP user svc-vra-nsx@rainpole.io with the enterprise_admin role in NSX Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER type
        The type of principal to assign the role to.

        .PARAMETER principal
        The principal to assign the role to.

        .PARAMETER role
        The role to assign to the principal.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateSet("auditor", "enterprise_admin", "gi_partner_admin", "lb_admin", "lb_auditor", "network_engineer", "network_op", "netx_partner_admin", "security_engineer", "security_op", "vpn_admin")] [string]$role
    )
    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if (!((Get-NsxtUser | Where-Object {$_.type -eq ("remote_$type")}) -and (Get-NsxtUser | Where-Object {$_.display_name -eq $principal}) -and (Get-NsxtUser | Where-Object {$_.identity_source_type -eq "LDAP"}))) {
                                    $domainFqdn = $principal.Split('@')[-1]
                                    Set-NsxtRole -principal $principal -type remote_$type -role $role -identitySource LDAP -domain $domainFqdn | Out-Null
                                    if ((Get-NsxtUser | Where-Object {$_.type -eq ("remote_$type")}) -and (Get-NsxtUser | Where-Object {$_.display_name -eq $principal}) -and (Get-NsxtUser | Where-Object {$_.identity_source_type -eq "LDAP"})) {
                                        Write-Output "Assigning LDAP $type ($principal) the role ($role) in NSX for Workload Domain ($domain): SUCCESSFUL"
                                        } else {
                                            Write-Error "Assigning LDAP $type ($principal) the role ($role) in NSX for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                        }
                                } else {
                                    Write-Warning "Assigning LDAP $type ($principal) the role ($role) in NSX for Workload Domain ($domain), already exists: SKIPPED"
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NsxtLdapRole

Function Undo-NsxtLdapRole {
    <#
        .SYNOPSIS
        Remove an LDAP user/group role-based access control from NSX Manager.

        .DESCRIPTION
        The Undo-NsxtLdapRole cmdlet removes role assignments in NSX Manager for LDAP users/groups. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes user or group's from NSX Manager roles based on the -principal

        .EXAMPLE
        Undo-NsxtLdapRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -principal "gg-nsx-enterprise-admins@sfo.rainpole.io"
        This example removes the group gg-nsx-enterprise-admins@sfo.rainpole.io from NSX Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER principal
        The principal to remove the role from.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if ((Get-NsxtUser | Where-Object {$_.display_name -eq $principal}) -and (Get-NsxtUser | Where-Object {$_.identity_source_type -eq "LDAP"})) {
                                    Remove-NsxtRole -id (Get-NsxtUser | Where-Object { $_.name -eq $principal }).id | Out-Null
                                    if (!((Get-NsxtUser | Where-Object {$_.display_name -eq $principal}) -and (Get-NsxtUser | Where-Object {$_.identity_source_type -eq "LDAP"}))) {
                                        Write-Output "Removing LDAP access for ($principal) from NSX for Workload Domain ($domain): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing LDAP access for ($principal) from NSX for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing LDAP access for ($principal) from NSX for Workload Domain ($domain), already removed: SKIPPED"
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NsxtLdapRole

Function Add-WorkspaceOneRole {
    <#
        .SYNOPSIS
        Assign Active Directory Groups to Roles in the Workspace ONE Access.

        .DESCRIPTION
        The Add-WorkspaceOneRole cmdlet assigns roles to Active Directory groups provided to manage administrative
        access to the Workspace ONE Access instance. The cmdlet connects to Workspace ONE Access using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to Workspace ONE Access
        - Validates the role exists in Workspace ONE Access
        - Validates the Active Directory group exists in Workspace ONE Access
        - Assigns the role to the Active Directory group

        .EXAMPLE
        Add-WorkspaceOneRole -server sfo-wsa01.sfo.rainpole.io -user admin -pass VMw@re1! -group "gg-wsa-admins" -role "Super Admin"
        This example adds the Active Directory group gg-wsa-admins to the Super Admin role.

        .PARAMETER server
        The FQDN of the Workspace ONE Access Virtual Appliance.

        .PARAMETER user
        The admin username of the Workspace ONE Access Virtual Appliance.

        .PARAMETER pass
        The admin password of the Workspace ONE Access Virtual Appliance.

        .PARAMETER group
        The Active Directory group to assign the role to.

        .PARAMETER role
        The role to assign to the group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$group,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet("Super Admin", "Directory Admin", "ReadOnly Admin")] [String]$role
    )

    Try {
        if (Test-WSAConnection -server $server) {
            if (Test-WSAAuthentication -server $server -user $user -pass $pass) {
                if (Get-WSARoleId -role $role) {
                    if (((Get-WSAActiveDirectoryGroupDetail -group $group).Resources.displayName).Split('@')[0] -eq $group) {
                        if (!(Get-WSARoleAssociation -roleId (Get-WSARoleId -role $role)).groups -contains (Get-WSAActiveDirectoryGroupDetail -group $group).Resources.id) {
                            if ($role -ne "ReadOnly Admin") {
                                Set-WSARoleMember -groupId (Get-WSAActiveDirectoryGroupDetail -group $group).Resources.id -id (Get-WsaRole | Where-Object {$_.displayName -eq "Administrator"}).id | Out-Null
                            }
                            Add-WSARoleAssociation -roleId (Get-WSARoleId -role $role) -groupId (Get-WSAActiveDirectoryGroupDetail -group $group).Resources.id | Out-Null
                            if ((Get-WSARoleAssociation -roleId (Get-WSARoleId -role $role)).groups -eq (Get-WSAActiveDirectoryGroupDetail -group $group).Resources.id) {
                                Write-Output "Assigning group ($group) to role ($role) in Workspace ONE Access Instance ($server): SUCCESSFUL"
                            } else {
                                Write-Error "Assigning group ($group) to role ($role) in Workspace ONE Access Instance ($server): POST_VALIDATION_FAILED"
                            }
                        } else {
                            Write-Warning "Assigning group ($group) to role ($role) in Workspace ONE Access Instance ($server), already exists: SKIPPED"
                        }
                    } else {
                        Write-Error "Unable to find the group ($group) in Workspace ONE Access Instance ($server): PRE_VALIDATION_FAILED"
                    }
                } else {
                    Write-Error "Unable to find role ($role) in Workspace ONE Access Instance ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-WorkspaceOneRole

Function Add-NsxtIdentitySource {
    <#
        .SYNOPSIS
        Add Active Directory over LDAP/LDAPS as an Identity Provider to NSX Manager.

        .DESCRIPTION
        The Add-NsxtIdentitySource cmdlets adds Active Directory over LDAP/LDAPS as an Identity Provider to the NSX
        Managr. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Verifies a connection to the Active Directory Domain Controller using the -domain and -dcMachineName values
        - Adds the Active Directory Domain as an Identity Provider if not already present

        .EXAMPLE
        Add-NsxtIdentitySource -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -dcMachineName sfo-ad01 -baseDn "dc=sfo,dc=rainpole,dc=io" -protocol ldap
        This example adds the sfo.rainpole.io domain as an Identity Provider to NSX Manager using LDAP

        .EXAMPLE
        Add-NsxtIdentitySource -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -dcMachineName sfo-ad01 -baseDN "dc=sfo,dc=rainpole,dc=io" -protocol ldaps -certificate F:\certificates\Root64.cer
        This example adds the sfo.rainpole.io domain as an Identity Provider to NSX Manager using LDAPS.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the Management Domain.

        .PARAMETER domain
        The name of the Active Directory Domain.

        .PARAMETER domainBindUser
        The username of the Active Directory Domain Bind User.

        .PARAMETER domainBindPass
        The password of the Active Directory Domain Bind User.

        .PARAMETER dcMachineName
        The name of the Active Directory Domain Controller.

        .PARAMETER baseDn
        The base DN of the Active Directory Domain.

        .PARAMETER protocol
        The protocol to use for the connection to the Active Directory Domain Controller.

        .PARAMETER certificate
        The certificate to use for the connection to the Active Directory Domain Controller.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$dcMachineName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDn,
        [Parameter (Mandatory = $true)] [ValidateSet("ldap", "ldaps")] [String]$protocol,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificate
    )

    if (!$PsBoundParameters.ContainsKey("certificate") -and ($protocol -eq "ldaps")) {
        $certificate = Get-ExternalFileName -title "Select the Root CA Certificate File (.cer)" -fileType "cer" -location "default"
    } elseif ($protocol -eq "ldaps") {
        if (!(Test-Path -Path $certificate)) {
            Write-Error  "Certificate (cer) for Root Certificate Authority '$certificate' File Not Found"
            Break
        }
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $sddcDomain)) {
                    if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                            if (!(Get-NsxtLdap | Where-Object { $_.domain_name -eq $domain })) {
                                if (Test-Connection -ComputerName ($dcMachineName + "." + $domain) -Quiet -Count 1) {
                                    if ($protocol -eq "ldaps") {
                                        New-NsxtLdap -dcMachineName $dcMachineName -protocol LDAPS -startTtls false -domain $domain -baseDn $baseDn -bindUser ($domainBindUser + "@" + $domain ) -bindPassword $domainBindPass -certificate $certificate | Out-Null
                                    } else {
                                        New-NsxtLdap -dcMachineName $dcMachineName -protocol LDAP -startTtls false -domain $domain -baseDn $baseDn -bindUser ($domainBindUser + "@" + $domain ) -bindPassword $domainBindPass | Out-Null
                                    }
                                    if (Get-NsxtLdap | Where-Object { $_.domain_name -eq $domain }) {
                                        if ((Get-NsxtLdapStatus -id $domain).result -ne "FAILURE") {
                                            Write-Output "Adding Identity Source to NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Identity Source to NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain) error ($((Get-NsxtLdapStatus -id $domain).errors.error_type)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Adding Identity Source to NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to communicate with Active Directory Domain Controller ($dcMachineName), check details: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding Identity Source to NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NsxtIdentitySource

Function Undo-NsxtIdentitySource {
    <#
        .SYNOPSIS
        Remove Active Directory over LDAP/LDAPS as an Identity Provider from NSX Manager.

        .DESCRIPTION
        The Undo-NsxtIdentitySource cmdlets removes Active Directory over LDAP/LDAPS as an Identity Provider from NSX
        Managr. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes the Active Directory Domain as an Identity Provider if present

        .EXAMPLE
        Undo-NsxtIdentitySource -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-w01 -domain sfo.rainpole.io
        This example removes the sfo.rainpole.io domain as an Identity Provider from NSX Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the Management Domain.

        .PARAMETER domain
        The name of the Active Directory Domain.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $sddcDomain)) {
                    if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                            if (Get-NsxtLdap | Where-Object { $_.domain_name -eq $domain }) {
                                Remove-NsxtLdap -id (Get-NsxtLdap | Where-Object { $_.domain_name -eq $domain }).id | Out-Null
                                if (!(Get-NsxtLdap | Where-Object { $_.domain_name -eq $domain })) {
                                    Write-Output "Removing Identity Source from NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing Identity Source from NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing Identity Source from NSX Manager ($($vcfNsxDetails.fqdn)) named ($domain), already removed: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NsxtIdentitySource



#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region S I T E P R O T E C T I O N & D I S A S T E R R E C O V E R Y F U N C T I O N S ###########

Function Install-SiteRecoveryManager {
    <#
        .SYNOPSIS
        Deploy Site Recovery Manager Virtual Appliance.

        .DESCRIPTION
        The Install-SiteRecoveryManager cmdlet deploys the Site Recovery Manager Virtual Appliance OVA. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values to retrive the management domain
        vCenter Server details from its inventory and then:
        - Gathers vSphere configuration from vCenter Server
        - Gathers DNS and NTP configuration from SDDC Manager
        - Deploys the Site Recovery Manage Virtual Appliance

        .EXAMPLE
        Install-SiteRecoveryManager -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -srmFqdn sfo-wsa01.sfo.rainpole.io -srmIpAddress 192.168.31.60 -srmGateway 192.168.31.1 -srmNetPrefix 255.255.255.0 -srmNetworkSearchPath sfo.rainpole.io -srmFolder sfo-m01-fd-srm -srmVaRootPassword VMw@re1! -srmVaAdminPassword VMw@re1! -srmDbPassword VMw@re1! -deploymentOption standard -srmOvfPath F:\identity-manager.ova
        This example deploys the Site Recovery Manager Virtual Appliance into the sfo-m01-fd-srm folder of the management domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The SSO Administrator username
        
        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER srmFqdn
        The FQDN of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmIpAddress
        The IP Address of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmGateway
        The Gateway of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmNetPrefix
        The Netmask of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmNetworkSearchPath
        The DNS Search Path of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmFolder
        The folder to deploy the Site Recovery Manager Virtual Appliance into.

        .PARAMETER srmVaRootPassword
        The root password of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmVaAdminPassword
        The admin password of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmDbPassword
        The database password of the Site Recovery Manager Virtual Appliance.

        .PARAMETER srmOvfPath
        The path to the Site Recovery Manager Virtual Appliance OVA file.

        .PARAMETER deploymentOption
        The deployment option to use for the Site Recovery Manager Virtual Appliance.

        .PARAMETER vmwareOvfToolPath
        The path to the VMware OVF Tool executable.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmIpAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmGateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmNetPrefix,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmNetworkSearchPath,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmFolder,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmVaRootPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmVaAdminPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmDbPassword,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$srmOvfPath,
        [Parameter (Mandatory = $false)] [ValidateSet("Standard", "Large")] [String]$deploymentOption,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmwareOvfToolPath='C:\Program Files\VMware\VMware OVF Tool\ovftool.exe'
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("srmOvfPath")) {
            $srmOvfPath = Get-ExternalFileName -title "Select the Site Recovery Manager OVF file (.ovf)" -fileType "ovf"
        } else {
            if (!(Test-Path -Path $srmOvfPath)) {
                Write-Error  "Site Recovery Manager OVA ($srmOvfPath) File Not Found"
                Break
            }
        }
        if (!(Test-Path -Path $vmwareOvfToolPath)) {
            Write-Error  "VMware OVF Tool ($vmwareOvfToolPath) Not Found, Run again with parameter -vmwareOvfToolPath <path to exe file>"
            Break
        }
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $srmHostname = $srmFqdn.Split(".")[0]
                            $srmDomain = $srmFQDN.Substring($srmFQDN.IndexOf(".") + 1)
                            if (Get-VM -Name $srmHostname -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore) {
                                Write-Warning "Deploying a virtual machine in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($srmHostname), already exists: SKIPPED"
                            } else {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                $datastore = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).primaryDatastoreName
                                $datacenter = (Get-Datacenter -Cluster $cluster).Name
                                if (((Get-VCFConfigurationDNS).ipAddress).Count -gt 1) {
                                    $dnsServer = (Get-VCFConfigurationDNS).ipAddress[0] + "," + (Get-VCFConfigurationDNS).ipAddress[1]
                                } else { 
                                    $dnsServer = (Get-VCFConfigurationDNS).ipAddress
                                }
                                if (((Get-VCFConfigurationNTP).ipAddress).Count -gt 1) {
                                    $ntpServer = (Get-VCFConfigurationNTP).ipAddress[0] + "," + (Get-VCFConfigurationNTP).ipAddress[1]
                                } else { 
                                    $ntpServer = (Get-VCFConfigurationNTP).ipAddress
                                }
                                $mgmtPortgroup = ((Get-VMHost)[0] | Get-VMHostNetwork | Select-Object Hostname, VMkernelGateway -ExpandProperty VirtualNic | Where-Object {$_.DeviceName -eq "vmk0"}).PortGroupName
                                $netMode = "static"
                                $command = '"' + $vmwareOvfToolPath + '" --noSSLVerify --acceptAllEulas --allowAllExtraConfig --diskMode=thin --powerOn --name=' + $srmHostname + ' --ipProtocol="IPv4" --ipAllocationPolicy="fixedAllocatedPolicy" --vmFolder=' + $srmFolder + ' --net:"Network 1"=' + $mgmtPortgroup + ' --datastore=' + $datastore + ' --deploymentOption=' + $deploymentOption + ' --prop:varoot-password=' + $srmVaRootPassword + ' --prop:vaadmin-password=' + $srmVaAdminPassword +' --prop:dbpassword=' + $srmDbPassword + ' --prop:network.netmode.VMware_Site_Recovery_Manager_Appliance=' + $netMode + ' --prop:network.ip0.VMware_Site_Recovery_Manager_Appliance=' + $srmIpAddress + ' --prop:network.netprefix0.VMware_Site_Recovery_Manager_Appliance=' + $srmNetPrefix + ' --prop:vami.hostname=' + $srmFqdn + ' --prop:network.domain.VMware_Site_Recovery_Manager_Appliance=' + $srmDomain + ' --prop:network.searchpath.VMware_Site_Recovery_Manager_Appliance=' + $srmNetworkSearchPath + ' --prop:ntpserver=' + $ntpServer +' --prop:network.gateway.VMware_Site_Recovery_Manager_Appliance=' + $srmGateway + ' --prop:network.DNS.VMware_Site_Recovery_Manager_Appliance=' + $dnsServer + ' --prop:enableFileIntegrity= ' + $enableFileIntegrity +' ' + $srmOvfPath + ' "vi://' + $vcfVcenterDetails.ssoAdmin + ':' + $vcfVcenterDetails.ssoAdminPass + '@' + $vcfVcenterDetails.fqdn + '/' + $datacenter + '/host/' + $cluster + '/"'
                                Invoke-Expression -Command "& $command" -ErrorAction Ignore
                                (Get-VM -Name $srmHostname -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore)
                                $Timeout = 900  ## seconds
                                $CheckEvery = 15  ## seconds
                                Try {
                                    $timer = [Diagnostics.Stopwatch]::StartNew()  ## Start the timer
                                    Write-Output "Waiting for Site Recovery Manager Instance ($srmFqdn) using IP Address ($srmIpAddress) to Become Pingable."
                                    While (!(Test-NetConnection $srmIpAddress -Port 5480 -WarningAction silentlyContinue | Where-Object { $_.TcpTestSucceeded -eq $True })) {
                                        ## If the timer has waited greater than or equal to the timeout, throw an exception exiting the loop
                                        if ($timer.Elapsed.TotalSeconds -ge $Timeout) {
                                            Write-Error "Site Recovery Manager Instance ($srmFqdn) failed to initialize properly. Please delete the VM from vCenter Server ($($vcfVcenterDetails.fqdn)) and retry: POST_VAIDATION_FAILED"
                                        }
                                        Start-Sleep -Seconds $CheckEvery  ## Stop the loop every $CheckEvery seconds
                                    }
                                } Catch {
                                    Write-Error "Failed to get a Response from Site Recovery Manager Instance ($srmFqdn): POST_VALIDATION_FAILURE"
                                } Finally {
                                    $timer.Stop()  ## Stop the timer
                                    Do {
                                        $vamiStatus = Test-SrmVamiAuthentication -server $srmFqdn -user admin -pass $srmVaAdminPassword -ErrorAction SilentlyContinue
                                    } Until (($vamiStatus -eq $true))
                                    Write-Output "Deploying a virtual machine in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($srmHostname): SUCCESSFUL"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-SiteRecoveryManager

Function Undo-SiteRecoveryManager {
    <#
        .SYNOPSIS
        Remove vSphere Replication Virtual Appliance.

        .DESCRIPTION
        The Undo-SiteRecoveryManager cmdlet removes the vSphere Replication Virtual Appliance. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes the vSphere Replication Virtual Appliance from vCenter Server

        .EXAMPLE
        Undo-SiteRecoveryManager -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -srmHostname sfo-m01-srm01
        This example removes the vSphere Replication Virtual Appliance named sfo-m01-vrms01 from the Management Domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER srmHostname
        The hostname of the vSphere Replication Virtual Appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmHostname
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VM -Name $srmHostname -ErrorAction Ignore) {
                                if ((Get-VM -Name $srmHostname).PowerState -ne "PoweredOff") {
                                    Stop-VM -VM $srmHostname -Kill -Confirm:$false | Out-Null
                                    if ((Get-VM -Name $srmHostname).PowerState -ne "PoweredOff") {
                                        Write-Error "Unable to Power Off virtual machine ($srmHostname): PRE_VALIDATION_FAILED"
                                        Break
                                    }
                                }
                                Remove-VM $srmHostname -DeletePermanently -Confirm:$false | Out-null
                                if (!(Get-VM -Name $srmHostname -ErrorAction Ignore)) {
                                    Write-Output "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($srmHostname): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($srmHostname): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($srmHostname), already removed: SKIPPED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SiteRecoveryManager

Function Install-vSphereReplicationManager {
    <#
        .SYNOPSIS
        Deploy vSphere Replication Manager Virtual Appliance.

        .DESCRIPTION
        The Install-vSphereReplicationManager cmdlet deploys the vSphere Replication Manager Virtual Appliance OVA.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values to retrive the management domain
        vCenter Server details from its inventory and then:
        - Gathers vSphere configuration from vCenter Server
        - Gathers DNS and NTP configuration from SDDC Manager
        - Deploys the vSphere Replication Manager Virtual Appliance

        .EXAMPLE
        Install-vSphereReplicationManager -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -vrmsFqdn sfo-m01-vrms01.sfo.rainpole.io -vrmsIpAddress 192.168.31.60 -vrmsGateway 192.168.31.1 -vrmsNetPrefix 255.255.255.0 -vrmsNetworkSearchPath sfo.rainpole.io -vrmsFolder sfo-m01-fd-vrms -vrmsVaRootPassword VMw@re1! -vrmsVaAdminPassword VMw@re1! -vrmsOvfPath F:\vrms.ova
        This example deploys the vSphere Replication Manager Virtual Appliance into the sfo-m01-fd-vrms folder of the management domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER vrmsFqdn
        The FQDN of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsIpAddress
        The IP Address of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsGateway
        The Gateway of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsNetPrefix
        The Netmask of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsNetworkSearchPath
        The DNS Search Path of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsFolder
        The folder to deploy the vSphere Replication Manager Virtual Appliance into.

        .PARAMETER vrmsVaRootPassword
        The root password of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsVaAdminPassword
        The admin password of the vSphere Replication Manager Virtual Appliance.

        .PARAMETER vrmsOvfPath
        The path to the vSphere Replication Manager Virtual Appliance OVA file.

        .PARAMETER vmwareOvfToolPath
        The path to the VMware OVF Tool executable.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsIpAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsGateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsNetPrefix,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsNetworkSearchPath,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsFolder,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsVaRootPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsVaAdminPassword,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vrmsOvfPath,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmwareOvfToolPath='C:\Program Files\VMware\VMware OVF Tool\ovftool.exe'
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("vrmsOvfPath")) {
            $vrmsOvfPath = Get-ExternalFileName -title "Select the vSphere Replication Manager OVF file (.ovf)" -fileType "ovf"
        } else {
            if (!(Test-Path -Path $vrmsOvfPath)) {
                Write-Error  "vSphere Replication Manager OVA '$vrmsOvfPath' File Not Found"
                Break
            }
        }
        if (!(Test-Path -Path $vmwareOvfToolPath)) {
            Write-Error  "VMware OVF Tool ($vmwareOvfToolPath) Not Found, Run again with parameter -vmwareOvfToolPath <path to exe file>"
            Break
        }
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrmsHostname = $vrmsFqdn.Split(".")[0]
                            $vrmsDomain = $vrmsFQDN.Substring($vrmsFQDN.IndexOf(".") + 1)
                            if (Get-VM -Name $vrmsHostname -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore) {
                                Write-Warning "Deploying a virtual machine in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($vrmsHostname), already exists: SKIPPED"
                            } else {
                                # $dnsServer1 = (Get-VCFConfigurationDNS | Where-Object { $_.isPrimary -Match "True" }).ipAddress
                                # $dnsServer2 = (Get-VCFConfigurationDNS | Where-Object { $_.isPrimary -Match "False" }).ipAddress
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                $datastore = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).primaryDatastoreName
                                $datacenter = (Get-Datacenter -Cluster $cluster).Name
                                if (((Get-VCFConfigurationDNS).ipAddress).Count -gt 1) {
                                    $dnsServer = (Get-VCFConfigurationDNS).ipAddress[0] + "," + (Get-VCFConfigurationDNS).ipAddress[1]
                                } else { 
                                    $dnsServer = (Get-VCFConfigurationDNS).ipAddress
                                }
                                if (((Get-VCFConfigurationNTP).ipAddress).Count -gt 1) {
                                    $ntpServer = (Get-VCFConfigurationNTP).ipAddress[0] + "," + (Get-VCFConfigurationNTP).ipAddress[1]
                                } else { 
                                    $ntpServer = (Get-VCFConfigurationNTP).ipAddress
                                }
                                $mgmtPortgroup = ((Get-VMHost)[0] | Get-VMHostNetwork | Select-Object Hostname, VMkernelGateway -ExpandProperty VirtualNic | where-object {$_.DeviceName -eq "vmk0"}).PortGroupName
                                $netMode = "static"
                                $command = '"' + $vmwareOvfToolPath + '" --noSSLVerify --acceptAllEulas --allowAllExtraConfig --diskMode=thin --powerOn --name=' + $vrmsHostname + ' --ipProtocol="IPv4" --ipAllocationPolicy="fixedAllocatedPolicy" --vmFolder=' + $vrmsFolder + ' --net:"Network 1"=' + $mgmtPortgroup + ' --datastore=' + $datastore + ' --prop:varoot-password=' + $vrmsVaRootPassword + ' --prop:vaadmin-password=' + $vrmsVaAdminPassword +' --prop:network.netmode.vSphere_Replication_Appliance=' + $netMode + ' --prop:network.ip0.vSphere_Replication_Appliance=' + $vrmsIpAddress + ' --prop:network.netprefix0.vSphere_Replication_Appliance=' + $vrmsNetPrefix + ' --prop:vami.hostname=' + $vrmsFqdn + ' --prop:network.domain.vSphere_Replication_Appliance=' + $vrmsDomain + ' --prop:network.searchpath.vSphere_Replication_Appliance=' + $vrmsNetworkSearchPath + ' --prop:ntpserver=' + $ntpServer +' --prop:network.gateway.vSphere_Replication_Appliance=' + $vrmsGateway + ' --prop:network.DNS.vSphere_Replication_Appliance=' + $dnsServer + ' --prop:enableFileIntegrity= ' + $enableFileIntegrity +' --vService:installation=com.vmware.vim.vsm:extension_vservice ' + $vrmsOvfPath + ' "vi://' + $vcfVcenterDetails.ssoAdmin + ':' + $vcfVcenterDetails.ssoAdminPass + '@' + $vcfVcenterDetails.fqdn + '/' + $datacenter + '/host/' + $cluster + '/"'
                                Invoke-Expression -Command "& $command"
                                if (Get-VM -Name $vrmsHostname -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore) {
                                    $Timeout = 900  ## seconds
                                    $CheckEvery = 15  ## seconds
                                    Try {
                                        $timer = [Diagnostics.Stopwatch]::StartNew()  ## Start the timer
                                        Write-Output "Waiting for vSphere Replication Instance ($vrmsFQDN) using IP Address ($vrmsIpAddress) to Become Pingable."
                                        While (!(Test-NetConnection $vrmsIpAddress -Port 5480 -WarningAction silentlyContinue | Where-Object { $_.TcpTestSucceeded -eq $True })) {
                                            ## If the timer has waited greater than or equal to the timeout, throw an exception exiting the loop
                                            if ($timer.Elapsed.TotalSeconds -ge $Timeout) {
                                                Throw "Timeout Exceeded. Giving up on ping availability to $vrmsIpAddress"
                                            }
                                            Start-Sleep -Seconds $CheckEvery  ## Stop the loop every $CheckEvery seconds
                                        }
                                    } Catch {
                                        Write-Error "Failed to get a Response from vSphere Replication Instance ($vrmsFQDN): POST_VALIDATION_FAILURE"
                                    } Finally {
                                        $timer.Stop()  ## Stop the timer
                                        Write-Output "Deploying a virtual machine in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($vrmsHostname): SUCCESSFUL"
                                    }       
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-vSphereReplicationManager

Function Undo-vSphereReplicationManager {
    <#
        .SYNOPSIS
        Remove vSphere Replication Virtual Appliance.

        .DESCRIPTION
        The Undo-vSphereReplicationManager cmdlet removes the vSphere Replication Virtual Appliance. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes the vSphere Replication Virtual Appliance from vCenter Server

        .EXAMPLE
        Undo-vSphereReplicationManager -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -vrmsHostname sfo-m01-vrms01
        This example removes the vSphere Replication Virtual Appliance named sfo-m01-vrms01 from the Management Domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER vrmsHostname
        The hostname of the vSphere Replication Virtual Appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsHostname
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VM -Name $vrmsHostname -ErrorAction Ignore) {
                                if ((Get-VM -Name $vrmsHostname).PowerState -ne "PoweredOff") {
                                    Stop-VM -VM $vrmsHostname -Kill -Confirm:$false | Out-Null
                                    if ((Get-VM -Name $vrmsHostname).PowerState -ne "PoweredOff") {
                                        Write-Error "Unable to Power Off virtual machine ($vrmsHostname): PRE_VALIDATION_FAILED"
                                        Break
                                    }
                                }
                                Remove-VM $vrmsHostname -DeletePermanently -Confirm:$false | Out-null
                                if (!(Get-VM -Name $vrmsHostname -ErrorAction Ignore)) {
                                    Write-Output "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($vrmsHostname): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($vrmsHostname): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing virtual machine from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($vrmsHostname), already removed: SKIPPED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vSphereReplicationManager

Function Connect-DRSolutionTovCenter {
    <#
        .SYNOPSIS
        Register Site Recovery Manager or vSphere Replication with vCenter Server.

        .DESCRIPTION
        The Connect-DRSolutionTovCenter cmdlet registers Site Recovery Manager or vSphere Replication with a vCenter
        Server. The cmdlet connects to SDDC Manager using the -server, -user, and -password:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Validates that network connectivity and authentication is possible to the vSphere Replication or Site
        Recovery Manaeger instance
        - Validates if the solution has already been registerd and if not proceeds with the registration

        .EXAMPLE
        Connect-DRSolutionTovCenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -applianceFqdn sfo-m01-srm01.sfo.rainpole.io -vamiAdminPassword VMw@re1! -siteName SFO-M01 -adminEmail "srm-administrator@rainpole.io" -solution SRM
        This example registers Site Recovery Manager with the vCenter Server of the Management Domain

        .EXAMPLE
        Connect-DRSolutionTovCenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -applianceFqdn sfo-m01-vrms01.sfo.rainpole.io -vamiAdminPassword VMw@re1! -siteName SFO-M01 -adminEmail "vrms-administrator@rainpole.io" -solution VRMS
        This example registers Site Recovery Manager with the vCenter Server of the Management Domain .

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER applianceFqdn
        The FQDN of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER vamiAdminPassword
        The admin password of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER siteName
        The name of the Site.

        .PARAMETER adminEmail
        The email address of the Site Administrator.

        .PARAMETER solution
        The solution to register with the vCenter Server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$applianceFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vamiAdminPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$siteName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adminEmail,
        [Parameter (Mandatory = $true)] [ValidateSet("SRM", "VRMS")] [String]$solution
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($solution -eq "VRMS") {
                                if (Test-VrmsVamiConnection -server $applianceFqdn) {
                                    if (Test-VrmsVamiAuthentication -server $applianceFqdn -user admin -pass $vamiAdminPassword) {
                                        if (!((Get-VrmsConfiguration -ErrorAction SilentlyContinue).connection.vc_instance_id -eq ($global:DefaultVIServer.InstanceUuid))) {
                                            $configTask = Set-VrmsConfiguration -vcenterFqdn $vcfVcenterDetails.fqdn -vcenterInstanceId ($global:DefaultVIServer.InstanceUuid) -ssoUser $vcfVcenterDetails.ssoAdmin -ssoPassword $vcfVcenterDetails.ssoAdminPass -adminEmail $adminEmail -siteName $siteName
                                            $counter = 0
                                            Do {
                                                Try {
                                                    $vamiStatus = Test-VrmsVamiAuthentication -server $applianceFqdn -user admin -pass $vamiAdminPassword -ErrorAction SilentlyContinue
                                                    $taskStatus = Get-VrmsTask -taskId $configTask.id -ErrorAction SilentlyContinue
                                                } Catch {
                                                    Write-Output "Pausing for 30 seconds to allow the $solution instance ($applianceFqdn) to initialize, please wait..."
                                                    Start-Sleep -Seconds 30
                                                    $counter++
                                                    # If the counter reaches 20, then the task has been running for 10 minutes will be considered as failed.
                                                    if ($counter -eq 20) {
                                                        Write-Error "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): FAILED"
                                                        Break
                                                    }
                                                }
                                            } Until (($taskStatus.Status -ne "RUNNING") -and ($vamiStatus -eq $true))
                                            if ($taskStatus.Status -eq "SUCCESS") {
                                                Write-Output "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)), already registered: SKIPPED"
                                        }
                                    }
                                }
                            } elseif ($solution -eq "SRM") {
                                if (Test-SrmVamiConnection -server $applianceFqdn) {
                                    if (Test-SrmVamiAuthentication -server $applianceFqdn -user admin -pass $vamiAdminPassword) {
                                        if (!((Get-SrmConfiguration -ErrorAction SilentlyContinue).connection.vc_instance_id -eq ($global:DefaultVIServer.InstanceUuid))) {
                                            $configTask = Set-SrmConfiguration -vcenterFqdn $vcfVcenterDetails.fqdn -vcenterInstanceId ($global:DefaultVIServer.InstanceUuid) -ssoUser $vcfVcenterDetails.ssoAdmin -ssoPassword $vcfVcenterDetails.ssoAdminPass -adminEmail $adminEmail -siteName $siteName
                                            $counter = 0
                                            Do {
                                                Try {
                                                    $vamiStatus = Test-VrmsVamiAuthentication -server $applianceFqdn -user admin -pass $vamiAdminPassword -ErrorAction SilentlyContinue
                                                    $taskStatus = Get-VrmsTask -taskId $configTask.id -ErrorAction SilentlyContinue
                                                } Catch {
                                                    Write-Output "Pausing for 30 seconds to allow the $solution instance ($applianceFqdn) to initialize, please wait..."
                                                    Start-Sleep -Seconds 30
                                                    $counter++
                                                    # If the counter reaches 20, then the task has been running for 10 minutes will be considered as failed.
                                                    if ($counter -eq 20) {
                                                        Write-Error "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): FAILED"
                                                        Break
                                                    }
                                                }
                                            } Until (($taskStatus.Status -ne "RUNNING") -and ($vamiStatus -eq $true))
                                            if ($taskStatus.Status -eq "SUCCESS") {
                                                Write-Output "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Registering $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)), already registered: SKIPPED"
                                        }
                                    }
                                }
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Connect-DRSolutionTovCenter

Function Undo-DRSolutionTovCenter {
    <#
        .SYNOPSIS
        Remove registration of Site Recovery Manager or vSphere Replication with vCenter Server.

        .DESCRIPTION
        The Undo-DRSolutionTovCenter cmdlet removes registration of Site Recovery Manager or vSphere Replication with
        a vCenter Server. The cmdlet connects to SDDC Manager using the -server, -user, and -password:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Validates that network connectivity and authentication is possible to the vSphere Replication or Site
        Recovery Manaeger instance
        - Validates if the solution is registerd and if so proceeds to unregister

        .EXAMPLE
        Undo-DRSolutionTovCenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -applianceFqdn sfo-m01-srm01.sfo.rainpole.io -vamiAdminPassword VMw@re1! -solution SRM
        This example registers Site Recovery Manager with the vCenter Server of the Management Domain

        .EXAMPLE
        Undo-DRSolutionTovCenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -applianceFqdn sfo-m01-vrms01.sfo.rainpole.io -vamiAdminPassword VMw@re1! -solution VRMS
        This example registers Site Recovery Manager with the vCenter Server of the Management Domain .

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER applianceFqdn
        The FQDN of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER vamiAdminPassword
        The admin password of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER solution
        The solution to register with the vCenter Server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$applianceFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vamiAdminPassword,
        [Parameter (Mandatory = $true)] [ValidateSet("SRM", "VRMS")] [String]$solution
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($solution -eq "VRMS") {
                                if (Test-VrmsVamiConnection -server $applianceFqdn) {
                                    if (Test-VrmsVamiAuthentication -server $applianceFqdn -user admin -pass $vamiAdminPassword) {
                                        if ((Get-VrmsConfiguration -ErrorAction SilentlyContinue).connection.vc_instance_id -eq ($global:DefaultVIServer.InstanceUuid)) {
                                            Remove-VrmsConfiguration -ssoUser $vcfVcenterDetails.ssoAdmin -ssoPassword $vcfVcenterDetails.ssoAdminPass | Out-Null
                                            if (!((Get-VrmsConfiguration -ErrorAction SilentlyContinue).connection.vc_instance_id -eq ($global:DefaultVIServer.InstanceUuid))) {
                                                Write-Output "Removing registration for $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removing registration for $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Removing registration for $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)), not registered: SKIPPED"
                                        }
                                    }
                                }
                            } elseif ($solution -eq "SRM") {
                                if (Test-SrmVamiConnection -server $applianceFqdn) {
                                    if (Test-SrmVamiAuthentication -server $applianceFqdn -user admin -pass $vamiAdminPassword) {
                                        if ((Get-SrmConfiguration -ErrorAction SilentlyContinue).connection.vc_instance_id -eq ($global:DefaultVIServer.InstanceUuid)) {
                                            Remove-SrmConfiguration -ssoUser $vcfVcenterDetails.ssoAdmin -ssoPassword $vcfVcenterDetails.ssoAdminPass | Out-Null
                                            if (!((Get-SrmConfiguration -ErrorAction SilentlyContinue).connection.vc_instance_id -eq ($global:DefaultVIServer.InstanceUuid))) {
                                                Write-Output "Removing registration for $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removing registration for $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Removing registration for $solution instance ($applianceFqdn) with vCenter Server ($($vcfVcenterDetails.fqdn)), not registered: SKIPPED"
                                        }
                                    }
                                }
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-DRSolutionTovCenter

Function Install-VamiCertificate {
    <#
        .SYNOPSIS
        Install a new certificate for a VAMI interface.

        .DESCRIPTION
        The Install-VamiCertificate cmdlet allows you to replace the certificate of a VAMI interface. Supports:
        - vSphere Replication appliance
        - Site Recovery Manager appliance

        .EXAMPLE
        Install-VamiCertificate -server sfo-m01-vrms01.sfo.rainpole.io -user admin -pass VMw@re1! -certFile C:\Certs\sfo-m01-vrms01.4.p12 -certPassword VMw@re1! -solution VRMS
        This example replaces the certificate for the VAMI interface of the vSphere Replication
        
        .EXAMPLE
        Install-VamiCertificate -server sfo-m01-srm01.sfo.rainpole.io -user admin -pass VMw@re1! -certFile C:\Certs\sfo-m01-vrms01.4.p12 -certPassword VMw@re1! -solution SRM
        This example replaces the certificate for the VAMI interface of the Site Recovery Manager appliance.

        .PARAMETER server
        The FQDN of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER user
        The admin username of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER pass
        The admin password of the vSphere Replication or Site Recovery Manager Virtual Appliance.

        .PARAMETER certFile
        The path to the certificate file (.p12).

        .PARAMETER certPassword
        The password of the certificate file (.p12).

        .PARAMETER solution
        The solution to register with the vCenter Server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certPassword,
        [Parameter (Mandatory = $true)] [ValidateSet("SRM", "VRMS")] [String]$solution
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("certFile")) {
            $certFile = Get-ExternalFileName -title "Select the Appliance Certificate File (.p12)" -fileType "p12"
        } elseif ($PsBoundParameters.ContainsKey("certFile")) {
            if (!(Test-Path -Path $certFile)) {
                Write-Error  "Certificate (.p12) '$certFile' File Not Found"
            }
        }
        
        if ($solution -eq "VRMS") {
            if (Test-VrmsVamiConnection -server $server) {
                if (Test-VrmsVamiAuthentication -server $server -user $user -pass $pass) {
                    Set-VrmsVamiCertificate -pkcs12CertFile $certFile -certPassword $certPassword | Out-Null
                    Write-Output "Installing Signed Certifcate on vSphere Replication Appliance ($server) using ($certFile): SUCCESSFUL"
                }
            
            }
        } elseif ($solution -eq "SRM") {
            if (Test-SrmVamiConnection -server $server) {
                if (Test-SrmVamiAuthentication -server $server -user $user -pass $pass) {
                    Set-SrmVamiCertificate -pkcs12CertFile $certFile -certPassword $certPassword | Out-Null
                    Write-Output "Installing Signed Certifcate on Site Recovery Manager Appliance ($server) using ($certFile): SUCCESSFUL"
                }
            
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-VamiCertificate

Function Add-VrmsNetworkAdapter {
    <#
        .SYNOPSIS
        Adds a second ethernet adapter and configures the required routing for vSphere Replication appliance.

        .DESCRIPTION
        The Add-VrmsNetworkAdapter cmdlet adds a second ethernet adapter and configures the required routing for the
        vSphere Replication appliance. The cmdlet connects to SDDC Manager using the -server, -user, and -password
        values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Validates that network connectivity and authentication is possible to the vSphere Replication instance
        - Configures the secondary ethernet adapter and configures the required routing for the replication network

        .EXAMPLE
        Add-VrmsNetworkAdapter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -vrmsFqdn sfo-m01-vrms01.sfo.rainpole.io -vrmsRootPass VMw@re1! -vrmsAdminPass VMw@re1! -vrmsIpAddress 172.18.95.125 -replicationSubnet 172.18.111.0/24 -replicationIpAddress 172.18.111.125 -replicationGateway 172.18.111.1 -replicationPortgroup sfo-m01-cl01-vds01-pg-vrms -replicationRemoteNetwork 172.18.96.0/24
        This example configures the protected and recovery site vSphere Replication appliances to use a secondary ethernet adapter for vSphere Replication traffic.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the Management Domain.

        .PARAMETER vrmsFqdn
        The FQDN of the vSphere Replication Virtual Appliance.

        .PARAMETER vrmsRootPass
        The root password of the vSphere Replication Virtual Appliance.

        .PARAMETER vrmsAdminPass
        The admin password of the vSphere Replication Virtual Appliance.

        .PARAMETER vrmsIpAddress
        The IP Address of the vSphere Replication Virtual Appliance.

        .PARAMETER replicationSubnet
        The subnet of the vSphere Replication network.

        .PARAMETER replicationIpAddress
        The IP Address of the vSphere Replication Virtual Appliance on the vSphere Replication network.

        .PARAMETER replicationGateway
        The gateway of the vSphere Replication network.

        .PARAMETER replicationPortgroup
        The name of the vSphere Distributed Port Group for the vSphere Replication network.

        .PARAMETER replicationRemoteNetwork
        The subnet of the remote vSphere Replication network.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsRootPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsAdminPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsIpAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$replicationSubnet,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$replicationIpAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$replicationGateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$replicationPortgroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$replicationRemoteNetwork
    )

    Try {

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrmsVmName = $vrmsFqdn.Split(".")[0]
                            if (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {$_.Name -eq $replicationPortgroup}) {
                                if (Test-VrmsVamiAuthentication -server $vrmsFqdn -user admin -pass $vrmsAdminPass) {
                                    if (((Get-VM -Name $vrmsVmName -Server $vcfVcenterDetails.fqdn | Get-NetworkAdapter).Count) -le 1) {
                                        # Add the second NIC to the vSphere Replication appliance and Restart
                                        Get-VM -Name $vrmsVmName -Server $vcfVcenterDetails.fqdn | New-NetworkAdapter -Server $vcfVcenterDetails.fqdn -NetworkName $replicationPortgroup -Type vmxnet3 -StartConnected:$true -Confirm:$false -WarningAction SilentlyContinue -ErrorAction Stop | Out-Null
                                        Set-VrmsApplianceState -action restart | Out-Null
                                        Do {
                                            Start-Sleep 2
                                            $vmObject = Get-VMGuest -VM $vrmsVmName -Server $vcfVcenterDetails.fqdn-ErrorAction SilentlyContinue
                                            $vamiStatus = Test-VrmsVamiAuthentication -server $vrmsFqdn -user admin -pass $vrmsAdminPass -ErrorAction SilentlyContinue
                                        } Until (($vmObject.IPAddress) -and ($vamiStatus -eq $true))
                                        # Configure the IP via API and Restart the vSphere Replication appliance
                                        Set-VrmsNetworkInterface -interface eth1 -ipAddress $replicationIPAddress -gateway $replicationGateway -prefix $replicationSubnet.Split("/")[1]  | Out-Null
                                        Set-VrmsApplianceState -action restart | Out-Null
                                        Do {
                                            Start-Sleep 2
                                            $vmObject = Get-VMGuest -VM $vrmsVmName -Server $vcfVcenterDetails.fqdn-ErrorAction SilentlyContinue
                                            $vamiStatus = Test-VrmsVamiAuthentication -server $vrmsFqdn -user admin -pass $vrmsAdminPass -ErrorAction SilentlyContinue
                                        } Until (($vmObject.IPAddress) -and ($vamiStatus -eq $true))
                                        # Configure a static route for the replication network
                                        $scriptCommand = "sed -i '/^Gateway*/a Destination=$replicationRemoteNetwork' /etc/systemd/network/10-eth1.network | systemctl restart systemd-networkd.service"
                                        Invoke-VMScript -ScriptType bash -VM $vrmsVmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vrmsRootPass -Server $vcfVcenterDetails.fqdn | Out-Null
                                        # Configure the Incoming Storage Replication Port
                                        Request-VrmsToken -fqdn $vrmsFqdn -username admin -password $vrmsAdminPass | Out-Null
                                        Set-VrmsReplication -filterIp $replicationIpAddress -managementIp $vrmsIpAddress | Out-Null
                                        #Set-vSRIncomingStorageTraffic -fqdn $vrmsFqdn -username admin -password $vrmsAdminPass -ipAddress $replicationIpAddress -ErrorAction SilentlyContinue | Out-Null
                                        if (!((Get-VrmsConfiguration -replication).filter_ip -match $replicationIpAddress)) {                                                
                                            Write-Error "Setting Incoming Storage Traffic IP Address for vSphere Replication Appliance ($vrmsFqdn): POST_VALIDATION_FAILED"
                                        } else {
                                            Write-Output "Adding Ethernet Adapter to vSphere Replication Instance ($vrmsFqdn): SUCCESSFUL"
                                        }
                                    } else {
                                        Write-Warning "Adding Ethernet Adapter to vSphere Replication Instance ($vrmsFqdn), already exists: SKIPPING" 
                                    }
                                } else {
                                    Write-Error "Unable to find vSphere Distributed Port Group ($replicationPortgroup) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                }
                                Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-VrmsNetworkAdapter

Function Backup-VMOvfProperties {
    <#
        .SYNOPSIS
        Backup-VMOvfProperties.

        .DESCRIPTION
        The Backup-VMOvfProperties cmdlet creates a backup of the OVF properties for each supplied VM.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values to retrieve the DR protected VMs from its inventory and then:
        - Creates a backup of the VM OVF environment

        .EXAMPLE
        Backup-VMOvfProperties -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example creates a backup of the OVF properties for each supplied VM.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER fileDir
        The directory to store the backup files.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$fileDir
    )
        
    Try {
        if (!$PsBoundParameters.ContainsKey("fileDir")) {
            $fileDir = Get-ExternalDirectoryPath
        } else {
            if (!(Test-Path -Path $fileDir)) {
                Write-Error  "Directory '$fileDir' Not Found"
                Break
            }
        } 
        # Disconnect all connected vCenter Server instances to ensure only the desired vCenter Server instance is available
        if ($defaultviservers) {
            $server = $defaultviservers.Name
            foreach ($server in $defaultviservers) {            
                Disconnect-VIServer -Server $server -Confirm:$False
            }
        }
        $vcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT
        # Retrieve VMware Aria Suite Lifecycle VM Name
        $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass
        if ($vrslcmDetails) {
            Write-Output "Getting VMware Aria Suite Lifecycle VM Name"
            Connect-VIServer -server $vcenter.fqdn -user $vcenter.ssoAdmin -password $vcenter.ssoAdminPass | Out-Null
            $vrslcmVMName = Get-VM * | Where-Object {$_.Guest.Hostname -eq $vrslcmDetails.fqdn} | Select-Object Name
            $vrslcmVMName = $vrslcmVMName.Name
            $vmsToBackup = @("$vrslcmVMName")                
            Disconnect-VIServer -server $vcenter.fqdn -Confirm:$False
        }
        # Retrieve Workpace ONE Access VM Names
        $wsaDetails = Get-WSAServerDetail -fqdn $server -username $user -password $pass
        if ($wsaDetails) {
            Write-Output "Getting Workspace ONE Access VM Names"
            Connect-VIServer -server $vcenter.fqdn -user $vcenter.ssoAdmin -password $vcenter.ssoAdminPass | Out-Null
            Foreach ($wsaFQDN in $wsaDetails.fqdn) {
                $wsaVMName = Get-VM * | Where-Object {$_.Guest.Hostname -eq $wsaFQDN} | Select-Object Name
                $wsaVMName = $wsaVMName.Name
                $vmsToBackup += ,$wsaVMName
            }
            Disconnect-VIServer -server $vcenter.fqdn -Confirm:$False
        }
        # Retrieve VMware Aria Operations VM Names
        $vropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass
        if ($vropsDetails) {
            Write-Output "Getting Aria Operations VM Names"
            Connect-VIServer -server $vcenter.fqdn -user $vcenter.ssoAdmin -password $vcenter.ssoAdminPass | Out-Null
            Foreach ($vropsFQDN in $vropsDetails.fqdn) {
                $vropsVMName = Get-VM * | Where-Object{$_.Guest.Hostname -eq $vropsFQDN} | Select-Object Name
                $vropsVMName = $vropsVMName.Name
                $vmsToBackup += ,$vropsVMName
            }
            Disconnect-VIServer -server $vcenter.fqdn -Confirm:$False
        }
        # Retrieve VMware Aria Automation VM Names
        $vraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass
        if ($vraDetails) {
            Write-Output "Getting VMware Aria Automation VM Names"
            Connect-VIServer -server $vcenter.fqdn -user $vcenter.ssoAdmin -password $vcenter.ssoAdminPass | Out-Null
            Foreach ($vraFQDN in $vraDetails.fqdn) {
                $vraVMName = Get-VM * | Where-Object {$_.Guest.Hostname -eq $vraFQDN} | Select-Object Name
                $vraVMName = $vraVMName.Name
                $vmsToBackup += ,$vraVMName
            }
            Disconnect-VIServer -server $vcenter.fqdn -Confirm:$False
        }
        Connect-VIServer -server $vcenter.fqdn -user $vcenter.ssoAdmin -password $vcenter.ssoAdminPass | Out-Null
        Foreach ($vm in $vmsToBackup) {
            $vmToBackup = Get-VM -Name $vm
            Get-VMvAppConfig -vm $vmToBackup
        }
        Disconnect-VIServer -server $vcenter.fqdn -Confirm:$False
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Backup-VMOvfProperties

Function Restore-VMOvfProperties {
    <#
        .SYNOPSIS
        Restore-VMOvfProperties.

        .DESCRIPTION
        The Restore-VMOvfProperties cmdlet creates a backup of the OVF properties for each supplied VM.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values to retrieve the DR protected VMs from its inventory and then:
        - Creates a restore of the VM OVF environment

        .EXAMPLE
        Restore-VMOvfProperties -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example creates a backup of the OVF properties for each supplied VM.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER fileDir
        The directory where the OVF property backup files are stored.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$fileDir
    )

    Try {       
        if (!$PsBoundParameters.ContainsKey("fileDir")) {
            $fileDir = Get-ExternalDirectoryPath
        } else {
            if (!(Test-Path -Path $fileDir)) {
                Write-Error  "Directory '$fileDir' Not Found"
                Break
            }
        } 
        $fileNames = @()
        $fileNames = Get-ChildItem -File "$($fileDir)\*-property-backup.json" -Recurse
        # Disconnect all connected vCenter Server instances to ensure only the desired vCenter Server instance is available
        if ($defaultviservers) {
            $server = $defaultviservers.Name
            foreach ($server in $defaultviservers) {            
                Disconnect-VIServer -Server $server -Confirm:$False
            }
        }
        $vCenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT
        Connect-VIServer -server $vcenter.fqdn -user $vcenter.ssoAdmin -password $vcenter.ssoAdminPass | Out-Null
        Foreach ($fileName in $fileNames) {
            $fileName = $fileName.Name
            $separator = "-property-backup.json"
            $restoredVM = ($filename -split $separator)[0]

            $vmSettings = Get-content "$($fileDir)\$($restoredVM)-property-backup.json" | convertfrom-json
            if ($vmSettings) {
                $foundVM = Get-VM -Name $restoredVM -ErrorAction SilentlyContinue
                if ($foundVM) {
                    Write-Output "Restoring VM OVF Settings for $restoredVM"
                    Set-VMOvfIPAssignment -vm $foundVM -assignment $vmSettings.IpAssignment
                    if ($vmSettings.eula) {
                        Set-VMOvfEULA -vm $foundVM -eula $vmSettings.eula    
                    }
                    Set-VMOvfEnvTransport -vm $foundVM -transport $vmSettings.ovfEnvironmentTransport
                    foreach ($product in $vmSettings.product) {
                        New-VMOvfProduct -vm $foundVM -product $product
                    }
                    foreach ($property in $vmSettings.property) {
                        New-VMOvfProperty -vm $foundVM -property $property
                    }                   
                } else {
                    Write-Output "Placeholder $restoredVM not found in $($vcenter.fqdn)"
                }
            }
        }
        Disconnect-VIServer -server $vcenter.fqdn -Confirm:$False
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Restore-VMOVFProperties

Function Get-VMvAppConfig {
    <#
        .SYNOPSIS
        Retrieves the full OVF environment settings from a standard VM.

        .DESCRIPTION
        Saves the setting of the passed VM object to a JSON file

        .EXAMPLE
        Get-VMAppConfig -vm $vm.

        .PARAMETER vm
        The virtual appliance to retrieve the OVF properties from.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$vm
    )

    $targetFile = $fileDir + "\" + $vm.name + "-property-backup.json"
    Write-Output "Initating Backup of OVF Properties for $vm"
    Try {
        if ($vm.ExtensionData.Config.VAppConfig) {
            $vmVappConfig = $vm.ExtensionData.Config.VAppConfig | ConvertTo-Json | Out-File $targetFile
            Write-Output "OVF Properties successfully captured"
            return $vmVappConfig
        } else {
            Write-Output "No OVF properties were detected on $($vm.name). You may ignore this message if this is correct." -colour magenta
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-VMvAppConfig

Function New-VMOvfProperty {
    <#
        .SYNOPSIS
        Create a single OVF Property on a standard VM.

        .DESCRIPTION
        Accepts a object with propery details, parses it and adds it to supplied VM

        .EXAMPLE
        New-VMOvfProperty -vm $vm -property $propertyObject.

        .PARAMETER vm
        The virtual appliance to set the property on.

        .PARAMETER property
        The property to set on the virtual appliance.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$vm,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$property
    )

    #define spec
    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec
    $propertySpec = New-Object VMware.Vim.VAppPropertySpec
    
    #populate spec
    $propertySpec.Operation = "Add"
    $propertySpec.Info = New-Object VMware.Vim.VAppPropertyInfo
    $propertySpec.info.category = $property.category 
    $propertySpec.info.classId = $property.classId
    $propertySpec.info.defaultValue = $property.defaultValue 
    $propertySpec.info.description = $property.description   
    $propertySpec.info.id = $property.id 
    $propertySpec.info.instanceId = $property.instanceId      
    $propertySpec.info.key = $property.key
    $propertySpec.info.label = $property.label   
    $propertySpec.info.type = $property.type 
    $propertySpec.info.typeReference = $property.typeReference 
    $propertySpec.info.userConfigurable = $property.userConfigurable 
    $propertySpec.info.value = $property.value
    $spec.VAppConfig.Property = $propertySpec

    #write spec
    Write-Output "Creating OVF Property $($property.id) on $($vm.name)"
    $task = $vm.ExtensionData.ReconfigVM_Task($spec)
    $task1 = Get-Task -Id ("Task-$($task.value)")
    $waitask = $task1 | Wait-Task 
}
Export-ModuleMember -Function New-VMOvfProperty

Function Set-VMOvfIPAssignment {
    <#
        .SYNOPSIS
        Sets the IP Assignment OVF Setting.

        .DESCRIPTION
        Accepts a object with IP Assigment details and assigns it to the supplied VM

        .EXAMPLE
        Set-VMOvfIPAssignment -vm $vm -assignment $assignmentObject.

        .PARAMETER vm
        The virtual appliance to set the IP Assignment on.

        .PARAMETER assignment
        The IP Assignment to set on the virtual appliance.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$vm,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$assignment
    )

    #define spec
    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec
    $assignmentSpec = New-Object VMware.Vim.VAppIPAssignmentInfo

    #populate spec
    $assignmentSpec.ipAllocationPolicy = $assignment.ipAllocationPolicy
    $assignmentSpec.SupportedAllocationScheme = $assignment.SupportedAllocationScheme
    $assignmentSpec.SupportedIpProtocol = $assignment.SupportedIpProtocol
    $assignmentSpec.IpProtocol = $assignment.IpProtocol
    $spec.vAppConfig.IpAssignment = $assignmentSpec

    #write spec
    Write-Output "Configuring IP Assignment setting on $($vm.name)"
    $task = $vm.ExtensionData.ReconfigVM_Task($spec)
    $task1 = Get-Task -Id ("Task-$($task.value)")
    $waitask = $task1 | Wait-Task 
}
Export-ModuleMember -Function Set-VMOvfIPAssignment

Function Set-VMOvfEnvTransport {
    <#
        .SYNOPSIS
        Sets the Environment Transport setting for OVF properties.

        .DESCRIPTION
        Accepts a object with Environment Transport details and assigns it to the supplied VM

        .EXAMPLE
        Set-VMOvfEnvTransport -vm $vm -transport $transportObject.

        .PARAMETER vm
        The virtual appliance to set the Environment Transport on.

        .PARAMETER transport
        The Environment Transport to set on the virtual appliance.
    #>
 

    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$vm,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$transport
    )

    #define spec
    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec

    #populate spec
    $spec.vAppConfig.ovfEnvironmentTransport = $transport
    
    #write spec
    Write-Output "Configuring Environment Transport setting on $($vm.name)"
    $task = $vm.ExtensionData.ReconfigVM_Task($spec)
    $task1 = Get-Task -Id ("Task-$($task.value)")
    $waitask = $task1 | Wait-Task 
}
Export-ModuleMember -Function Set-VMOvfEnvTransport

Function New-VMOvfProduct {
    <#
        .SYNOPSIS
        Create a single OVF Product on a standard VM.

        .DESCRIPTION
        Accepts a object with produt details, parses it and adds it to supplied VM

        .EXAMPLE
        New-VMOvfProduct -vm $vm -product $productObject.

        .PARAMETER vm
        The virtual appliance to set the product on.

        .PARAMETER product
        The product to set on the virtual appliance.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()][PSObject]$vm,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$product
    )

    #define spec
    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec
    $productSpec = New-Object VMware.Vim.VAppProductSpec

    #populate spec
    $productSpec.Operation = "Add"
    $productSpec.Info = New-Object VMware.Vim.VAppProductInfo
    $productSpec.info.appUrl = $product.appUrl
    $productSpec.info.classId = $product.classId 
    $productSpec.info.fullVersion = $product.fullVersion 
    $productSpec.info.instanceId = $product.instanceId   
    $productSpec.info.key = $product.key 
    $productSpec.info.name = $product.name 
    $productSpec.info.productUrl = $product.productUrl   
    $productSpec.info.vendor = $product.vendor
    $productSpec.info.vendorUrl = $product.vendorUrl
    $productSpec.info.version = $product.version
    $spec.VAppConfig.Product = $productSpec

    #write spec
    Write-Output "Adding Product Setting on $($vm.name)"
    $task = $vm.ExtensionData.ReconfigVM_Task($spec)
    $task1 = Get-Task -Id ("Task-$($task.value)")
    $waitask = $task1 | Wait-Task 
}
Export-ModuleMember -Function New-VMOvfProduct

Function Set-VMOvfEULA {
    <#
        .SYNOPSIS
        Sets the EULA setting for OVF properties.

        .DESCRIPTION
        Accepts a object with EULA details and assigns it to the supplied VM

        .EXAMPLE
        Set-VMOvfEULA -vm $vm -eula $eulaObject.

        .PARAMETER vm
        The virtual appliance to set the EULA on.

        .PARAMETER eula
        The EULA to set on the virtual appliance.
    #>
    

    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$vm,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$eula
    )

    #define spec
    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec

    #populate spec
    $spec.vAppConfig.eula = $eula

    #write spec
    Write-Output "Setting EULA on $($vm.name)"
    $task = $vm.ExtensionData.ReconfigVM_Task($spec)
    $task1 = Get-Task -Id ("Task-$($task.value)")
    $waitask = $task1 | Wait-Task 
}
Export-ModuleMember -Function Set-VMOvfEULA

Function Get-VMOvfProperty {
    <#
        .SYNOPSIS
        Get OVF properties of a virtual appliance.

        .DESCRIPTION
        Returns OVF properties of a virtual appliance

        .EXAMPLE
        Get-VMOvfProperty -vm (Get-VM -Name xreg-wsa01a)
        This example returns an object that contains a full list of OVF properties for xreg-wsa01a.

        .PARAMETER vm
        The virtual appliance to get the OVF properties from.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [psObject]$vm
    )

    $vappProperties = $VM.ExtensionData.Config.VAppConfig.Property
    $results = @()
    foreach ($vappProperty in $vappProperties | Sort-Object -Property Id) {
        $tmp = [pscustomobject] @{
            Id = $vappProperty.Id;
            Value = $vappProperty.Value
        }
        $results+=$tmp
    }
    $results
}
Export-ModuleMember -Function Get-VMOvfProperty

Function Set-VMOvfProperty {
    <#
        .SYNOPSIS
        Sets OVF properties on a virtual appliance.

        .DESCRIPTION
        Accepts a hash table with property ID and value and sets the defined OVF property and value for a virtual
        appliance.

        .EXAMPLE
        Set-VMOvfProperty -vm (Get-VM -Name xreg-wsa01a) -Properties @{"DNS"="172.16.11.4,172.16.11.5"}
        This example sets the DNS servers to 172.16.11.4 and 172.16.11.5 in the OVF properties for xreg-wsa01a.

        .PARAMETER vm
        The virtual appliance to set the OVF properties on.

        .PARAMETER properties
        A hash table of OVF properties to set on the virtual appliance.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSObject]$vm,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [hashtable]$properties
    )

    $vappProperties = $VM.ExtensionData.Config.VAppConfig.Property
    
    #define spec
    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec
    $propertySpec = New-Object VMware.Vim.VAppPropertySpec[]($properties.count)

    #populate spec
    foreach ($vappProperty in $vappProperties) {
        if($properties.ContainsKey($vappProperty.Id)) {
            $tmp = New-Object VMware.Vim.VAppPropertySpec
            $tmp.Operation = "edit"
            $tmp.Info = New-Object VMware.Vim.VAppPropertyInfo
            $tmp.Info.Key = $vappProperty.Key
            $tmp.Info.value = $properties[$vappProperty.Id]
            $propertySpec+=($tmp)
        }
    }
    $spec.VAppConfig.Property = $propertySpec

    #write spec
    Write-Output "Setting vApp properties on $($vm.name)"
    $task = $vm.ExtensionData.ReconfigVM_Task($spec)
    $task1 = Get-Task -Id ("Task-$($task.value)")
    $waitask = $task1 | Wait-Task 
}
Export-ModuleMember -Function Set-VMOvfProperty

Function Get-NSXLBDetails {
    <#
        .SYNOPSIS
        Get-NSXLBDetails.

        .DESCRIPTION
        The Get-NSXLBDetails cmdlet gets the IP addresses of the VIPs and pool members for the NSX Load Balancer for VMware Aria.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values to retrive the NSX load balancer configurationn

        .EXAMPLE
        Get-NSXLBDetails -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example gets the IP addresses of the VIPs and pool members for the NSX Load Balancer for VMware Aria.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        # Retrieve Workspace ONE Access VIP
        $wsaDetails = Get-WSAServerDetail -fqdn $server -username $user -password $pass
        if ($wsaDetails) {
            Write-Output "Found Workspace ONE Access. Getting Virtual Server and Node IP Addresses."
            $wsaVIP = $wsaDetails.loadBalancerIpAddress
            $wsaNode1IP = $wsaDetails.node1IpAddress
            $wsaNode2IP = $wsaDetails.node2IpAddress
            $wsaNode3IP = $wsaDetails.node3IpAddress
        }
        # Retrieve VMware Aria Operations VM Names
        $vropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass
        if ($vropsDetails) {
            Write-Output "Found VMware Aria Operations. Getting Virtual Server and Node IP Addresses."                
            $vropsVIP = $vropsDetails.loadBalancerIpAddress
            $vopsNode1IP = $vropsDetails.node1IpAddress
            $vopsNode2IP = $vropsDetails.node2IpAddress
            $vopsNode3IP = $vropsDetails.node3IpAddress
        }
        # Retrieve VMware Aria Automation VM Names
        $vraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass
        if ($vraDetails) {
            Write-Output "Found VMware Aria Automation. Getting Virtual Server and Node IP Addresses."
            $vraVIP = $vraDetails.loadBalancerIpAddress
            $vraNode1IP = $vraDetails.node1IpAddress
            $vraNode2IP = $vraDetails.node2IpAddress
            $vraNode3IP = $vraDetails.node3IpAddress
        }
        # Gather NSX Manager Details
        Write-Output "Getting NSX Login Details"
        $nsxt = Get-NsxtServerDetail -fqdn $server -user $user -pass $pass -domainType MANAGEMENT
        $nsxtFQDN = $nsxt.fqdn
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-NSXLBDetails

Function Add-vRSLCMNtpServer {
    <#
        .SYNOPSIS
        Add an NTP Server for the VMware Aria Suite Lifecycle appliance.

        .DESCRIPTION
        The Add-vRSLCMNtpServer cmdlet configures the NTP Server details of the VMware Aria Suite Lifecycle
        appliance using one or more NTP servers passed as a parameter. The cmdlet connects to SDDC Manager using
        the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures the VMware Aria Suite Lifecycle appliance NTP configuration
        
        .EXAMPLE
        Add-vRSLCMNtpServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -ntpServer ntp.lax.rainpole.io -ntpServerDesc "VCF NTP Server 2"
        This example configures the VMware Aria Suite Lifecycle appliance managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to add ntp.lax.rainpole.io to its list of NTP servers.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER ntpServer
        The NTP server to add to the VMware Aria Suite Lifecycle appliance.

        .PARAMETER ntpServerDesc
        The NTP server description to add to the VMware Aria Suite Lifecycle appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServerDesc
    )

    Try {
        if (Test-NtpServer -Server $ntpServer) {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                                if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                    $vmName = $vrslcmDetails.fqdn.Split(".")[0]
                                    if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                        $vrslcmProductNtpServers = Get-vRSLCMProductNtpServer
                                        if ($vrslcmProductNtpServers -match $ntpServer -or $vrslcmProductNtpServers -match $ntpServerDesc) {
                                            Write-Warning "Adding ($ntpServer) or description ($ntpServerDesc) to VMware Aria Suite Lifecycle ($vmName) product NTP server list, already performed: SKIPPED"
                                        } else {
                                            $addvRSLCMProductNtp = Add-vRSLCMProductNtpServer -ntpServer $ntpServer -ntpServerDesc $ntpServerDesc -ErrorAction SilentlyContinue
                                            if ($addvRSLCMProductNtp -match $ntpServer) {
                                                Write-Output "Adding ($ntpServer) to VMware Aria Suite Lifecycle ($vmName) product NTP server list: SUCCESSFUL"
                                            } else {
                                                Write-Error "Adding ($ntpServer) to VMware Aria Suite Lifecycle ($vmName) product NTP server list: POST_VALIDATION_FAILED"
                                            }
                                        }
                                        $vrslcmApplianceNtpConfig = Get-vRSLCMApplianceNtpConfig
                                        if ($vrslcmApplianceNtpConfig.ntpServers -match $ntpServer -or $vrslcmApplianceNtpConfig.ntpServers -match $ntpServerDesc) {
                                            Write-Warning "Adding ($ntpServer) or description ($ntpServerDesc) to VMware Aria Suite Lifecycle ($vmName) appliance NTP configuration, already performed: SKIPPED"
                                        } else {
                                            $addvRSLCMApplianceNtp = Add-vRSLCMApplianceNtpConfig -ntpServer $ntpServer -ErrorAction SilentlyContinue
                                            if ($addvRSLCMApplianceNtp.ntpServers -match $ntpServer) {
                                                Write-Output "Adding ($ntpServer) to VMware Aria Suite Lifecycle ($vmName) appliance NTP configuration: SUCCESSFUL"
                                            } else {
                                                Write-Error "Adding ($ntpServer) to VMware Aria Suite Lifecycle ($vmName) appliance NTP configuration: POST_VALIDATION_FAILED"
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to authenticate with VMware Aria Suite Lifecycle ($vmName) appliance: PRE_VALIDATION_FAILED"
                                    }
                                    Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Write-Error "Unable to confirm NTP Server ($ntpServer) is valid: PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRSLCMNtpServer

Function Set-vRSLCMDnsConfig {
    <#
        .SYNOPSIS
        Configure DNS Server and/or DNS search domains on VMware Aria Suite Lifecycle appliance.

        .DESCRIPTION
        The Set-vRSLCMDnsConfig cmdlet configures the DNS server and search domain details of the VMware Aria Suite
        Lifecycle appliance using one or more DNS servers and/or DNS search domains passed as a parameter.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures the VMware Aria Suite Lifecycle appliance DNS configuration

        .EXAMPLE
        Set-vRSLCMDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -rootPass VMw@re1! -dnsServers "172.16.11.4 172.16.11.5" -dnsSearchDomains rainpole.io
        This example configures the VMware Aria Suite Lifecycle appliance managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use 172.16.11.4 and 172.16.11.5 as its DNS servers and rainpole.io as its search domain

        .EXAMPLE
        Set-vRSLCMDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -rootPass VMw@re1! -dnsServers "172.16.11.4 172.16.11.5 172.17.11.4 172.17.11.5" -dnsSearchDomains "rainpole.io sfo.rainpole.io lax.rainpole.io"
        This example configures the VMware Aria Suite Lifecycle appliance managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use 172.16.11.4, 172.16.11.5, 172.17.11.4, and 172.17.11.5 as its DNS servers and rainpole.io, sfo.rainpole.io, and lax.rainpole.io as its DNS search domains.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER dnsServers
        The DNS servers to configure on the VMware Aria Suite Lifecycle appliance.

        .PARAMETER dnsSearchDomains
        The DNS search domains to configure on the VMware Aria Suite Lifecycle appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsServers,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsSearchDomains
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                $vmName = $vrslcmDetails.fqdn.Split(".")[0]
                                if ((Get-VM -Name $vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                    if ($dnsServers) {
                                        $scriptCommand = "sed -i '/#DNS=/d' /etc/systemd/resolved.conf"
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vrslcmDetails.rootPassword -Server $vcfVcenterDetails.fqdn
                                        $scriptCommand = "sed -i '/^DNS=/c\DNS=$dnsServers' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vrslcmDetails.rootPassword -Server $vcfVcenterDetails.fqdn
                                        $scriptCommand = "cat /etc/systemd/resolved.conf"
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vrslcmDetails.rootPassword -Server $vcfVcenterDetails.fqdn
                                        if (($output.ScriptOutput).Contains("DNS=$dnsServers")) {
                                            Write-Output "Configuring VMware Aria Suite Lifecycle ($vmName) to use DNS Server(s) ($dnsServers): SUCCESSFUL"
                                        } else {
                                            Write-Error "Configuring VMware Aria Suite Lifecycle ($vmName) to use DNS Server(s) ($dnsServers): POST_VALIDATION_FAILED"
                                        }
                                    }
                                    if ($dnsSearchDomains) {
                                        if (($output.ScriptOutput).Contains("#Domains")) {
                                            $scriptCommand = "sed -i '/#Domains=/c\Domains=$dnsSearchDomains' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                        } else {
                                            $scriptCommand = "sed -i '/^Domains=/c\Domains=$dnsSearchDomains' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                        } 
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vrslcmDetails.rootPassword -Server $vcfVcenterDetails.fqdn   
                                        $scriptCommand = "cat /etc/systemd/resolved.conf"
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vrslcmDetails.rootPassword -Server $vcfVcenterDetails.fqdn
                                        if (($output.ScriptOutput).Contains("Domains=$dnsSearchDomains")) {
                                            Write-Output "Configuring VMware Aria Suite Lifecycle ($vmName) to use DNS search domain(s) ($dnsSearchDomains): SUCCESSFUL"
                                        } else {
                                            Write-Error "Configuring VMware Aria Suite Lifecycle ($vmName) to use DNS search domain(s) ($dnsSearchDomains): POST_VALIDATION_FAILED"
                                        }
                                    }
                                } else {
                                    Write-Error "Unable to locate a virtual machine named ($vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vRSLCMDnsConfig

Function Undo-vRSLCMNtpServer {
    <#
        .SYNOPSIS
        Set the NTP Server configuration of VMware Aria Suite Lifecycle to match SDDC Manager.

        .DESCRIPTION
        The Undo-vRSLCMNtpServer cmdlet sets the NTP Server details of the VMware Aria Suite Lifecycle appliance
        back to what is stored in SDDC Manager. The cmdlet connects to SDDC Manager using the -server, -user, and
        -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Retrieves NTP server configuration from SDDC Manager
        - Configures the VMware Aria Suite Lifecycle to use only the values stored in SDDC Manager
        
        .EXAMPLE
        Undo-vRSLCMNtpServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example configures the VMware Aria Suite Lifecycle appliance managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use only the NTP servers found in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    $sddcManagerNtpServers = Get-VCFConfigurationNTP | Select-Object -ExpandProperty ipAddress
                    if ($sddcManagerNtpServers.count -gt 1) {
                        $sddcManagerNtpServers = $sddcManagerNtpServers -join ","
                    }
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                $vmName = $vrslcmDetails.fqdn.Split(".")[0]
                                if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                    $evaluatevRSLCMApplianceNtpConfig = Get-vRSLCMApplianceNtpConfig | Select-Object -ExpandProperty ntpServers
                                    if ($evaluatevRSLCMApplianceNtpConfig -ne $sddcManagerNtpServers) {
                                        Set-vRSLCMApplianceNtpConfig -ntpServer $sddcManagerNtpServers -ErrorAction SilentlyContinue | Out-Null
                                        $validateApplianceNtpConfig = Get-vRSLCMApplianceNtpConfig | Select-Object -ExpandProperty ntpServers
                                        if ($validateApplianceNtpConfig -eq $sddcManagerNtpServers) {
                                            Write-Output "Restoring VMware Aria Suite Lifecycle ($vmName) appliance NTP servers to SDDC Manager defaults: SUCCESSFUL"
                                        } else {
                                            Write-Error "Restoring VMware Aria Suite Lifecycle ($vmName) appliance NTP servers to SDDC Manager defaults: POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Restoring VMware Aria Suite Lifecycle ($vmName) appliance NTP servers to SDDC Manager defaults: SKIPPED"
                                    }
                                    $sddcManagerNtpServers = $null
                                    $currentProductNtpServers = Get-vRSLCMProductNtpServer | Select-Object -ExpandProperty hostName
                                    $sddcManagerNtpServers = Get-VCFConfigurationNTP | Select-Object -ExpandProperty ipAddress
                                    foreach ($currentProductNtpServer in $currentProductNtpServers) {
                                        if ($sddcManagerNtpServers -notContains $currentProductNtpServer) {
                                            Remove-vRSLCMProductNtpServer -ntpServer $currentProductNtpServer -ErrorAction SilentlyContinue | Out-Null
                                            $removedvRSLCMProductNtpServer = 1
                                        }
                                    }
                                    if ($removedvRSLCMProductNtpServer -eq 1) {
                                        $validateProductNtpServers = Get-vRSLCMProductNtpServer | Select-Object -ExpandProperty hostName
                                        $validateProductNtpServerSuccess = 1
                                        foreach ($validateProductNtpServer in $validateProductNtpServers) {
                                            if ($sddcManagerNtpServers -notContains $validateProductNtpServer) {
                                                $validateProductNtpServerSuccess = 0
                                                Write-Error "Restoring VMware Aria Suite Lifecycle ($vmName) product NTP servers to SDDC Manager defaults: POST_VALIDATION_FAILED"
                                            }
                                        }
                                        if ($validateProductNtpServerSuccess -eq 1) {
                                            Write-Output "Restoring VMware Aria Suite Lifecycle ($vmName) product NTP servers to SDDC Manager defaults: SUCCESSFUL"
                                        }
                                    } else {
                                        Write-Warning "Restoring VMware Aria Suite Lifecycle ($vmName) product NTP servers to SDDC Manager defaults: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to authenticate with VMware Aria Suite Lifecycle ($vmName) appliance: PRE_VALIDATION_FAILED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRSLCMNtpServer

Function Undo-vRSLCMDnsConfig {
    <#
        .SYNOPSIS
        Sets the DNS Server and/or DNS search domains on VMware Aria Suite Lifecycle to match SDDC Manager.

        .DESCRIPTION
        The Undo-vRSLCMDnsConfig cmdlet configures the DNS server and search domain details of the VMware Aria Suite Lifecycle appliance to the values stored in SDDC Manager. The cmdlet connects to SDDC Manager using
        the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Retrieves the DNS server and search domain values from SDDC Manager
        - Configures the VMware Aria Suite Lifecycle appliance DNS configuration to match the values retrieved from SDDC Manager

        .EXAMPLE
        Undo-vRSLCMDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example configures the VMware Aria Suite Lifecycle appliance managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use values for DNS servers and search domains to the values stored in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER sddcManagerRootPass
        The root password used to authenticate to the VMware Aria Suite Lifecycle appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerRootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $sddcManagerInstance = Get-VCFManager
                $sddcManagerVmName = $sddcManagerInstance.fqdn.Split(".")[0]
                $sddcManagerDnsServers = Get-VCFConfigurationDNS | Select-Object -ExpandProperty ipAddress
                if ($sddcManagerDnsServers.Count -gt 1) {
                    $sddcManagerDnsServers = $sddcManagerDnsServers -Join " "
                }
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                $vmName = $vrslcmDetails.fqdn.Split(".")[0]
                                if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                    Try {
                                        $sddcManagerSearchDomains = Get-VCFDnsSearchDomain -sddcManagerVmName $sddcManagerVmName -sddcManagerRootPass $sddcManagerRootPass -ErrorAction Stop
                                    } Catch [System.Security.Authentication.InvalidCredentialException]{                                           
                                        $PSCmdlet.ThrowTerminatingError($PSItem)
                                    }                                
                                    if (!$sddcManagerDnsServers -or !$sddcManagerSearchDomains) {
                                        Write-Error "Unable to undo DNS configuration on VMware Aria Suite Lifecycle ($vmName) appliance: PRE_VALIDATION_FAILED"
                                    } else {
                                        Try {
                                            Set-vRSLCMDnsConfig -server $server -user $user -pass $pass -dnsServers $sddcManagerDnsServers -dnsSearchDomains $sddcManagerSearchDomains
                                        } Catch {
                                            Write-Error "Unable to undo DNS configuration on VMware Aria Suite Lifecycle ($vmName) appliance: POST_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            } else {
                                Write-Error "Unable to locate a virtual machine named ($sddcManagerVmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRSLCMDnsConfig

Function Set-WorkspaceOneDnsConfig {
    <#
        .SYNOPSIS
        Sets the DNS server and/or DNS search domains for all Workspace ONE Access appliances.

        .DESCRIPTION
        The Set-WorkspaceOneDnsConfig cmdlet configures the DNS server and search domain details of all Workspace ONE
        Access appliances to the values stored in SDDC Manager. The cmdlet connects to SDDC Manager using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures the DNS configuration for all Workspace ONE Access appliances

        .EXAMPLE
        Set-WorkspaceOneDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -dnsServers "172.16.11.4 172.16.11.5" -dnsSearchDomains "rainpole.io sfo.rainpole.io lax.rainpole.io"
        This example configures all Workspace ONE Access appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use 172.16.11.4 amd 172.16.11.5 as its DNS servers and rainpole.io, sfo.rainpole.io, and lax.rainpole.io as its DNS search domains.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER dnsServers
        The DNS servers to configure on all Workspace ONE Access appliances.

        .PARAMETER dnsSearchDomains
        The DNS search domains to configure on all Workspace ONE Access appliances.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsServers,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsSearchDomains
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                Try {
                                    $newRequest = Stop-vRSLCMProductNode -environment globalenvironment -product vidm -ErrorAction Stop
                                } Catch {
                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                }
                                if ($newRequest) {
                                    Write-Output "Powering off Workspace ONE Access appliances. This may take quite a while."
                                    Start-Sleep 10
                                    Watch-vRSLCMRequest -vmid $($newRequest.requestId) | Out-Null
                                } else {
                                    Write-Error "Power off request of Workspace ONE Access failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                } 
                                $productVMs = Get-vRSLCMProductNode -environmentName globalenvironment -product vidm              
                                foreach ($productVM in $productVMs) {
                                    if ((Get-VM -Name $productVM.vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                        if ($dnsServers) {
                                            $existingDNS = Get-VMOvfProperty -vm (Get-VM -Name $productVM.vmName) | Where-Object {$_.Id -eq "DNS"} | Select-Object -ExpandProperty Value
                                            if ($existingDNS -eq $dnsServers) {
                                                Write-Warning "Configuring Workspace ONE Access appliance $($productVM.vmName) to use DNS Server(s) ($dnsServers) already done: SKIPPED"
                                            } else {
                                                Set-VMOvfProperty -vm (Get-VM -Name $productVM.vmName) -properties @{"DNS"="$dnsServers"} | Out-Null
                                            }
                                            $validateDNS = Get-VMOvfProperty -vm (Get-VM -Name $productVM.vmName) | Where-Object {$_.Id -eq "DNS"} | Select-Object -ExpandProperty Value
                                            if ($validateDNS -eq $dnsServers) {
                                                Write-Output "Configuring Workspace ONE Access appliance $($productVM.vmName) to use DNS server(s) ($dnsServers): SUCCESSFUL"
                                            } else {
                                                Write-Error "Configuring Workspace ONE Access appliance $($ProductVM.vmName) to use DNS server(s) ($dnsServers): POST_VALIDATION_FAILED"
                                            }
                                        }
                                        if ($dnsSearchDomains) {
                                            $existingSearchDomains = Get-VMOvfProperty -vm (Get-VM -Name $productVM.vmName) | Where-Object {$_.Id -eq "searchpath"} | Select-Object -ExpandProperty Value
                                            if ($existingSearchDomains -eq $dnsSearchDomains) {
                                                Write-Warning "Configuring Workspace ONE Access appliance $($productVM.vmName) to use DNS search domain(s) ($dnsSearchDomains) already done: SKIPPED"
                                            } else {
                                                Set-VMOvfProperty -vm (Get-VM -Name $productVM.vmName) -properties @{"searchpath"="$dnsSearchDomains"} | Out-Null
                                            }
                                            $validateSearchDomains = Get-VMOvfProperty -vm (Get-VM -Name $productVM.vmName) | Where-Object {$_.Id -eq "searchpath"} | Select-Object -ExpandProperty Value
                                            if ($validateSearchDomains -eq $dnsSearchDomains) {
                                                Write-Output "Configuring Workspace ONE Access appliance $($productVM.vmName) to use DNS search domain(s) ($dnsSearchDomains): SUCCESSFUL"
                                            } else {
                                                Write-Error "Configuring Workspace ONE Access appliance $($ProductVM.vmName) to use DNS search domain(s) ($dnsSearchDomains): POST_VALIDATION_FAILED"
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to locate a virtual machine named $($productVM.vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                    }
                                }
                                $newRequest = Start-vRSLCMProductNode -environment globalenvironment -product vidm
                                if ($newRequest) {
                                    Write-Output "Powering on Workspace ONE Access appliances and bringing up services. This may take quite a while."
                                    Start-Sleep 10
                                    Watch-vRSLCMRequest -vmid $($newRequest.requestId) | Out-Null                                    
                                } else {
                                    Write-Error "Power on request of Workspace ONE Access appliance(s) failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-WorkspaceOneDnsConfig

Function Undo-WorkspaceOneDnsConfig {
    <#
        .SYNOPSIS
        Sets the DNS Server and/or DNS search domains on Workspace ONE Access to match SDDC Manager.

        .DESCRIPTION
        The Undo-WorkspaceOneDnsConfig cmdlet configures the DNS server and search domain details of all Workspace
        ONE Access appliances to the values stored in SDDC Manager. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Retrieves the DNS server and search domain values from SDDC Manager
        - Configures all Workspace ONE appliance DNS configuration to match the values retrieved from SDDC Manager

        .EXAMPLE
        Undo-WorkspaceOneDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcManagerRootPass VMw@re1!
        This example configures all Workspace ONE Access appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use values for DNS servers and search domains to the values stored in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER sddcManagerRootPass
        The root password of the SDDC Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerRootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $sddcManagerInstance = Get-VCFManager
                $sddcManagerVmName = $sddcManagerInstance.fqdn.Split(".")[0]
                $sddcManagerDnsServers = Get-VCFConfigurationDNS | Select-Object -ExpandProperty ipAddress
                if ($sddcManagerDnsServers.Count -gt 1) {
                    $sddcManagerDnsServers = $sddcManagerDnsServers -Join ","
                }
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                    Try {
                                        $sddcManagerSearchDomains = Get-VCFDnsSearchDomain -sddcManagerVmName $sddcManagerVmName -sddcManagerRootPass $sddcManagerRootPass -ErrorAction Stop
                                    } Catch [System.Security.Authentication.InvalidCredentialException]{       
                                        $PSCmdlet.ThrowTerminatingError($PSItem)
                                    }                                
                                    if (!$sddcManagerDnsServers -or !$sddcManagerSearchDomains) {
                                        Write-Error "Unable to undo DNS configuration on Workspace ONE Access ($vmName) appliance: PRE_VALIDATION_FAILED"
                                    } else {
                                        Try {
                                            Set-WorkspaceOneDnsConfig -server $server -user $user -pass $pass -dnsServers $sddcManagerDnsServers -dnsSearchDomains $sddcManagerSearchDomains -ErrorAction Stop -WarningAction SilentlyContinue
                                        } Catch {
                                            Write-Error $_.Exception.Message
                                        }
                                    }
                                }
                            } else {
                                Write-Error "Unable to locate a virtual machine named ($sddcManagerVmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-WorkspaceOneDnsConfig

Function Set-vROPSDnsConfig {
    <#
        .SYNOPSIS
        Configure DNS Server and/or DNS search domains on VMware Aria Operations appliance.

        .DESCRIPTION
        The Set-vROPSDnsConfig cmdlet configures the DNS server and search domain details of all VMware Aria Operations
        analytics cluster appliances to the values passed as parameters. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures all VMware Aria Operations analytics cluster appliance DNS configuration to the values
        passed to the function using -dnsServers and -dnsSearchDomains.

        .EXAMPLE
        Set-vROPSDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName xint-env -dnsServers "172.16.11.4 172.16.11.5" -dnsSearchDomains rainpole.io
        This example configures the VMware Aria Operations analytics cluster appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use 172.16.11.4 and 172.16.11.5 as its DNS servers and rainpole.io as its search domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER environmentName
        The name of the environment to configure DNS on.

        .PARAMETER dnsServers
        The DNS servers to configure on the VMware Aria Operations analytics cluster appliances.

        .PARAMETER dnsSearchDomains
        The DNS search domains to configure on the VMware Aria Operations analytics cluster appliances.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsServers,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsSearchDomains
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                $vropsVMs = (Get-VCFvROPs).nodes.fqdn
                                Try {
                                    $productVMs = Get-vRSLCMProductNode -environmentName $environmentName -product vrops -ErrorAction Stop
                                } Catch [System.Net.WebException] {
                                    $PSCmdlet.ThrowTerminatingError(
                                        [System.Management.Automation.ErrorRecord]::new(
                                            ([System.Management.Automation.GetValueException]"Retrieving VMware Aria Operations appliance information from VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"),
                                            'Get-vRSLCMProductNode',
                                            [System.Management.Automation.ErrorCategory]::ReadError,
                                            ""
                                        )
                                    )
                                }
                                $vropsXregVMs = @()
                                foreach ($productVM in $productVMs) {
                                    if ($vropsVMs -contains $productVM.hostName) {
                                        $vropsXregVMs += $productVM
                                    }
                                }
                                foreach ($vropsXregVM in $vropsXregVMs){
                                    $vropsRootPass = (Get-VCFCredential | Where-Object {$_.credentialType -eq "SSH" -and $_.resource.resourceType -eq "VROPS" -and $_.resource.resourceName -eq $vropsXregVM.hostName}).password
                                    if ((Get-VM -Name $vropsXregVM.vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                        if ($dnsServers) {
                                            $scriptCommand = "sed -i '/#DNS=/d' /etc/systemd/resolved.conf"
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            $scriptCommand = "sed -i '/^DNS=/c\DNS=$dnsServers' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            $scriptCommand = "cat /etc/systemd/resolved.conf"
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            if (($output.ScriptOutput).Contains("DNS=$dnsServers")) {
                                                Write-Output "Configuring VMware Aria Operations appliance ($($vropsXregVM.vmName)) to use DNS Server(s) ($dnsServers): SUCCESSFUL"
                                            } else {
                                                Write-Error "Configuring VMware Aria Operations appliance ($($vropsXregVM.vmName)) to use DNS Server(s) ($dnsServers): POST_VALIDATION_FAILED"
                                            }
                                        }
                                        if ($dnsSearchDomains) {
                                            $scriptCommand = "cat /etc/systemd/network/10-eth0.network"
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            if (($output.ScriptOutput).Contains("Domains=")) {
                                                $scriptCommand = "sed -i '/^Domains=/d' /etc/systemd/network/10-eth0.network | systemctl restart systemd-networkd"
                                                $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            } 
                                            $scriptCommand = "cat /etc/systemd/resolved.conf"
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            if (($output.ScriptOutput).Contains("#Domains")) {
                                                $scriptCommand = "sed -i '/#Domains=/c\Domains=$dnsSearchDomains' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                            } else {
                                                $scriptCommand = "sed -i '/^Domains=/c\Domains=$dnsSearchDomains' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                            } 
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn   
                                            $scriptCommand = "cat /etc/systemd/resolved.conf"
                                            $output = Invoke-VMScript -VM $vropsXregVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                            if (($output.ScriptOutput).Contains("Domains=$dnsSearchDomains")) {
                                                Write-Output "Configuring VMware Aria Operations appliance ($($vropsXregVM.vmName)) to use DNS search domain(s) ($dnsSearchDomains): SUCCESSFUL"
                                            } else {
                                                Write-Error "Configuring VMware Aria Operations appliance ($($vropsXregVM.vmName)) to use DNS search domain(s) ($dnsSearchDomains): POST_VALIDATION_FAILED"
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to locate a virtual machine named ($($vropsXregVM.vmName)) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                    }
                                } 
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }  
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vROPSDnsConfig

Function Undo-vROPSDnsConfig {
    <#
        .SYNOPSIS
        Sets the DNS Server and/or DNS search domains on VMware Aria Operations appliances to match SDDC Manager.

        .DESCRIPTION
        The Undo-vROPSDnsConfig cmdlet configures the DNS server and search domain details of VMware Aria Operations
        analytics cluster appliances to the values stored in SDDC Manager. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Retrieves the DNS server and search domain values from SDDC Manager
        - Configures VMware Aria Operations analytics cluster appliance DNS configuration to match the values
        retrieved from SDDC Manager

        .EXAMPLE
        Undo-vROPSDnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcManagerRootPass VMw@re1! -environmentName xint-env
        This example configures all VMware Aria Operations analytics cluster appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use values for DNS servers and search domains to the values stored in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER sddcManagerRootPass
        The root password to authenticate to SDDC Manager appliance. to connect with.

        .PARAMETER environmentName
        The SDDC Manager environment name to connect with.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerRootPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $sddcManagerInstance = Get-VCFManager
                $sddcManagerVmName = $sddcManagerInstance.fqdn.Split(".")[0]
                $sddcManagerDnsServers = Get-VCFConfigurationDNS | Select-Object -ExpandProperty ipAddress
                if ($sddcManagerDnsServers.Count -gt 1) {
                    $sddcManagerDnsServers = $sddcManagerDnsServers -Join " "
                }
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass
                            if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                    $vcfvROPSDetails = Get-VCFvROPS
                                    if (Test-vROPSConnection -server $vcfVROPSDetails.loadBalancerFqdn) {
                                        Try {
                                            $sddcManagerSearchDomains = Get-VCFDnsSearchDomain -sddcManagerVmName $sddcManagerVmName -sddcManagerRootPass $sddcManagerRootPass -ErrorAction Stop 
                                        } Catch [System.Security.Authentication.InvalidCredentialException]{                                       
                                            $PSCmdlet.ThrowTerminatingError($PSItem)
                                        }                                
                                        if (!$sddcManagerDnsServers -or !$sddcManagerSearchDomains) {
                                            Write-Error "Unable to undo DNS configuration for VMware Aria Operations analytics cluster appliances: PRE_VALIDATION_FAILED"
                                        } else {
                                            Try {
                                                Set-vROPSDnsConfig -server $server -user $user -pass $pass -environmentName $environmentName -dnsServers $sddcManagerDnsServers -dnsSearchDomains $sddcManagerSearchDomains -ErrorAction Stop -WarningAction SilentlyContinue
                                            } Catch {
                                                Write-Error $_.Exception.Message
                                            }
                                        }                                    
                                    } else {
                                        Write-Error "Unable connect to VMware Aria Operations: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to authenticate with VMware Aria Suite Lifecycle to retrieve VMware Aria Operations analytics cluster appliances: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to connect to VMware Aria Suite Lifecycle ($($vrslcmDetails.fqdn.Split(".")[0])): PRE_VALIDATION_FAILED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        } else {
                            Write-Error "Unable to locate a virtual machine named ($sddcManagerVmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vROPSDnsConfig

Function Add-vROPSNtpServer {
    <#
        .SYNOPSIS
        Adds an NTP server to all VMware Aria Operations appliances.

        .DESCRIPTION
        The Add-vROPSNtpServer cmdlet adds an NTP server to all VMware Aria Operations appliances. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures all VMware Aria Operations appliances to use an additional NTP server defined using the value
        passed to the function using -ntpServer.

        .EXAMPLE
        Add-vROPSNtpServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName xint-env -ntpServer ntp.lax.rainpole.io
        This example configures the VMware Aria Operations appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to add the NTP server ntp.lax.rainpole.io.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER environmentName
        The name of the environment to configure.

        .PARAMETER ntpServer
        The NTP server to add to the VMware Aria Operations appliances.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServer
    )

    $testNtp = Test-NtpServer -Server $ntpServer
    if ($testNtp -eq $false) {
        Write-Error "Unable to confirm NTP server $ntpServer is valid: PRE_VALIDATION_FAILED"
        break
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                Try {
                                    $productVM = (Get-vRSLCMProductNode -environmentName $environmentName -product vrops -ErrorAction Stop)[0]
                                } Catch [System.Net.WebException] {
                                    $PSCmdlet.ThrowTerminatingError(
                                        [System.Management.Automation.ErrorRecord]::new(
                                            ([System.Management.Automation.GetValueException]"Retrieving VMware Aria Operations appliance information from VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"),
                                            'Get-vRSLCMProductNode',
                                            [System.Management.Automation.ErrorCategory]::ReadError,
                                            ""
                                        )
                                    )
                                }
                                $vropsRootPass = (Get-VCFCredential | Where-Object {$_.credentialType -eq "SSH" -and $_.resource.resourceType -eq "VROPS" -and $_.resource.resourceName -eq $productVM.hostName}).password
                                if ((Get-VM -Name $productVM.vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                    $scriptCommand = "python /usr/lib/vmware-casa/bin/ntp_list.py"
                                    $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                    $existingNtpServers = ($output.ScriptOutput | ConvertFrom-JSON).time_servers
                                    $ntpServers = @()
                                    foreach ($existingNtpServer in $existingNtpServers) {
                                        $ntpServers += $existingNtpServer.address
                                    }
                                    $ntpServers += $ntpServer
                                    $ntpServersJson = $ntpServers | ConvertTo-JSON
                                    $ntpServersJson = $ntpServersJson -replace "`r`n","" -replace " ",""
                                    $scriptCommand = "echo '$ntpServersJson' | python /usr/lib/vmware-casa/bin/ntp_update.py > /dev/null 2>&1"
                                    $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                    $scriptCommand = "python /usr/lib/vmware-casa/bin/ntp_list.py"
                                    $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                    $vropsNtpServers = ($output.ScriptOutput | ConvertFrom-JSON).time_servers
                                    $vropsNtpServerArray = @()
                                    foreach ($vropsNtpServer in $vropsNtpServers) {
                                        $vropsNtpServerArray += $vropsNtpServer.address
                                    }
                                    $compareArrays = Compare-Object -ReferenceObject $ntpServers -DifferenceObject $vropsNtpServerArray
                                    if (!$compareArrays) {
                                        Write-Output "Configuring VMware Aria Operations appliances to use NTP servers ($($ntpServers -Join ", ")): SUCCESSFUL"
                                    } else {
                                        Write-Output "Unable to validate VMware Aria Operations appliances were configured to use NTP servers ($($ntpServers -Join ", ")): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to locate a virtual machine named ($($productVM.vmName)) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                } 
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }  
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSNtpServer

Function Undo-vROPSNtpServer {
    <#
        .SYNOPSIS
        Configure NTP settings for all VMware Aria Operations appliances to match SDDC Manager.

        .DESCRIPTION
        The Undo-vROPSNtpServer cmdlet removes any added NTP server(s) to all VMware Aria Operations appliances by
        returning their configuration to match that of SDDC Manager. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures all VMware Aria Operations appliances to the use NTP server(s) defined in SDDC Manager.

        .EXAMPLE
        Undo-vROPSNtpServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName xint-env
        This example configures the VMware Aria Operations appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use the NTP server(s) defined in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER environmentName
        The name of the environment to configure.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                            if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                Try {
                                    $productVM = (Get-vRSLCMProductNode -environmentName $environmentName -product vrops -ErrorAction Stop)[0] 
                                } Catch [System.Net.WebException] {
                                    $PSCmdlet.ThrowTerminatingError(
                                        [System.Management.Automation.ErrorRecord]::new(
                                            ([System.Management.Automation.GetValueException]"Retrieving VMware Aria Operations appliance information from VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"),
                                            'Get-vRSLCMProductNode',
                                            [System.Management.Automation.ErrorCategory]::ReadError,
                                            ""
                                        )
                                    )
                                }
                                $vropsRootPass = (Get-VCFCredential | Where-Object {$_.credentialType -eq "SSH" -and $_.resource.resourceType -eq "VROPS" -and $_.resource.resourceName -eq $productVM.hostName}).password
                                if ((Get-VM -Name $productVM.vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                    $ntpServers = (Get-VCFConfigurationNTP).ipAddress
                                    if ($ntpServers.count -eq 1) {
                                        $ntpServersJson = $ntpServers | ConvertTo-JSON
                                        $ntpServersJson = "[$ntpServersJson]" 
                                    } else {
                                        $ntpServersJson = $ntpServers | ConvertTo-JSON
                                        $ntpServersJson = $ntpServersJson -replace "`r`n","" -replace " ",""
                                    }
                                    $scriptCommand = "echo '$ntpServersJson' | python /usr/lib/vmware-casa/bin/ntp_update.py > /dev/null 2>&1"
                                    $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                    $scriptCommand = "python /usr/lib/vmware-casa/bin/ntp_list.py"
                                    $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vropsRootPass -Server $vcfVcenterDetails.fqdn
                                    $vropsNtpServers = ($output.ScriptOutput | ConvertFrom-JSON).time_servers
                                    $vropsNtpServerArray = @()
                                    foreach ($vropsNtpServer in $vropsNtpServers) {
                                        $vropsNtpServerArray += $vropsNtpServer.address
                                    }
                                    $compareArrays = Compare-Object -ReferenceObject $ntpServers -DifferenceObject $vropsNtpServerArray
                                    if (!$compareArrays) {
                                        Write-Output "Configuring VMware Aria Operations appliances to use NTP servers ($($ntpServers -Join ", ")): SUCCESSFUL"
                                    } else {
                                        Write-Output "Unable to validate VMware Aria Operations appliances were configured to use NTP servers ($($ntpServers -Join ", ")): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to locate a virtual machine named ($($productVM.vmName)) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                } 
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }  
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vROPSNtpServer

Function Set-vRADnsConfig {
    <#
        .SYNOPSIS
        Configure DNS Server and/or DNS search domains on VMware Aria Automation appliances.

        .DESCRIPTION
        The Set-vRADnsConfig cmdlet configures the DNS server and search domain details of all VMware Aria Automation
        appliances to the values passed as parameters. The cmdlet connects to SDDC Manager using the -server, -user,
        and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures all VMware Aria Automation appliance DNS configuration to the values passed to the function using
        -dnsServers and -dnsSearchDomains.

        .EXAMPLE
        Set-vRADnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -environmentName xint-env -dnsServers "172.16.11.4 172.17.11.4" -dnsSearchDomains rainpole.io
        This example configures the VMware Aria Automation appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use 172.16.11.4 and 172.17.11.4 as its DNS servers and rainpole.io as its search domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user to connect with.

        .PARAMETER vraPass
        The VMware Aria Automation password to connect with.

        .PARAMETER environmentName
        The VMware Aria Suite Lifecycle environment name.

        .PARAMETER dnsServers
        The DNS server(s) to configure the VMware Aria Automation appliances to use.

        .PARAMETER dnsSearchDomains
        The DNS search domain(s) to configure the VMware Aria Automation appliances to use.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsServers,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$dnsSearchDomains
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                        if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                            if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                                if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                                        if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                            Try {
                                                $productVMs = Get-vRSLCMProductNode -environmentName $environmentName -product vra -ErrorAction Stop
                                            } Catch [System.Net.WebException] {
                                                $PSCmdlet.ThrowTerminatingError(
                                                    [System.Management.Automation.ErrorRecord]::new(
                                                        ([System.Management.Automation.GetValueException]"Retrieving VMware Aria Automation appliance information from VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"),
                                                        'Get-vRSLCMProductNode',
                                                        [System.Management.Automation.ErrorCategory]::ReadError,
                                                        ""
                                                    )
                                                )
                                            }
                                            $vraRootPass = (Get-VCFCredential -ErrorAction Stop | Where-Object {$_.credentialType -eq "SSH" -and $_.resource.resourceType -eq "VRA" -and $_.resource.resourceName -match $productVMs[0].hostName}).password
                                            if ((Get-VM -Name $productVMs[0].vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                                if ($dnsServers) {
                                                    $scriptCommand = "cat /etc/resolv.conf"
                                                    $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn                                            
                                                    [Array]$dnsServersArray = $dnsServers.Split(" ")
                                                    $alreadyConfigured = @()
                                                    Foreach ($dnsServer in $dnsServersArray) {
                                                        if ($output.ScriptOutput -Match $dnsServer) {
                                                            $alreadyConfigured += $dnsServer
                                                        }
                                                    }                               
                                                    $compareArrays = Compare-Object -ReferenceObject $dnsServersArray -DifferenceObject $alreadyConfigured
                                                    if (!$compareArrays) {
                                                        Write-Warning "Configuring VMware Aria Automation appliances to use DNS Server(s) ($dnsServers) already done: SKIPPED"
                                                    } else {
                                                        $dnsServers = $dnsServers.Split(" ") -Join(",")
                                                        $scriptCommand = "vracli network dns set --servers $dnsServers"
                                                        $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                        $scriptCommand = "vracli network dns status"
                                                        $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                        [Array]$checkDns = $output.ScriptOutput
                                                        foreach ($item in $checkDns) {
                                                            $alreadyConfigured = @()
                                                            foreach ($dnsServer in $dnsServersArray) {
                                                                if ($item -Match $dnsServer) {
                                                                    $alreadyConfigured += $dnsServer
                                                                }
                                                            }
                                                        }
                                                        $compareArrays = Compare-Object -ReferenceObject $dnsServersArray -DifferenceObject $alreadyConfigured        
                                                        if ($compareArrays){
                                                            Write-Error "Unable to validate VMware Aria Automation appliances using DNS Server(s) ($dnsServers): POST_VALIDATION_FAILED"
                                                            Break
                                                        } else {
                                                            $dnsServersVracliValidated = $true
                                                            $scriptCommand = "cat /etc/resolv.conf"
                                                            $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn                                            
                                                            [Array]$dnsServersArray = $dnsServers.Split(",")
                                                            $alreadyConfigured = @()
                                                            Foreach ($dnsServer in $dnsServersArray) {
                                                                if ($output.ScriptOutput -Match $dnsServer) {
                                                                    $alreadyConfigured += $dnsServer
                                                                }
                                                            }                               
                                                            $compareArrays = Compare-Object -ReferenceObject $dnsServersArray -DifferenceObject $alreadyConfigured
                                                            if ($compareArrays) {
                                                                Write-Error "Configuring VMware Aria Automation appliances to use DNS Server(s) ($dnsServers): POST_VALIDATION_FAILED"
                                                                Break
                                                            } else {
                                                                $dnsServersResolvConfValidated = $true
                                                                Write-Output "Configuring VMware Aria Automation appliances to use DNS Server(s) ($dnsServers): SUCCESSFUL"
                                                            }
                                                        } 
                                                    }
                                                }
                                                if ($dnsSearchDomains) {
                                                    Foreach ($productVM in $productVMs) {
                                                        $scriptCommand = "cat /etc/resolv.conf"
                                                        $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                        if (($output.ScriptOutput).Contains("search $dnsSearchDomains")) {
                                                            Write-Warning "Configuring VMware Aria Automation appliance ($($productVM.vmName)) to use DNS search domain(s) ($dnsSearchDomains) already done: SKIPPED" 
                                                        } else {
                                                            $scriptCommand = "cat /etc/systemd/resolved.conf"
                                                            $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                            if (($output.ScriptOutput).Contains("#Domains")) {
                                                                $scriptCommand = "sed -i '/#Domains=/c\Domains=$dnsSearchDomains' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                                            } else {
                                                                $scriptCommand = "sed -i '/^Domains=/c\Domains=$dnsSearchDomains' /etc/systemd/resolved.conf | systemctl restart systemd-resolved"
                                                            } 
                                                            $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn   
                                                            $scriptCommand = "cat /etc/resolv.conf"
                                                            $output = Invoke-VMScript -VM $productVM.vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                            if (($output.ScriptOutput).Contains("search $dnsSearchDomains")) {
                                                                $dnsSearchDomainsResolvConfValidated = $true
                                                                Write-Output "Configuring VMware Aria Automation appliance ($($productVM.vmName)) to use DNS search domain(s) ($dnsSearchDomains): SUCCESSFUL" 
                                                            } else {
                                                                Write-Error "Configuring VMware Aria Automation appliance ($($productVM.vmName)) to use DNS search domain(s) ($dnsSearchDomains): POST_VALIDATION_FAILED"
                                                            }
                                                        }
                                                    }
                                                }
                                                if (($dnsServers -and $dnsServersVracliValidated -eq $true -and $dnsServersResolvConfValidated -eq $true) -or ($dnsSearchDomains -and $dnsSearchDomainsResolvConfValidated -eq $true)) {
                                                    Write-Output "Restarting VMware Aria Automation appliances and starting services upon bootup. This can take quite a while."
                                                    $scriptCommand = "/opt/scripts/svc-stop.sh"
                                                    $output = Invoke-VMScript -VM $productVM[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                    $scriptCommand = "/opt/scripts/deploy.sh --shutdown"
                                                    $output = Invoke-VMScript -VM $productVM[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                    Foreach ($productVM in $productVMs) {
                                                        Get-VM -Name $productVM.vmName | Restart-VMGuest | Out-Null
                                                    }
                                                    Start-Sleep -Seconds 15
                                                    Foreach ($productVM in $productVMs) {
                                                        Do {
                                                            $toolsStatus = (Get-VM -Name $productVM.vmName -ErrorAction SilentlyContinue).ExtensionData.Guest.ToolsRunningStatus
                                                            if ($toolsStatus -ne "guestToolsRunning") {
                                                                Start-Sleep -Seconds 15
                                                            }
                                                        }
                                                        Until ($toolsStatus -eq "guestToolsRunning")
                                                    }
                                                    Foreach ($productVM in $productVMs) {
                                                        Do {
                                                            $testvRA = Test-vRAConnection -server $productVM.hostname
                                                            if ($testvRA -eq $false) {
                                                                Start-Sleep -Seconds 15
                                                            }
                                                        }
                                                        Until ($testvRA -eq $true)
                                                    }
                                                    $scriptCommand = "ln -s /opt/vmware/bin/vamicli /usr/sbin/vamicli | /opt/scripts/deploy.sh"
                                                    $output = Invoke-VMScript -VM $productVM[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                    Do {
                                                        $checkVraAuth = Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass -ErrorAction SilentlyContinue
                                                        if ($checkVraAuth -eq $false) {
                                                            Start-Sleep -Seconds 60
                                                        }
                                                    }
                                                    Until ($checkVraAuth -eq $true)
                                                    $scriptCommand = "unlink /usr/sbin/vamicli"
                                                    $output = Invoke-VMScript -VM $productVM[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn

                                                }
                                            } else {
                                                Write-Error "Unable to locate a virtual machine named ($($productVM.vmName)) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                            } 
                                        }
                                    }  
                                    Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vRADnsConfig

Function Undo-vRADnsConfig {
    <#
        .SYNOPSIS
        Sets the DNS Server and/or DNS search domains on VMware Aria Automation appliances to match SDDC Manager.

        .DESCRIPTION
        The Undo-vROPSDnsConfig cmdlet configures the DNS server and search domain details of VMware Aria Automation
        appliances to the values stored in SDDC Manager. The cmdlet connects to SDDC Manager using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Retrieves the DNS server and search domain values from SDDC Manager
        - Configures VMware Aria Automation appliance DNS configuration to match the values retrieved from SDDC Manager

        .EXAMPLE
        Undo-vRADnsConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcManagerRootPass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -environmentName xint-env
        This example configures all VMware Aria Automation appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use values for DNS servers and search domains to the values stored in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER sddcManagerRootPass
        The root password to authenticate to SDDC Manager appliance. to connect with.

        .PARAMETER vraUser
        The VMware Aria Automation appliance user to connect with.

        .PARAMETER vraPass
        The VMware Aria Automation appliance password to connect with.

        .PARAMETER environmentName
        The VMware Aria Automation appliance environment name to connect with.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerRootPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $sddcManagerInstance = Get-VCFManager
                $sddcManagerVmName = $sddcManagerInstance.fqdn.Split(".")[0]
                $sddcManagerDnsServers = Get-VCFConfigurationDNS | Select-Object -ExpandProperty ipAddress
                if ($sddcManagerDnsServers.Count -gt 1) {
                    $sddcManagerDnsServers = $sddcManagerDnsServers -Join " "
                }
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass) {
                                if ($vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass) {
                                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                                        if (Test-vRSLCMConnection -server $vrslcmDetails.fqdn) {
                                            if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                                if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                                                    Try {
                                                        $sddcManagerSearchDomains = Get-VCFDnsSearchDomain -sddcManagerVmName $sddcManagerVmName -sddcManagerRootPass $sddcManagerRootPass -ErrorAction Stop                               
                                                    } Catch [System.Security.Authentication.InvalidCredentialException]{                                        
                                                        $PSCmdlet.ThrowTerminatingError($PSItem)
                                                    }
                                                    if (!$sddcManagerDnsServers -or !$sddcManagerSearchDomains) {
                                                        Write-Error "Unable to undo DNS configuration for VMware Aria Automation appliances: PRE_VALIDATION_FAILED"
                                                    } else {
                                                        Set-vRADnsConfig -server $server -user $user -pass $pass -vraUser $vraUser -vraPass $vraPass -environmentName $environmentName -dnsServers $sddcManagerDnsServers -dnsSearchDomains $sddcManagerSearchDomains -ErrorAction Stop
                                                    }                                    
                                                } else {
                                                    Write-Error "Unable connect to VMware Aria Automation appliances: PRE_VALIDATION_FAILED"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        } else {
                            Write-Error "Unable to locate a virtual machine named ($sddcManagerVmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRADnsConfig

Function Set-vRANtpConfig {
    <#
        .SYNOPSIS
        Configure NTP servers on VMware Aria Automation appliances.

        .DESCRIPTION
        The Set-vRANtpConfig cmdlet configures the NTP server details of all VMware Aria Automation appliances to the
        values passed as parameters. The cmdlet connects to SDDC Manager using the -server, -user, and -password
        values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures all VMware Aria Automation appliance NTP configuration to the values passed to the function using
        -ntpServers.

        .EXAMPLE
        Set-vRANtpConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -environmentName xint-env -ntpServers "ntp.sfo.rainpole.io ntp.lax.rainpole.io"
        This example configures the VMware Aria Automation appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use ntp.sfo.rainpole.io and ntp.lax.rainpole.io as their NTP servers.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username of the SDDC Manager instance.

        .PARAMETER pass
        The password of the SDDC Manager instance.

        .PARAMETER vraUser
        The username of the VMware Aria Automation appliance.

        .PARAMETER vraPass
        The password of the VMware Aria Automation appliance.

        .PARAMETER environmentName
        The name of the environment to configure.

        .PARAMETER ntpServers
        The NTP server(s) to configure on the VMware Aria Automation appliances.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ntpServers
    )

    [Array]$ntpServersArray = $ntpServers.Split(" ")
    foreach ($ntpServer in $ntpServersArray) {
        $testNtp = Test-NtpServer -Server $ntpServer
        if ($testNtp -eq $false) {
            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    ([System.Management.Automation.GetValueException]"Unable to confirm NTP server $ntpServer is valid: PRE_VALIDATION_FAILED"),
                    'Test-NtpServer',
                    [System.Management.Automation.ErrorCategory]::InvalidArgument,
                    ""
                )
            )
        }
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                        if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                            if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                                if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        $vrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop
                                        if (Test-vRSLCMAuthentication -server $vrslcmDetails.fqdn -user $vrslcmDetails.adminUser -pass $vrslcmDetails.adminPass) {
                                            Try {
                                                $productVMs = Get-vRSLCMProductNode -environmentName $environmentName -product vra -ErrorAction Stop
                                            } Catch [System.Net.WebException] {
                                                $PSCmdlet.ThrowTerminatingError(
                                                    [System.Management.Automation.ErrorRecord]::new(
                                                        ([System.Management.Automation.GetValueException]"Retrieving VMware Aria Automation appliance information from VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"),
                                                        'Get-vRSLCMProductNode',
                                                        [System.Management.Automation.ErrorCategory]::ReadError,
                                                        ""
                                                    )
                                                )
                                            }
                                            $vraRootPass = (Get-VCFCredential -ErrorAction Stop | Where-Object {$_.credentialType -eq "SSH" -and $_.resource.resourceType -eq "VRA" -and $_.resource.resourceName -match $productVMs[0].hostName}).password
                                            if ((Get-VM -Name $productVMs[0].vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                                $scriptCommand = "vracli ntp show-config"
                                                $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn                                            
                                                $outputComparison = (($output.ScriptOutput -Split "`n")[1]).Split("'") | Select-String -pattern "\w\.\w"
                                                if (!$outputComparison) {
                                                    $outputComparison = (($output.ScriptOutput -Split "`n")[1]).Split("'") | Select-String -pattern "\d{1,3}(\.\d{1,3}){3}"
                                                }
                                                $alreadyConfigured = @()
                                                Foreach ($ntpServer in $ntpServersArray) {
                                                    if ($outputComparison -Match $ntpServer) {
                                                        $alreadyConfigured += $ntpServer
                                                    }
                                                }
                                                if (($alreadyConfigured.Count -eq $outputComparison.Count) -and ($alreadyConfigured.Count -eq $ntpServersArray.Count) ) {
                                                    $compareArrays = Compare-Object -ReferenceObject $ntpServersArray -DifferenceObject $alreadyConfigured
                                                    if (!$compareArrays) {
                                                        Write-Warning "Configuring VMware Aria Automation appliances to use NTP Server(s) ($ntpServers) already done: SKIPPED"
                                                    } 
                                                } elseif ($compareArrays -or ($alreadyConfigured.Count -ne $outputComparison.Count) -or ($alreadyConfigured.Count -ne $ntpServersArray.Count)) {
                                                    if ($ntpServersArray.Count -gt 1){
                                                        [String]$ntpServersString = $null
                                                        Foreach ($ntpServer in $ntpServersArray) {
                                                            $ntpServersString = $ntpServersString+"'$($ntpServer)',"
                                                        }
                                                        $ntpServersString = $ntpServersString.Substring(0,$ntpServersString.Length-1)
                                                        $scriptCommand = "vracli ntp systemd --set $ntpServersString"
                                                    } else {
                                                        $scriptCommand = "vracli ntp systemd --set $ntpServers"
                                                    }
                                                    $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                    $scriptCommand = "vracli ntp show-config"
                                                    $output = Invoke-VMScript -VM $productVMs[0].vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $vraRootPass -Server $vcfVcenterDetails.fqdn
                                                    [Array]$ntpServersArray = $ntpServers.Split(" ")
                                                    $outputComparison = (($output.ScriptOutput -Split "`n")[1]).Split("'") | Select-String -pattern "\w\.\w"
                                                    if (!$outputComparison) {
                                                        $outputComparison = (($output.ScriptOutput -Split "`n")[1]).Split("'") | Select-String -pattern "\d{1,3}(\.\d{1,3}){3}"
                                                    }                                                    
                                                    $alreadyConfigured = @()
                                                    Foreach ($ntpServer in $ntpServersArray) {
                                                        if ($outputComparison -Match $ntpServer) {
                                                            $alreadyConfigured += $ntpServer
                                                        }
                                                    }
                                                    if ($alreadyConfigured.Count -eq $outputComparison.Count) {
                                                        $compareArrays = Compare-Object -ReferenceObject $ntpServersArray -DifferenceObject $alreadyConfigured
                                                        if ($compareArrays) {
                                                            Write-Error "Unable to configure VMware Aria Automation appliances to use NTP Server(s) ($ntpServers): POST_VALIDATION_FAILED"
                                                        } else {
                                                            Write-Output "Configuring VMware Aria Automation appliances to use NTP Server(s) ($ntpServers): SUCCESSFUL"
                                                        }
                                                    }
                                                }
                                            } else {
                                                Write-Error "Unable to locate a virtual machine named ($($productVM.vmName)) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"
                                            } 
                                        }
                                    }  
                                    Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vRANtpConfig

Function Undo-vRANtpConfig {
    <#
        .SYNOPSIS
        Configure NTP settings for all VMware Aria Automation appliances to match SDDC Manager.

        .DESCRIPTION
        The Undo-vRANtpServer cmdlet removes any added NTP server(s) on all VMware Aria Automation appliances by
        returning their configuration to match that of SDDC Manager. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Configures all VMware Aria Automation appliances to the use NTP server(s) defined in SDDC Manager.

        .EXAMPLE
        Undo-vRANtpServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -environmentName xint-env
        This example configures the VMware Aria Automation appliances managed by SDDC Manager sfo-vcf01.sfo.rainpole.io to use the NTP server(s) defined in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user account used to connect to the VMware Aria Automation API.

        .PARAMETER vraPass
        The VMware Aria Automation user account password used to connect to the VMware Aria Automation API.

        .PARAMETER environmentName
        The VMware Aria Automation environment name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $ntpServers = (Get-VCFConfigurationNTP).ipAddress
                [String]$ntpServersString = $null
                if ($ntpServers.count -gt 1) {
                    Foreach ($ntpServer in $ntpServers) {
                        $ntpServersString = $ntpServersString + "$ntpServer "
                    }
                    $ntpServersString = $ntpServersString.Substring(0,$ntpServersString.Length-1)
                } else {
                    $ntpServersString = $ntpServers
                }
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            Try {
                                Set-vRANtpConfig -server $server -user $user -pass $pass -vraUser $vraUser -vraPass $vraPass -environmentName $environmentName -ntpServers $ntpServersString -ErrorAction Stop
                            } Catch {
                                $PSCmdlet.ThrowTerminatingError($PSItem)
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRANtpConfig

Function Add-SrmMapping {
    <#
        .SYNOPSIS
        Create a mapping between objects (folder, network, or compute resource) in the protected and failover VCF
        instances in Site Recovery Manager.

        .DESCRIPTION
        The Add-SrmMapping cmdlet creates a mapping between objects (folder, network, or compute resource) in the
        protected and failover instances in Site Recovery Manager. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to both SDDC Manager instances
        - Validates that network connectivity and authentication is possible to both vCenter Server instances
        - Validates that network connectivity and authentication are possible to both Site Recovery Manager instances
        - Create a mapping between objects in the protected and failover instances in Site Recovery Manager as
        defined by the -type, -protected, and -recovery parameters.

        .EXAMPLE
        Add-SrmMapping -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -type Folder -protected xint-m01-fd-vrslcm -recovery xint-m01-fd-vrslcm
        This example creates a mapping between protected site folder xint-m01-fd-vrslcm01 and recovery site folder xint-m01-fd-vrslcm01 in Site Recovery Manager.
        
        .EXAMPLE
        Add-SrmMapping -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -type Network -protected xint-m01-seg01 -recovery xint-m01-seg01
        This example creates a mapping between protected site network xint-m01-seg01 and recovery site network xint-m01-seg01 in Site Recovery Manager.
        
        .EXAMPLE
        Add-SrmMapping -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -type Resource -protected sfo-m01-cl01 -recovery lax-m01-cl01
        This example creates a mapping between protected site compute resource vSphere Cluster sfo-m01-cl01 and recovery site compute resource vSphere Cluster lax-m01-cl01 in Site Recovery Manager.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager. managing the protected site.

        .PARAMETER sddcManagerAUser
        The username of the SDDC Manager instance managing the protected site.

        .PARAMETER sddcManagerAPass
        The password of the SDDC Manager instance managing the protected site.

        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager. managing the recovery site.

        .PARAMETER sddcManagerBUser
        The username of the SDDC Manager instance managing the recovery site.

        .PARAMETER sddcManagerBPass
        The password of the SDDC Manager instance managing the recovery site.

        .PARAMETER type
        The type of object to be mapped between the protected and recovery sites. Valid values are Folder, Network, or Resource.

        .PARAMETER protected
        The name of the object to be mapped in the protected site.

        .PARAMETER recovery
        The name of the object to be mapped in the recovery site.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateSet("Folder","Network","Resource")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$protected,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$recovery
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $global:DefaultSrmServers = $null
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $srmBFqdn)) {
                                                    if (Test-SrmAuthentication -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass) {
                                                        $siteASrmServer = $global:DefaultSrmServers | Where-Object {$_.Name -match $srmAFqdn}
                                                        if ($type -eq "Folder") {
                                                            Try {
                                                                $protectedMoRef = (Get-Folder -Server $siteAvCenterDetails.fqdn -Name $protected -ErrorAction Stop | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}).id
                                                                $recoveryMoRef = (Get-Folder -Server $siteBvCenterDetails.fqdn -Name $recovery -ErrorAction Stop | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}).id
                                                                $existingSiteAMappings = $siteASrmServer.extensionData.InventoryMapping.GetFolderMappings()    
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Network") {
                                                            Try {
                                                                $protectedMoRef = (Get-VirtualNetwork -Server $siteAvCenterDetails.fqdn -Name $protected -ErrorAction Stop | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}).id
                                                                $recoveryMoRef = (Get-VirtualNetwork -Server $siteBvCenterDetails.fqdn -Name $recovery -ErrorAction Stop | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}).id  
                                                                $existingSiteAMappings = $siteASrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Resource") {
                                                            Try {
                                                                $protectedCluster = Get-Cluster -Server $SiteAvCenterDetails.fqdn -Name $protected -ErrorAction SilentlyContinue | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}
                                                                if ($protectedCluster) {
                                                                    $protectedMoRef = ($protectedCluster | Get-ResourcePool -Name "Resources").id
                                                                } else {
                                                                    $protectedMoRef = (Get-ResourcePool -Server $siteAvCenterDetails.fqdn -Name $protected -ErrorAction Stop | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}).id
                                                                }
                                                                $recoveryCluster = Get-Cluster -Server $SiteBvCenterDetails.fqdn -Name $recovery -ErrorAction SilentlyContinue | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}
                                                                if ($recoveryCluster) {
                                                                    $recoveryMoRef = ($recoveryCluster | Get-ResourcePool -Name "Resources").id
                                                                } else {
                                                                    $recoveryMoRef = (Get-ResourcePool -Server $siteBvCenterDetails.fqdn -Name $recovery -ErrorAction Stop | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}).id
                                                                }
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                            $existingSiteAMappings = $siteASrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()
                                                        }
                                                        if ($existingSiteAMappings) {
                                                            $forwardMappingExists = $null
                                                            foreach ($existingSiteAMapping in $existingSiteAMappings) {
                                                                if (($protectedMoRef -match $existingSiteAMapping.primaryObject.Value) -and ($recoveryMoRef -match $existingSiteAMapping.secondaryObject.Value)) {
                                                                    $forwardMappingExists = $true
                                                                }
                                                            }
                                                        }
                                                        if (!$forwardMappingExists) {
                                                            if ($type -eq "Folder") {
                                                                Try {
                                                                    $SiteASrmServer.extensionData.InventoryMapping.AddFolderMapping($protectedMoRef,$recoveryMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteAMappings = $SiteASrmServer.extensionData.InventoryMapping.GetFolderMappings()
                                                            } elseif ($type -eq "Network") {
                                                                Try {
                                                                    $SiteASrmServer.extensionData.InventoryMapping.AddNetworkMapping($protectedMoRef,$recoveryMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteAMappings = $SiteASrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } elseif ($type -eq "Resource") {
                                                                Try {
                                                                    $SiteASrmServer.extensionData.InventoryMapping.AddResourcePoolMapping($protectedMoRef,$recoveryMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteAMappings = $SiteASrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()
                                                            }
                                                            $forwardMappingValidated = $null
                                                            Foreach ($validateSiteAMapping in $validateSiteAMappings) {
                                                                if (($protectedMoRef -match $validateSiteAMapping.primaryObject.Value) -and ($recoveryMoRef -match $validateSiteAMapping.secondaryObject.Value)) {
                                                                    $forwardMappingValidated = $true
                                                                }
                                                            }
                                                            if ($forwardMappingValidated -eq $true) {
                                                                Write-Output "Create $type mapping between protected $type ($protected) and recovery $type ($recovery): SUCCESSFUL"
                                                            } else {
                                                                $PSCmdlet.ThrowTerminatingError(
                                                                    [System.Management.Automation.ErrorRecord]::new(
                                                                        ([System.Management.Automation.GetValueException]"Create $type mapping between protected $type ($protected) and recovery $type ($recovery): POST_VALIDATION_FAILED"),
                                                                        'Add-SrmMapping',
                                                                        [System.Management.Automation.ErrorCategory]::ObjectNotFound,
                                                                        ""
                                                                    )
                                                                )
                                                            }
                                                        } else {
                                                            Write-Warning "$type mapping between protected $type ($protected) and recovery $type ($recovery) already exists: SKIPPING"
                                                        }
                                                        Disconnect-SrmServer -Server $srmAFqdn -Confirm:$False
                                                    }
                                                    if (Test-SrmAuthentication -server $srmBFqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass -remoteUser $siteAvCenterDetails.ssoAdmin -remotePass $siteAvCenterDetails.ssoAdminPass) {
                                                        $siteBSrmServer = $global:DefaultSrmServers | Where-Object {$_.Name -match $srmBFqdn}
                                                        if ($type -eq "Folder") {
                                                            Try {
                                                                $existingSiteBMappings = $siteBSrmServer.extensionData.InventoryMapping.GetFolderMappings()    
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Network") {
                                                            Try {
                                                                $existingSiteBMappings = $siteBSrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Resource") {
                                                            Try {
                                                                $existingSiteBMappings = $siteBSrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()   
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        }
                                                        if ($existingSiteBMappings) {
                                                            $reverseMappingExists = $null
                                                            Foreach ($existingSiteBMapping in $existingSiteBMappings) {
                                                                if (($recoveryMoRef -match $existingSiteBMapping.primaryObject.Value) -and ($protectedMoRef -match $existingSiteBMapping.secondaryObject.Value)) {
                                                                    $reverseMappingExists = $true
                                                                }
                                                            }
                                                        }  
                                                        if (!$reverseMappingExists) {
                                                            if ($type -eq "Folder") {
                                                                Try {
                                                                    $SiteBSrmServer.extensionData.InventoryMapping.AddFolderMapping($recoveryMoRef,$protectedMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteBMappings = $SiteBSrmServer.extensionData.InventoryMapping.GetFolderMappings()
                                                            } elseif ($type -eq "Network") {
                                                                Try {
                                                                    $SiteBSrmServer.extensionData.InventoryMapping.AddNetworkMapping($recoveryMoRef,$protectedMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteBMappings = $SiteBSrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } elseif ($type -eq "Resource") {
                                                                Try {
                                                                    $SiteBSrmServer.extensionData.InventoryMapping.AddResourcePoolMapping($recoveryMoRef,$protectedMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteBMappings = $SiteBSrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()
                                                            }
                                                            $reverseMappingValidated = $null
                                                            Foreach ($validateSiteBMapping in $validateSiteBMappings) {
                                                                if (($recoveryMoRef -match $validateSiteBMapping.primaryObject.Value) -and ($protectedMoRef -match $validateSiteBMapping.secondaryObject.Value)) {
                                                                    $reverseMappingValidated = $true
                                                                }
                                                            }
                                                            if ($reverseMappingValidated -eq $true) {
                                                                Write-Output "Create $type mapping between recovery $type ($recovery) and protected $type ($protected): SUCCESSFUL"
                                                            } else {
                                                                $PSCmdlet.ThrowTerminatingError(
                                                                    [System.Management.Automation.ErrorRecord]::new(
                                                                        ([System.Management.Automation.GetValueException]"Create $type mapping between recovery $type ($recovery) and protected $type ($protected): POST_VALIDATION_FAILED"),
                                                                        'Add-SrmMapping',
                                                                        [System.Management.Automation.ErrorCategory]::ObjectNotFound,
                                                                        ""
                                                                    )
                                                                )
                                                            }
                                                        } else {
                                                            Write-Warning "$type mapping between recovery $type ($recovery) and protected $type ($protected) already exists: SKIPPING"
                                                        }
                                                        Disconnect-SrmServer -Server $srmBFqdn -Confirm:$false
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-SrmMapping

Function Undo-SrmMapping {
    <#
        .SYNOPSIS
        Remove a mapping between objects (folder, network, or compute resource) in the protected and failover VCF
        instances in Site Recovery Manager.

        .DESCRIPTION
        The Undo-SrmMapping cmdlet removes a mapping between objects (folder, network, or compute resource) in the
        protected and failover instances in Site Recovery Manager. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to both SDDC Manager instances
        - Validates that network connectivity and authentication is possible to both vCenter Server instances
        - Validates that network connectivity and authentication are possible to both Site Recovery Manager instances
        - Removes a mapping between objects in the protected and failover instances in Site Recovery Manager as
        defined by the -type, -protected, and -recovery parameters.

        .EXAMPLE
        Undo-SrmMapping -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -type Folder -protected xint-m01-fd-vrslcm -recovery xint-m01-fd-vrslcm
        This example removes a mapping between protected site folder xint-m01-fd-vrslcm01 and recovery site folder xint-m01-fd-vrslcm01 in Site Recovery Manager.
        
        .EXAMPLE
        Undo-SrmMapping -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -type Network -protected xint-m01-seg01 -recovery xint-m01-seg01
        This example removes a mapping between protected site network xint-m01-seg01 and recovery site network xint-m01-seg01 in Site Recovery Manager.
        
        .EXAMPLE
        Undo-SrmMapping -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -type Resource -protected sfo-m01-cl01 -recovery lax-m01-cl01
        This example removes a mapping between protected site compute resource vSphere Cluster sfo-m01-cl01 and recovery site compute resource vSphere Cluster lax-m01-cl01 in Site Recovery Manager.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager. managing the protected site.

        .PARAMETER sddcManagerAUser
        The user name of the SDDC Manager instance managing the protected site.

        .PARAMETER sddcManagerAPass
        The password of the SDDC Manager instance managing the protected site.

        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager. managing the recovery site.

        .PARAMETER sddcManagerBUser
        The user name of the SDDC Manager instance managing the recovery site.

        .PARAMETER sddcManagerBPass
        The password of the SDDC Manager instance managing the recovery site.

        .PARAMETER type
        The type of object to be mapped between the protected and recovery sites. Valid values are Folder, Network, or Resource.

        .PARAMETER protected
        The name of the object to be mapped in the protected site.

        .PARAMETER recovery
        The name of the object to be mapped in the recovery site.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateSet("Folder","Network","Resource")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$protected,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$recovery
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $global:DefaultSrmServers = $null
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $srmBFqdn)) {
                                                    if (Test-SrmAuthentication -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass) {
                                                        $siteASrmServer = $global:DefaultSrmServers | Where-Object {$_.Name -match $srmAFqdn}
                                                        if ($type -eq "Folder") {
                                                            Try {
                                                                $protectedMoRef = (Get-Folder -Server $siteAvCenterDetails.fqdn -Name $protected -ErrorAction Stop | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}).id
                                                                $recoveryMoRef = (Get-Folder -Server $siteBvCenterDetails.fqdn -Name $recovery -ErrorAction Stop | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}).id
                                                                $existingSiteAMappings = $siteASrmServer.extensionData.InventoryMapping.GetFolderMappings()    
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Network") {
                                                            Try {
                                                                $protectedMoRef = (Get-VirtualNetwork -Server $siteAvCenterDetails.fqdn -Name $protected -ErrorAction Stop | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}).id
                                                                $recoveryMoRef = (Get-VirtualNetwork -Server $siteBvCenterDetails.fqdn -Name $recovery -ErrorAction Stop | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}).id  
                                                                $existingSiteAMappings = $siteASrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Resource") {
                                                            Try {
                                                                $protectedCluster = Get-Cluster -Server $SiteAvCenterDetails.fqdn -Name $protected -ErrorAction SilentlyContinue | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}
                                                                if ($protectedCluster) {
                                                                    $protectedMoRef = ($protectedCluster | Get-ResourcePool -Name "Resources").id
                                                                } else {
                                                                    $protectedMoRef = (Get-ResourcePool -Server $siteAvCenterDetails.fqdn -Name $protected -ErrorAction Stop | Where-Object {$_.Uid -match $siteAvCenterDetails.fqdn}).id
                                                                }
                                                                $recoveryCluster = Get-Cluster -Server $SiteBvCenterDetails.fqdn -Name $recovery -ErrorAction SilentlyContinue | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}
                                                                if ($recoveryCluster) {
                                                                    $recoveryMoRef = ($recoveryCluster | Get-ResourcePool -Name "Resources").id
                                                                } else {
                                                                    $recoveryMoRef = (Get-ResourcePool -Server $siteBvCenterDetails.fqdn -Name $recovery -ErrorAction Stop | Where-Object {$_.Uid -match $siteBvCenterDetails.fqdn}).id
                                                                }
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                            $existingSiteAMappings = $siteASrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()
                                                        }
                                                        if ($existingSiteAMappings) {
                                                            $forwardMappingExists = $null
                                                            Foreach ($existingSiteAMapping in $existingSiteAMappings) {
                                                                if (($protectedMoRef -match $existingSiteAMapping.primaryObject.Value) -and ($recoveryMoRef -match $existingSiteAMapping.secondaryObject.Value)) {
                                                                    $forwardMappingExists = $true
                                                                }
                                                            }
                                                        }
                                                        if ($forwardMappingExists -eq $true) {
                                                            if ($type -eq "Folder") {
                                                                Try {
                                                                    $SiteASrmServer.extensionData.InventoryMapping.RemoveFolderMapping($protectedMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteAMappings = $SiteASrmServer.extensionData.InventoryMapping.GetFolderMappings()
                                                            } elseif ($type -eq "Network") {
                                                                Try {
                                                                    $SiteASrmServer.extensionData.InventoryMapping.RemoveNetworkMapping($protectedMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteAMappings = $SiteASrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } elseif ($type -eq "Resource") {
                                                                Try {
                                                                    $SiteASrmServer.extensionData.InventoryMapping.RemoveResourcePoolMapping($protectedMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteAMappings = $SiteASrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()
                                                            }
                                                            $forwardMappingValidated = $null
                                                            Foreach ($validateSiteAMapping in $validateSiteAMappings) {
                                                                if (($protectedMoRef -match $validateSiteAMapping.primaryObject.Value) -and ($recoveryMoRef -match $validateSiteAMapping.secondaryObject.Value)) {
                                                                    $forwardMappingValidated = $true
                                                                }
                                                            }
                                                            if (!$forwardMappingValidated) {
                                                                Write-Output "Remove $type mapping between protected $type ($protected) and recovery $type ($recovery): SUCCESSFUL"
                                                            } else {
                                                                $PSCmdlet.ThrowTerminatingError(
                                                                    [System.Management.Automation.ErrorRecord]::new(
                                                                        ([System.Management.Automation.GetValueException]"Remove $type mapping between protected $type ($protected) and recovery $type ($recovery): POST_VALIDATION_FAILED"),
                                                                        'Add-SrmMapping',
                                                                        [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                        ""
                                                                    )
                                                                )
                                                            }
                                                        } else {
                                                            Write-Warning "$type mapping between protected $type ($protected) and recovery $type ($recovery) does not exist: SKIPPING"
                                                        }
                                                        Disconnect-SrmServer -Server $srmAFqdn -Confirm:$False
                                                    }
                                                    if (Test-SrmAuthentication -server $srmBFqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass -remoteUser $siteAvCenterDetails.ssoAdmin -remotePass $siteAvCenterDetails.ssoAdminPass) {
                                                        $siteBSrmServer = $global:DefaultSrmServers | Where-Object {$_.Name -match $srmBFqdn}
                                                        if ($type -eq "Folder") {
                                                            Try {
                                                                $existingSiteBMappings = $siteBSrmServer.extensionData.InventoryMapping.GetFolderMappings()    
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Network") {
                                                            Try {
                                                                $existingSiteBMappings = $siteBSrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        } elseif ($type -eq "Resource") {
                                                            Try {
                                                                $existingSiteBMappings = $siteBSrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()   
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        }
                                                        if ($existingSiteBMappings) {
                                                            $reverseMappingExists = $null
                                                            Foreach ($existingSiteBMapping in $existingSiteBMappings) {
                                                                if (($recoveryMoRef -match $existingSiteBMapping.primaryObject.Value) -and ($protectedMoRef -match $existingSiteBMapping.secondaryObject.Value)) {
                                                                    $reverseMappingExists = $true
                                                                }
                                                            }
                                                        }  
                                                        if ($reverseMappingExists -eq $true) {
                                                            if ($type -eq "Folder") {
                                                                Try {
                                                                    $SiteBSrmServer.extensionData.InventoryMapping.RemoveFolderMapping($recoveryMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteBMappings = $SiteBSrmServer.extensionData.InventoryMapping.GetFolderMappings()
                                                            } elseif ($type -eq "Network") {
                                                                Try {
                                                                    $SiteBSrmServer.extensionData.InventoryMapping.RemoveNetworkMapping($recoveryMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteBMappings = $SiteBSrmServer.extensionData.InventoryMapping.GetNetworkMappings()
                                                            } elseif ($type -eq "Resource") {
                                                                Try {
                                                                    $SiteBSrmServer.extensionData.InventoryMapping.RemoveResourcePoolMapping($recoveryMoRef)
                                                                } Catch {
                                                                    $PSCmdlet.ThrowTerminatingError($PSItem)
                                                                }
                                                                $validateSiteBMappings = $SiteBSrmServer.extensionData.InventoryMapping.GetResourcePoolMappings()
                                                            }
                                                            $reverseMappingValidated = $null
                                                            Foreach ($validateSiteBMapping in $validateSiteBMappings) {
                                                                if (($recoveryMoRef -match $validateSiteBMapping.primaryObject.Value) -and ($protectedMoRef -match $validateSiteBMapping.secondaryObject.Value)) {
                                                                    $reverseMappingValidated = $true
                                                                }
                                                            }
                                                            if (!$reverseMappingValidated) {
                                                                Write-Output "Remove $type mapping between recovery $type ($recovery) and protected $type ($protected): SUCCESSFUL"
                                                            } else {
                                                                $PSCmdlet.ThrowTerminatingError(
                                                                    [System.Management.Automation.ErrorRecord]::new(
                                                                        ([System.Management.Automation.GetValueException]"Remove $type mapping between recovery $type ($recovery) and protected $type ($protected): POST_VALIDATION_FAILED"),
                                                                        'Add-SrmMapping',
                                                                        [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                        ""
                                                                    )
                                                                )
                                                            }
                                                        } else {
                                                            Write-Warning "$type mapping between recovery $type ($recovery) and protected $type ($protected) does not exist: SKIPPING"
                                                        }
                                                        Disconnect-SrmServer -Server $srmBFqdn -Confirm:$false
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SrmMapping

Function New-SrmSitePair {
    <#
        .SYNOPSIS
        Create a site pair between Site Recovery Manager instances.

        .DESCRIPTION
        The New-SrmSitePair cmdlet creates a site pair between Site Recovery Manager instances. The cmdlet connects to
        SDDC Manager in both the protected and recovery sites using the -sddcManagerAFqdn, -sddcManagerAUser,
        -sddcManagerAPass, -sddcManagerBFqdn, -sddcManagerBUser, and -sddcManagerBPass values:
        - Validates that network connectivity and authentication is possible to both SDDC Manager instances
        - Validates that network connectivity and authentication is possible to both vCenter Server instances
        - Validates that network connectivity and authentication are possible to both Site Recovery Manager instances
        - Create a site pair between the Site Recovery Manager instances integrated with their respective vCenter
        Server instances.

        .EXAMPLE
        New-SrmSitePair -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1!
        This example creates a site pair between Site Recovery Manager instances integrated with the management vCenter Server instance in each site.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager. in the protected site.

        .PARAMETER sddcManagerAUser
        The user name of the SDDC Manager instance in the protected site.

        .PARAMETER sddcManagerAPass
        The password of the SDDC Manager instance in the protected site.

        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager. in the recovery site.

        .PARAMETER sddcManagerBUser
        The user name of the SDDC Manager instance in the recovery site.

        .PARAMETER sddcManagerBPass
        The password of the SDDC Manager instance in the recovery site.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $global:DefaultSrmServers = $null
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $srmBFqdn)) {
                                                    if (Test-SrmAuthentication -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                                                        if (Test-SrmAuthentication -server $srmBFqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                            Try {
                                                                $existingSitePair = $null
                                                                $getPairedSite = '$global:DefaultSrmServers[1].ExtensionData.GetPairedSite()'
                                                                $existingSitePair = Invoke-Expression $getPairedSite -ErrorAction SilentlyContinue
                                                            } Catch {
                                                            }
                                                            if ($existingSitePair.VcHost -eq $siteBvCenterDetails.fqdn) {
                                                                Write-Warning "Create Site Recovery Manager pair between local server $($srmAFqdn.Split(".")[0]) and remote server $($srmBFqdn.Split(".")[0]) already done: SKIPPING"
                                                                Break
                                                            }
                                                            $creds = @{
                                                                user = $siteBvCenterDetails.ssoAdmin
                                                                password = $siteBvCenterDetails.ssoAdminPass
                                                            }
                                                            $thumbprints = $global:DefaultSrmServers[1].ExtensionData.ProbeSsl($siteBvCenterDetails.fqdn)
                                                            $connectionSpec = @{
                                                                host = $siteBvCenterDetails.fqdn
                                                                thumbprints = $thumbprints
                                                                creds = $creds
                                                            }
                                                            Try {
                                                                $global:DefaultSrmServers[1].ExtensionData.PairSrm_Task($connectionSpec) | Out-Null
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                            Try {
                                                                Start-Sleep -Seconds 5
                                                                $existingSitePair = $null
                                                                $getPairedSite = '$global:DefaultSrmServers[1].ExtensionData.GetPairedSite()'
                                                                $existingSitePair = Invoke-Expression $getPairedSite -ErrorAction SilentlyContinue
                                                                if ($existingSitePair.VcHost -eq $siteBvCenterDetails.fqdn) {
                                                                    Write-Output "Create Site Recovery Manager pair between local server $($srmAFqdn.Split(".")[0]) and remote server $($srmBFqdn.Split(".")[0]) : SUCCESSFUL"
                                                                } else {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                        ([System.Management.Automation.GetValueException]"Create Site Recovery Manager pair between local server $($srmAFqdn.Split(".")[0]) and remote server $($srmBFqdn.Split(".")[0]): POST_VALIDATION_FAILED"),
                                                                            'New-SrmSitePair',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                }
                                                            } Catch {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-SrmSitePair

Function Undo-SrmSitePair {
    <#
        .SYNOPSIS
        Removes an existing site pair between Site Recovery Manager instances.

        .DESCRIPTION
        The Undo-SrmSitePair cmdlet removes an existing site pair between Site Recovery Manager instances. The cmdlet
        connects to SDDC Manager in both the protected and recovery sites using the -sddcManagerAFqdn,
        -sddcManagerAUser, -sddcManagerAPass, -sddcManagerBFqdn, -sddcManagerBUser, and -sddcManagerBPass values:
        - Validates that network connectivity and authentication is possible to both SDDC Manager instances
        - Validates that network connectivity and authentication is possible to both vCenter Server instances
        - Validates that network connectivity and authentication are possible to both Site Recovery Manager instances
        - Removes an existing site pair between the Site Recovery Manager instances integrated with their respective
        vCenter Server instances.

        .EXAMPLE
        Undo-SrmSitePair -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1 -sddcManagerBFqdn lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1!
        This example removes a site pair between Site Recovery Manager instances integrated with the management vCenter Server instance in each site.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager. in the protected site.

        .PARAMETER sddcManagerAUser
        The user name of the SDDC Manager instance in the protected site.

        .PARAMETER sddcManagerAPass
        The password of the SDDC Manager instance in the protected site.

        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager. in the recovery site.

        .PARAMETER sddcManagerBUser
        The user name of the SDDC Manager instance in the recovery site.

        .PARAMETER sddcManagerBPass
        The password of the SDDC Manager instance in the recovery site.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $global:DefaultSrmServers = $null
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $srmBFqdn)) {
                                                    if (Test-SrmAuthentication -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                                                        Try {
                                                            $existingSitePair = $null
                                                            $getPairedSite = '$global:DefaultSrmServers[0].ExtensionData.GetPairedSite()'
                                                            $existingSitePair = Invoke-Expression $getPairedSite -ErrorAction SilentlyContinue
                                                        } Catch {
                                                            if (!$existingSitePair) {
                                                                Write-Warning "Site Recovery Manager pair between local server $($srmAFqdn.Split(".")[0]) and remote server $($srmBFqdn.Split(".")[0]) does not exist: SKIPPING"
                                                                Break
                                                            } else {
                                                                $PSCmdlet.ThrowTerminatingError($PSItem)
                                                            }
                                                        }
                                                        Try {
                                                            $global:DefaultSrmServers[0].ExtensionData.BreakPairing_Task($existingSitePair) | Out-Null
                                                        } Catch {
                                                            $PSCmdlet.ThrowTerminatingError($PSItem)
                                                        }
                                                        Try {
                                                            Start-Sleep -Seconds 5
                                                            $existingSitePair = $null
                                                            $getPairedSite = '$global:DefaultSrmServers[0].ExtensionData.GetPairedSite()'
                                                            $existingSitePair = Invoke-Expression $getPairedSite -ErrorAction SilentlyContinue
                                                            else {
                                                                $PSCmdlet.ThrowTerminatingError(
                                                                    [System.Management.Automation.ErrorRecord]::new(
                                                                    ([System.Management.Automation.GetValueException]"Remove Site Recovery Manager pair between local server $($srmAFqdn.Split(".")[0]) and remote server $($srmBFqdn.Split(".")[0]): POST_VALIDATION_FAILED"),
                                                                        'New-SrmSitePair',
                                                                        [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                        ""
                                                                    )
                                                                )
                                                            }
                                                        } Catch {
                                                            if (!$existingSitePair) {
                                                                Write-Output "Remove Site Recovery Manager pair between local server $($srmAFqdn.Split(".")[0]) and remote server $($srmBFqdn.Split(".")[0]) : SUCCESSFUL"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SrmSitePair

Function Add-EsxiVrmsVMkernelPort {
    <#
        .SYNOPSIS
        Create a VMkernel port on ESXi hosts.

        .DESCRIPTION
        The Add-EsxiVrmsVMkernelPort cmdlet creates a VMkernel port on each ESXi host for vSphere Replication traffic. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Creates a VMkernel port on each ESXi host for vSphere Replication traffic

        .EXAMPLE
        Add-EsxiVrmsVMkernelPort -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -portgroup sfo-m01-cl01-vds01-pg-vrms -netmask 255.255.255.0 -ipAddresses @("172.27.15.101","172.27.15.102","172.27.15.103","172.27.15.104")
        This example creates a VMkernel port for each ESXi host Management Domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER portgroup
        The vSphere Distributed Port Group name.

        .PARAMETER netmask
        The subnet mask for the VMkernel port.

        .PARAMETER ipAddresses
        The IP addresses for the VMkernel port.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$portgroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$netmask,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$ipAddresses
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}) {
                                $vdswitchName = (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}).VDSwitch.Name
                                $esxiHosts = Get-VCFHost | Where-Object {$_.cluster.id -eq ((Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain -and $_.vcenters.fqdn -eq $vcfVcenterDetails.fqdn}).clusters.id)}
                                if ($esxiHosts.Count -eq $ipAddresses.Count) {
                                    if ((Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VirtualSwitch $vdswitchName -PortGroup $portgroup | Where-Object {$_.VSphereReplicationEnabled -eq $true -and $_.VSphereReplicationNfcEnabled -eq $true}) -ne $esxiHosts.Count) {
                                        For ($i=0; $i -lt $esxiHosts.Count; $i++) {
                                            if (!(Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VMHost $esxiHosts.fqdn[$i] | Where-Object {$_.vSphereReplicationEnabled -eq $true})) {
                                                New-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VMHost $esxiHosts.fqdn[$i] -VirtualSwitch $vdswitchName -PortGroup $portgroup -ErrorAction Stop | Set-VMHostNetworkAdapter -IP $ipAddresses[$i] -SubnetMask $netmask -vSphereReplicationEnabled:$true -vSphereReplicationNfcEnabled:$true -Confirm:$false -ErrorAction Stop | Out-Null
                                            }
                                        }
                                        $validateVMkernelCreated = Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VirtualSwitch $vdswitchName -PortGroup $portgroup | Where-Object {$_.VSphereReplicationEnabled -eq $true -and $_.VSphereReplicationNfcEnabled -eq $true}
                                        if ($validateVMkernelCreated.Count -eq $esxiHosts.Count) {
                                            Write-Output "Creating VMkernel Ports for vSphere Replication traffic on all ESXi hosts in Workload Domain ($domain): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating VMkernel Ports for vSphere Replication traffic on all ESXi hosts in Workload Domain ($domain): POST_VALIDATED_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Creating VMkernel Ports for vSphere Replication traffic on all ESXi hosts in Workload Domain ($domain), already created: SKIPPED"
                                    }
                                } else {
                                    Write-Error "The number of IP addresses supplied do not match the number if ESXi hosts in Workload Domain ($domain): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to find vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($portgroup): PRE_VALIDATION_FAILED"
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-EsxiVrmsVMkernelPort

Function Undo-EsxiVrmsVMkernelPort {
    <#
        .SYNOPSIS
        Removes VMkernel ports on ESXi hosts.

        .DESCRIPTION
        The Undo-EsxiVrmsVMkernelPort cmdlet removes the VMkernel port on each ESXi host for vSphere Replication traffic. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Removes a VMkernel port on each ESXi host for vSphere Replication traffic

        .EXAMPLE
        Undo-EsxiVrmsVMkernelPort -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -portgroup sfo-m01-cl01-vds01-pg-vrms
        This example removes a VMkernel from each ESXi host Management Domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER portgroup
        The vSphere Distributed Port Group name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$portgroup
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}) {
                                $vdswitchName = (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}).VDSwitch.Name
                                $esxiHosts = Get-VCFHost | Where-Object {$_.cluster.id -eq ((Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain -and $_.vcenters.fqdn -eq $vcfVcenterDetails.fqdn}).clusters.id)}
                                
                                if (!(Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VirtualSwitch $vdswitchName -PortGroup $portgroup | Where-Object {$_.VSphereReplicationEnabled -eq $true -and $_.VSphereReplicationNfcEnabled -eq $true}) -ne $esxiHosts.Count) {
                                    For ($i=0; $i -lt $esxiHosts.Count; $i++) {
                                        if (Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VMHost $esxiHosts.fqdn[$i] | Where-Object {$_.vSphereReplicationEnabled -eq $true}) {
                                            Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VMHost $esxiHosts.fqdn[$i] -PortGroup $portgroup -ErrorAction Stop | Remove-VMHostNetworkAdapter -Confirm:$false -ErrorAction Stop
                                        }
                                    }
                                    $validateVMkernel = Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VirtualSwitch $vdswitchName -PortGroup $portgroup | Where-Object {$_.VSphereReplicationEnabled -eq $true -and $_.VSphereReplicationNfcEnabled -eq $true}
                                    if ($validateVMkernel.Count -eq 0) {
                                        Write-Output "Removing VMkernel Ports for vSphere Replication traffic on all ESXi hosts in Workload Domain ($domain): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing VMkernel Ports for vSphere Replication traffic on all ESXi hosts in Workload Domain ($domain): POST_VALIDATED_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing VMkernel Ports for vSphere Replication traffic on all ESXi hosts in Workload Domain ($domain), do not exist: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($portgroup): PRE_VALIDATION_FAILED"
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-EsxiVrmsVMkernelPort

Function Add-EsxiVrmsStaticRoute {
    <#
        .SYNOPSIS
        Create a static route on ESXi hosts for vSphere Replication traffic.

        .DESCRIPTION
        The Add-EsxiVrmsStaticRoute cmdlet creates a static route on each ESXi hosts for vSphere Replication traffic.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Creates static routes on ESXi hosts for vSphere Replication traffic

        .EXAMPLE
        Add-EsxiVrmsStaticRoute -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -subnet 172.27.15.0/24 -gateway 172.27.15.1 -portgroup sfo-sfo-m01-cl01-vds01-pg-vrms
        This example adds a static route to each ESXi host in the Management Domain to the recovery site vSphere Replication subnet.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER subnet
        The vSphere Replication subnet in CIDR notation.

        .PARAMETER gateway
        The vSphere Replication gateway.

        .PARAMETER portgroup
        The vSphere Distributed Port Group name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$subnet,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [IPAddress]$gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$portgroup
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $vdswitchName = (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}).VDSwitch.Name
                            $esxiHosts = Get-VCFHost | Where-Object {$_.cluster.id -eq ((Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain -and $_.vcenters.fqdn -eq $vcfVcenterDetails.fqdn}).clusters.id)}
                            if (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}) {
                                if ((Get-VMHostNetworkAdapter -Server $vcfVcenterDetails.fqdn -VirtualSwitch $vdswitchName -PortGroup $portgroup | Where-Object {$_.VSphereReplicationEnabled -eq $true -and $_.VSphereReplicationNfcEnabled -eq $true}).Count -eq $esxiHosts.Count) {
                                    [IPAddress]$network = $subnet.Split("/")[0]
                                    [Int32]$prefixLength = $subnet.Split("/")[1]
                                    Foreach ($esxiHost in $esxiHosts) {
                                        if (!(Get-VMHostRoute -VMHost $esxiHost.fqdn -Server $vcfVcenterDetails.fqdn | Where-Object {($_.ExtensionData.Network -eq $network) -and ($_.ExtensionData.Gateway -eq $gateway)})) {
                                            Get-VMHost -Name $esxiHost.fqdn -Server $vcfVcenterDetails.fqdn | New-VMHostRoute -Destination $network -Gateway $gateway -PrefixLength $prefixLength -Confirm:$false | Out-Null
                                            if (Get-VMHostRoute -VMHost $esxiHost.fqdn -Server $vcfVcenterDetails.fqdn | Where-Object {($_.ExtensionData.Network -eq $network) -and ($_.ExtensionData.Gateway -eq $gateway)}) {
                                                Write-Output "Adding static route for vSphere Replication traffic to ESXi Host ($($esxiHost.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Adding static route for vSphere Replication traffic to ESXi Host ($($esxiHost.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Adding static route for vSphere Replication traffic to ESXi Host ($($esxiHost.fqdn)), already exists: SKIPPED"
                                        }
                                    }
                                } else {
                                    Write-Error "Found ESXi hosts in Workload Domain ($domain) without a VMkernel port connected to ($portgroup) for vSphere Replication traffic: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to find vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($portgroup): PRE_VALIDATION_FAILED"
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-EsxiVrmsStaticRoute

Function Undo-EsxiVrmsStaticRoute {
    <#
        .SYNOPSIS
        Removes a static route from ESXi hosts for vSphere Replication traffic.

        .DESCRIPTION
        The Undo-EsxiVrmsStaticRoute cmdlet removes a static route on each ESXi hosts for vSphere Replication traffic.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Removes the static routes on ESXi hosts for vSphere Replication traffic

        .EXAMPLE
        Undo-EsxiVrmsStaticRoute -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -network 172.27.15.0
        This example removes a static route to each ESXi host in the Management Domain to the recovery site vSphere Replication subnet.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER network
        The network address of the static route to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [IPAddress]$network
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $esxiHosts = Get-VCFHost | Where-Object {$_.cluster.id -eq ((Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain -and $_.vcenters.fqdn -eq $vcfVcenterDetails.fqdn}).clusters.id)}
                            Foreach ($esxiHost in $esxiHosts) {
                                if (Get-VMHostRoute -VMHost $esxiHost.fqdn -Server $vcfVcenterDetails.fqdn | Where-Object {$network -contains $_.Destination.IPAddressToString}) {
                                    Remove-VMHostRoute -VMHostRoute (Get-VMHostRoute -VMHost $esxiHost.fqdn -Server $vcfVcenterDetails.fqdn | Where-Object {$network -contains $_.Destination.IPAddressToString}) -Confirm:$false
                                    if (!(Get-VMHostRoute -VMHost $esxiHost.fqdn -Server $vcfVcenterDetails.fqdn | Where-Object {$network -contains $_.Destination.IPAddressToString})) {
                                        Write-Output "Removing static route for vSphere Replication traffic to ESXi Host ($($esxiHost.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing static route for vSphere Replication traffic to ESXi Host ($($esxiHost.fqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing static route for vSphere Replication traffic to ESXi Host ($($esxiHost.fqdn)), already exists: SKIPPED"
                                }
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-EsxiVrmsStaticRoute

Function Add-SrmLicenseKey {
    <#
        .SYNOPSIS
        Add a license for Site Recovery Manager.

        .DESCRIPTION
        The Add-SrmLicenseKey cmdlet adds a license for Site Recovery Manager in vCenter Server. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance
        - Validates whether the license key exists in vCenter Server inventory, and if not, installs them
        - Assigns the license to Site Recovery Manager

        .EXAMPLE
        Add-SrmLicenseKey -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -srmLicenseKey AAAAA-BBBBB-CCCCC-DDDDD-EEEEE
        This example adds a license key to the Site Recovery Manager instance.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER srmLicenseKey
        The Site Recovery Manager license key.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmLicenseKey
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ((((Get-View -server $vcfVcenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]) {
                                $srmFqdn = (((Get-View -server $vcfVcenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                if (Test-SrmConnection -server $srmFqdn) {
                                    if (Test-SrmAuthentication -server $srmFqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        $serviceInstance = Get-View -Server $vcfVcenterDetails.fqdn ServiceInstance
                                        $licenseManager = Get-View -Server $vcfVcenterDetails.fqdn $serviceInstance.Content.LicenseManager | Where-Object {$_.LicensedEdition -match $vcfVcenterDetails.fqdn}
                                        $licenseAssignmentManager = Get-View -Server $vcfVcenterDetails.fqdn $licenseManager.licenseAssignmentManager
                                        if ($licenseManager.Licenses | Where-Object {$_.LicenseKey -eq $srmLicenseKey}) {
                                            Write-Warning "Adding License key ($srmLicenseKey) for Site Recovery Manager to vCenter Server ($($vcfVcenterDetails.fqdn)), already exists: SKIPPING"
                                        } else {
                                            $licenseManager.AddLicense($srmLicenseKey,$null) | Out-Null
                                            $licenseManager.UpdateViewData()
                                            if ($licenseManager.Licenses | Where-Object {$_.LicenseKey -eq $srmLicenseKey}) {
                                                Write-Output "Adding License key ($srmLicenseKey) for Site Recovery Manager to vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Adding License key ($srmLicenseKey) for Site Recovery Manager to vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                            $srmSiteName = (($global:DefaultSrmServers | Where-Object {$_.Name -eq $srmFqdn}).ExtensionData.GetLocalSiteInfo()).SiteName
                                            $srmPartialUuid = ($licenseAssignmentManager.QueryAssignedLicenses($null) | Where-Object {$_.EntityDisplayName -eq $srmSiteName}).EntityId
                                            $scriptCommand = "/usr/lib/vmware-vmafd/bin/vmafd-cli get-ldu --server-name localhost"
                                            $output = Invoke-VMScript -VM ($vcfVcenterDetails.fqdn).Split(".")[0] -ScriptText $scriptCommand -GuestUser root -GuestPassword $vcfVcenterDetails.rootPass -Server $vcfVcenterDetails.fqdn
                                            $srmUuid = ($srmPartialUuid + "-" + $output.ScriptOutput).Trim()
                                            if (($licenseAssignmentManager.QueryAssignedLicenses($srmUuid).AssignedLicense.LicenseKey) -eq $srmLicenseKey) {
                                                Write-Warning "Assigning License Key ($srmLicenseKey) to Site Recovery Manager instance ($srmFqdn), already exists: SKIPPING"
                                            } else {
                                                $licenseAssignmentManager.UpdateAssignedLicense($srmUuid,$srmLicenseKey,$null) | Out-Null
                                                $licenseAssignmentManager.UpdateViewData() | Out-Null
                                                if (($licenseAssignmentManager.QueryAssignedLicenses($srmUuid).AssignedLicense.LicenseKey) -eq $srmLicenseKey) {
                                                    Write-Output "Assigning License Key ($srmLicenseKey) to Site Recovery Manager instance ($srmFqdn): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Assigning License Key ($srmLicenseKey) to Site Recovery Manager instance ($srmFqdn): POST_VALIDATION_FAILED"
                                                }
                                            }
                                        }
                                    }
                                    Disconnect-SrmServer -Server $srmFqdn -Force -Confirm:$false
                                }
                            } else {
                                Write-Error "No Site Recovery Manager Appliance Registered with vCenter Server ($($vcfVcenterDetails.fqdn))"
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-SrmLicenseKey

Function Undo-SrmLicenseKey {
    <#
        .SYNOPSIS
        Removes a license for Site Recovery Manager.

        .DESCRIPTION
        The Undo-SrmLicenseKey cmdlet removes a license for Site Recovery Manager from vCenter Server. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance
        - Validates that network connectivity and authentication is possible to the vCenter Server instance
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance
        - Validates whether the license key exists in vCenter Server inventory, and removes it

        .EXAMPLE
        Undo-SrmLicenseKey -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -srmLicenseKey 00000-11111-22222-33333-4444
        This example removes the license key from Site Recovery Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER srmLicenseKey
        The Site Recovery Manager license key.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmLicenseKey
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ((((Get-View -server $vcfVcenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]) {
                                $srmFqdn = (((Get-View -server $vcfVcenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                if (Test-SrmConnection -server $srmFqdn) {
                                    if (Test-SrmAuthentication -server $srmFqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        $serviceInstance = Get-View -Server $vcfVcenterDetails.fqdn ServiceInstance 
                                        $licenseManager = Get-View -Server $vcfVcenterDetails.fqdn $serviceInstance.Content.LicenseManager | Where-Object {$_.LicensedEdition -match $vcfVcenterDetails.fqdn}
                                        $licenseAssignmentManager = Get-View -Server $vcfVcenterDetails.fqdn $licenseManager.licenseAssignmentManager
                                        $srmSiteName = (($global:DefaultSrmServers | Where-Object {$_.Name -eq $srmFqdn}).ExtensionData.GetLocalSiteInfo()).SiteName
                                        $srmPartialUuid = ($licenseAssignmentManager.QueryAssignedLicenses($null) | Where-Object {$_.EntityDisplayName -eq $srmSiteName}).EntityId
                                        $scriptCommand = "/usr/lib/vmware-vmafd/bin/vmafd-cli get-ldu --server-name localhost"
                                        $output = Invoke-VMScript -VM ($vcfVcenterDetails.fqdn).Split(".")[0] -ScriptText $scriptCommand -GuestUser root -GuestPassword $vcfVcenterDetails.RootPass -Server $vcfVcenterDetails.fqdn
                                        $srmUuid = ($srmPartialUuid + "-" + $output.ScriptOutput).Trim()
                                        if (!($licenseAssignmentManager.QueryAssignedLicenses($srmUuid).AssignedLicense.LicenseKey) -or ($licenseAssignmentManager.QueryAssignedLicenses($srmUuid).AssignedLicense.LicenseKey) -eq "00000-00000-00000-00000-00000") {
                                            Write-Warning "Removing License key ($srmLicenseKey) for Site Recovery Manager instance ($srmFqdn), already removed: SKIPPING"
                                        } else {
                                            $licenseAssignmentManager.RemoveAssignedLicense($srmUuid) | Out-Null
                                            $licenseAssignmentManager.UpdateViewData() | Out-Null
                                            if (!($licenseAssignmentManager.QueryAssignedLicenses($srmUuid).AssignedLicense.LicenseKey)) {
                                                Write-Output "Removing License key ($srmLicenseKey) from Site Recovery Manager instance ($srmFqdn): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removing License key ($srmLicenseKey) from Site Recovery Manager instance ($srmFqdn): POST_VALIDATION_FAILED"
                                            }
                                            if (!($licenseManager.Licenses | Where-Object {$_.LicenseKey -eq $srmLicenseKey})) {
                                                Write-Warning "Removing License key ($srmLicenseKey) from vCenter Server ($($vcfVcenterDetails.fqdn)), already removed: SKIPPING"
                                            } else {
                                                $licenseManager.RemoveLicense($srmLicenseKey) | Out-Null
                                                $licenseManager.UpdateViewData()
                                                if (!($licenseManager.Licenses | Where-Object {$_.LicenseKey -eq $srmLicenseKey})) {
                                                    Write-Output "Removing License key ($srmLicenseKey) from vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Removing License key ($srmLicenseKey) from vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SrmLicenseKey

Function Add-vSphereReplication {
    <#
        .SYNOPSIS
        Adds a vSphere Replication for a specified virtual machine.

        .DESCRIPTION
        The Add-vSphereReplication cmdlet adds vSphere Replication for a specified virtual machine. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the vSphere Replication instance.
        - Adds a vSphere Replication for the specified virtual machine.

        .EXAMPLE
        Add-vSphereReplication -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vmName xint-vrslcm01 -recoveryPointObjective 15
        This example adds vSphere Replication for VM xint-vrslcm01 from the protected instance to the recovery instance.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER vmName
        The name of the virtual machine(s) to target. To target multiple virtual machines, this must be presented as an array.

        .PARAMETER recoveryPointObjective
        The number of minutes, within a range of 5 to 1440 (one day), to define the RPO for the new replication.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$vmName,
        [Parameter (Mandatory = $true)] [ValidateRange(5,1440)] [Int]$recoveryPointObjective
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if (Test-SrmConnection -server $vrmsAFqdn) {
                                                    if (Test-SrmConnection -server $vrmsBFqdn) {
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if (($vrmsAuth.vrmsAuthentication -eq $true) -and ($vrmsAuth.vrmsRemoteAuthentication -eq $true)) {
                                                            $vmsToCheckReplication = @()
                                                            foreach ($vm in $vmName) {
                                                                $getVm = Get-VrmsVm -vmName $vm
                                                                if (!$getVm) {
                                                                    Write-Warning "Virtual machine ($vm) does not exist: PRE_VALIDATION_FAILED"
                                                                } else {
                                                                    $vmsToCheckReplication += $vm
                                                                }
                                                            }
                                                            $vmsToReplicate = @()
                                                            foreach ($vm in $vmsToCheckReplication) {
                                                                $getVmReplication = Get-VrmsReplication -vmName $vm
                                                                if ($getVmReplication -match "was not found") {
                                                                    $vmsToReplicate += $vm
                                                                } else {
                                                                    Write-Warning "Replication for virtual machine ($vm) already exists: SKIPPING"
                                                                }
                                                            }
                                                            foreach ($vm in $vmsToReplicate) {
                                                                $newReplication = Add-VrmsReplication -vmName $vm -recoveryPointObjective $recoveryPointObjective
                                                                if (!$newReplication) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Replication for virtual machine ($vm) failed: POST_VALIDATION_FAILED"),
                                                                            'Add-vSphereReplication',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                } else {
                                                                    Write-Output "Add vSphere Replication for virtual machine ($vm): SUCCESSFUL"
                                                                }
                                                            }    
                                                        }   
                                                    } else {
                                                        $PSCmdlet.ThrowTerminatingError(
                                                            [System.Management.Automation.ErrorRecord]::new(
                                                                ([System.Management.Automation.GetValueException]"Unable to authenticate with vSphere Replication servers: PRE_VALIDATION_FAILED"),
                                                                'Add-vSphereReplication',
                                                                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                ""
                                                            )
                                                        )
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vSphereReplication

Function Undo-vSphereReplication {
    <#
        .SYNOPSIS
        Removes a vSphere Replication for a specified virtual machine.

        .DESCRIPTION
        The Undo-vSphereReplication cmdlet adds vSphere Replication for a specified virtual machine. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the vSphere Replication instance.
        - Removes a vSphere Replication for the specified virtual machine.

        .EXAMPLE
        Undo-vSphereReplication -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vmName xint-vrslcm01
        This example removes the vSphere Replication for VM xint-vrslcm01.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER vmName
        The name of the virtual machine(s) to target. To target multiple virtual machines, this must be presented as an array.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$vmName
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if (Test-SrmConnection -server $vrmsAFqdn) {
                                                    if (Test-SrmConnection -server $vrmsBFqdn) {
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if (($vrmsAuth.vrmsAuthentication -eq $true) -and ($vrmsAuth.vrmsRemoteAuthentication -eq $true)) {
                                                            foreach ($vm in $vmName){
                                                                $vrmsVm = Get-VrmsVm -vmName $vm
                                                                if (!$vrmsVm) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Virtual machine $vm does not exist: PRE_VALIDATION_FAILED"),
                                                                            'Undo-vSphereReplication',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                }
                                                            }
                                                            $replicationsToRemove = @()
                                                            foreach ($vm in $vmName) {
                                                                $getVmReplication = Get-VrmsReplication -vmName $vm
                                                                if ($getVmReplication -match "was not found") {
                                                                    Write-Warning "Replication for virtual machine $vm does not exist: SKIPPING"
                                                                } else {
                                                                    $replicationsToRemove += $vm
                                                                }
                                                            }
                                                            foreach ($vm in $replicationsToRemove) {
                                                            $unconfigureReplication = Remove-VrmsReplication -vmName $vm
                                                                if (!$unconfigureReplication) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Replication for virtual machine $vm failed: POST_VALIDATION_FAILED"),
                                                                            'Undo-vSphereReplication',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                } else {
                                                                    Write-Host "Remove vSphere Replication for virtual machine ($vm): SUCCESSFUL"
                                                                }
                                                            }
                                                        } else {
                                                            $PSCmdlet.ThrowTerminatingError(
                                                                [System.Management.Automation.ErrorRecord]::new(
                                                                    ([System.Management.Automation.GetValueException]"Unable to authenticate with vSphere Replication servers: PRE_VALIDATION_FAILED"),
                                                                    'Undo-vSphereReplication',
                                                                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                    ""
                                                                )
                                                            )
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vSphereReplication

Function Add-ProtectionGroup {
    <#
        .SYNOPSIS
        Adds a Site Recovery Manager protection group.

        .DESCRIPTION
        The Add-ProtectionGroup cmdlet adds a Site Recovery Manager protection group. The cmdlet
        connects to SDDC Manager instances in both the protected and recovery sites:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance.
        - Adds a Site Recovery Manager protection group

        .EXAMPLE
        Add-ProtectionGroup -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1! -sddcManagerBFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -pgName xint-vrops01-pg -vmName @("xint-vrops01a", "xint-vrops01b", "xint-vrops01c")
        This example adds a protection group xint-vrops01-pg containing virtual machines xint-vrops01a, xint-vrops01b, and xint-vrops01c to Site Recovery Manager in the protected instance.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER pgName
        The name of the new protection group.

        .PARAMETER vmName
        The name of the virtual machine(s) to target. Must be presented as an array.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pgName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$vmName
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $vrmsAFqdn)) {
                                                    if ((Test-SrmConnection -server $srmBFqdn) -and (Test-SrmConnection -server $vrmsBFqdn)) {
                                                        $srmAuth = Test-SrmAuthenticationREST -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if (($srmAuth.srmAuthentication -eq $true) -and ($srmAuth.srmRemoteAuthentication -eq $true) -and ($vrmsAuth.vrmsAuthentication -eq $true) -and ($vrmsAuth.vrmsRemoteAuthentication -eq $true)) {
                                                            foreach ($vm in $vmName) {
                                                                $getVm = Get-VrmsVm -vmName $vm
                                                                if (!$getVM) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Virtual machine $vm does not exist: PRE_VALIDATION_FAILED"),
                                                                            'Add-ProtectionGroup',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                }
                                                                $getReplicationStatus = Get-VrmsReplication 
                                                            }
                                                            $srmProtectionGroups = Get-SrmProtectionGroup
                                                            $skip = $false
                                                            if ($srmProtectionGroups) {
                                                                foreach ($srmProtectionGroup in $srmProtectionGroups) {
                                                                    if ($pgName -eq $srmProtectionGroup.name) {
                                                                        Write-Warning "Protection Group $pgName already exists: SKIPPING"
                                                                        $skip = $true
                                                                        break
                                                                    }
                                                                }
                                                            }
                                                            if ($skip -eq $false) {
                                                                $newProtectionGroup = Add-SrmProtectionGroup -pgName $pgName -vmName $vmName
                                                                if (!$newProtectionGroup) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Protection Group $pgName creation failed: POST_VALIDATION_FAILED"),
                                                                            'Add-ProtectionGroup',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                } else {
                                                                    Write-Host "Add protection group ($pgName): SUCCESSFUL"
                                                                }
                                                            }   
                                                        } else {
                                                            $PSCmdlet.ThrowTerminatingError(
                                                                [System.Management.Automation.ErrorRecord]::new(
                                                                    ([System.Management.Automation.GetValueException]"Unable to authenticate with vSphere Replication or Site Recovery Manager servers: PRE_VALIDATION_FAILED"),
                                                                    'Add-ProtectionGroup',
                                                                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                    ""
                                                                )
                                                            )
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }

}
Export-ModuleMember -Function Add-ProtectionGroup

Function Undo-ProtectionGroup {
    <#
        .SYNOPSIS
        Removes a Site Recovery Manager protection group.

        .DESCRIPTION
        The Undo-ProtectionGroup cmdlet removes a Site Recovery Manager protection group. The cmdlet
        connects to SDDC Manager instances in both the protected and recovery sites:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance.
        - Removes a Site Recovery Manager protection group.

        .EXAMPLE
        Undo-ProtectionGroup -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1! -sddcManagerBFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -pgName xint-vrops01-pg
        This example removes protection group xint-vrops01-pg from Site Recovery Manager in the protected instance.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER pgName
        The name of the new protection group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pgName
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $vrmsAFqdn)) {
                                                    if ((Test-SrmConnection -server $srmBFqdn) -and (Test-SrmConnection -server $vrmsBFqdn)) {
                                                        $srmAuth = Test-SrmAuthenticationREST -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if (($srmAuth.srmAuthentication -eq $true) -and ($srmAuth.srmRemoteAuthentication -eq $true) -and ($vrmsAuth.vrmsAuthentication -eq $true) -and ($vrmsAuth.vrmsRemoteAuthentication -eq $true)) {
                                                            $protectionGroup = Get-SrmProtectionGroup -pgName $pgName
                                                            $skip = $false
                                                            if (!$protectionGroup) {
                                                                Write-Warning "Protection Group ($pgName) not found: SKIPPING"
                                                                $skip = $true
                                                                break
                                                            }
                                                            if ($skip -eq $false) {
                                                                $removeProtectionGroup = Remove-SrmProtectionGroup -pgName $pgName
                                                                if ($removeProtectionGroup -match "Protection Group $pgName was not found") {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Remove protection group $pgName failed: POST_VALIDATION_FAILED"),
                                                                            'Undo-ProtectionGroup',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                } else {
                                                                    Write-Host "Remove protection group ($pgName): SUCCESSFUL"
                                                                }
                                                            }   
                                                        } else {
                                                            $PSCmdlet.ThrowTerminatingError(
                                                                [System.Management.Automation.ErrorRecord]::new(
                                                                    ([System.Management.Automation.GetValueException]"Unable to authenticate with vSphere Replication or Site Recovery Manager servers: PRE_VALIDATION_FAILED"),
                                                                    'Undo-ProtectionGroup',
                                                                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                    ""
                                                                )
                                                            )
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }

}
Export-ModuleMember -Function Undo-ProtectionGroup

Function Add-RecoveryPlan {
    <#
        .SYNOPSIS
        Adds a Site Recovery Manager recovery plan.

        .DESCRIPTION
        The Add-RecoveryPlan cmdlet adds a Site Recovery Manager recovery plan. The cmdlet
        connects to SDDC Manager instances in both the protected and recovery sites:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance.
        - Adds a Site Recovery Manager recovery plan.

        .EXAMPLE
        Add-RecoveryPlan -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1! -sddcManagerBFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -rpName xint-vrops01-rp -pgName xint-vrops01-pg
        This example adds recovery plan xint-vrops01-rp with protection group xint-vrops01-pg to Site Recovery Manager.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER rpName
        The name of the new recovery plan.

        .PARAMETER pgName
        The name of the protection group to add to the new recovery plan.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pgName
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $vrmsAFqdn)) {
                                                    if ((Test-SrmConnection -server $srmBFqdn) -and (Test-SrmConnection -server $vrmsBFqdn)) {
                                                        $srmAuth = Test-SrmAuthenticationREST -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if (($srmAuth.srmAuthentication -eq $true) -and ($srmAuth.srmRemoteAuthentication -eq $true) -and ($vrmsAuth.vrmsAuthentication -eq $true) -and ($vrmsAuth.vrmsRemoteAuthentication -eq $true)) {
                                                            $getPg = Get-SrmProtectionGroup -pgName $pgName
                                                            if (!$getPg) {
                                                                $PSCmdlet.ThrowTerminatingError(
                                                                    [System.Management.Automation.ErrorRecord]::new(
                                                                        ([System.Management.Automation.GetValueException]"Protection Group $pgName does not exist: PRE_VALIDATION_FAILED"),
                                                                        'Add-RecoveryPlan',
                                                                        [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                        ""
                                                                    )
                                                                )
                                                            }
                                                            $srmRecoveryPlan = Get-SrmRecoveryPlan -rpName $rpName
                                                            $skip = $false
                                                            if ($srmRecoveryPlan) {
                                                               Write-Warning "Recovery Plan $rpName already exists: SKIPPING"
                                                                $skip = $true
                                                                break
                                                            }
                                                            if ($skip -eq $false) {
                                                                $newRecoveryPlan = Add-SrmRecoveryPlan -rpName $rpName -pgName $pgName
                                                                if (!$newRecoveryPlan) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Recovery Plan $rpName creation failed: POST_VALIDATION_FAILED"),
                                                                            'Add-RecoveryPlan',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                } else {
                                                                    Write-Host "Add recovery plan ($rpName): SUCCESSFUL"
                                                                }
                                                            }   
                                                        } else {
                                                            $PSCmdlet.ThrowTerminatingError(
                                                                [System.Management.Automation.ErrorRecord]::new(
                                                                    ([System.Management.Automation.GetValueException]"Unable to authenticate with vSphere Replication or Site Recovery Manager servers: PRE_VALIDATION_FAILED"),
                                                                    'Add-RecoveryPlan',
                                                                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                    ""
                                                                )
                                                            )
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-RecoveryPlan

Function Set-RecoveryPlan {
    <#
        .SYNOPSIS
        Configures a Site Recovery Manager recovery plan.

        .DESCRIPTION
        The Set-RecoveryPlan cmdlet configures a Site Recovery Manager recovery plan. The cmdlet
        connects to SDDC Manager instances in both the protected and recovery sites:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance.
        - Configures a Site Recovery Manager recovery plan.

        .EXAMPLE
        Set-RecoveryPlan -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1! -sddcManagerBFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -rpName xint-vrops01-rp -setVmPriority $true -vmName @("xint-vrops01a","xint-vrops01b","xint-vrops01c") -priority P1 -addCallout $false
        This example changes the restart priority for virtual machines xint-vrops01a, xint-vrops01b, and xint-vrops01c to P3 in recovery plan xint-vrops01-rp in Site Recovery Manager.

        .EXAMPLE
        Set-RecoveryPlan -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1! -sddcManagerBFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -rpName xint-vrops01-rp -setVmPriotiry $false -addCallout $true -calloutType PROMPT -calloutName "Verify the availability of the load balancer for VMware Aria Operations" -calloutContent "Verify the availability of the load balancer for VMware Aria Operations" -calloutPositionBefore P1 -calloutTimeoutSeconds 0
        This example adds a callout step before "Power on priority 3 VMs" in recovery plan xint-vrops01-rp in Site Recovery Manager.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER rpName
        The name of the new recovery plan.

        .PARAMETER setVmPriority
        To change the VM restart priority for a virtual machine or set of virtual machines (boolean).

        .PARAMETER vmName
        The name of the virtual machine(s) to target. Must be presented as an array. Only applicable if setVmPriority is set to $true.

        .PARAMETER priority
        The restart priority (P1 - P5) of the targeted virtual machine(s). Only applicable if setVmPriority is set to $true.

        .PARAMETER addCallout
        To add a callout to the recovery plan (boolean).

        .PARAMETER calloutType
        The type of callout to be added (PROMPT, RUN_ON_VM, RUN_ON_SRM_SERVER). Only applicable if addCallout is set to $true.

        .PARAMETER calloutName
        The name of the callout to be added. Only applicable if addCallout is set to $true.

        .PARAMETER calloutContent
        The content of the callout to be added. Only applicable if addCallout is set to $true.

        .PARAMETER calloutPositionBefore
        The position of the step before which the callout is to be added (P1 - P5). For example, a value of P1 sets the callout to appear before Priority 1 VMs are powered on. Only applicable if addCallout is set to $true.

        .PARAMETER calloutTimeoutSeconds
        The number of seconds the callout appears before it times out. Only applicable if addCallout is set to $true and calloutType is either RUN_ON_VM or RUN_ON_SRM_SERVER.
        #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [bool]$setVmPriority,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [array]$vmName,
        [Parameter (Mandatory = $false)] [ValidateSet("P1","P2","P3","P4","P5")] [string]$priority,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [bool]$addCallout,
        [Parameter (Mandatory = $false)] [ValidateSet("PROMPT","RUN_ON_VM","RUN_ON_SRM_SERVER")] [String]$calloutType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$calloutName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$calloutContent,
        [Parameter (Mandatory = $false)] [ValidateSet("P1","P2","P3","P4","P5")] [String]$calloutPositionBefore,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$calloutTimeoutSeconds
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $vrmsAFqdn)) {
                                                    if ((Test-SrmConnection -server $srmBFqdn) -and (Test-SrmConnection -server $vrmsBFqdn)) {
                                                        $srmAuth = Test-SrmAuthenticationREST -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if ($setVmPriority -eq $true) {
                                                            foreach ($vm in $vmName) {
                                                                $setPriority = Set-SrmRecoveryPlanVMPriority -rpName $rpName -vmName $vm -priority $priority
                                                                if (!$setPriority) {
                                                                    Write-Error "Setting the restart priority for virtual machine $vm in recovery plan $rpName failed: POST_VALIDATION_FAILED"
                                                                } else {
                                                                    Write-Output "Set the restart priority for virtual machine $vm in recovery plan $rpName to $priority : SUCCESSFUL"
                                                                }
                                                            }
                                                        }
                                                        if ($addCallout -eq $true) {
                                                            if ($calloutPositionBefore -eq "P1") {
                                                                $title = "Power on priority 1 VMs"
                                                            } elseif ($calloutPositionBefore -eq "P2") {
                                                                $title = "Power on priority 2 VMs"
                                                            } elseif ($calloutPositionBefore -eq "P3") {
                                                                $title = "Power on priority 3 VMs"
                                                            } elseif ($calloutPositionBefore -eq "P4") {
                                                                $title = "Power on priority 4 VMs"
                                                            } elseif ($calloutPositionBefore -eq "P5") {
                                                                $title = "Power on priority 5 VMs"
                                                            }
                                                            $findPosition = (Get-SrmRecoveryPlanStep -rpName $rpName | Where-Object {$_.title -eq $title}).step_number.split(".")[0]
                                                            if ($calloutTimeoutSeconds) {
                                                                $newCallout = Add-SrmRecoveryPlanCalloutStep -rpName $rpName -calloutType $calloutType -calloutName $calloutName -content $calloutContent -position $findPosition -timeoutSeconds $calloutTimeoutSeconds
                                                            } else {
                                                                $newCallout = Add-SrmRecoveryPlanCalloutStep -rpName $rpName -calloutType $calloutType -calloutName $calloutName -content $calloutContent -position $findPosition
                                                            }
                                                            if (!$newCallout) {
                                                                Write-Error "Add new callout step in recovery plan $rpName failed: POST_VALIDATION_FAILED"
                                                            } else {
                                                                Write-Output "Add new callout step in recovery plan $rpName : SUCCESSFUL"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-RecoveryPlan

Function Undo-RecoveryPlan {
    <#
        .SYNOPSIS
        Removes a Site Recovery Manager recovery plan.

        .DESCRIPTION
        The Undo-RecoveryPlan cmdlet adds a Site Recovery Manager recovery plan. The cmdlet
        connects to SDDC Manager instances in both the protected and recovery sites:
        - Validates that network connectivity and authentication is possible to the SDDC Manager instance.
        - Validates that network connectivity and authentication is possible to the vCenter Server instance.
        - Validates that network connectivity and authentication are possible to the Site Recovery Manager instance.
        - Removes a Site Recovery Manager recovery plan.

        .EXAMPLE
        Undo-RecoveryPlan -sddcManagerAFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPass VMw@re1! -sddcManagerBFqdn sfo-vcf01.sfo.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPass VMw@re1! -rpName xint-vrops01-rp
        This example removes recovery plan xint-vrops01-rp from Site Recovery Manager.

        .PARAMETER sddcManagerAFqdn
        The fully qualified domain name of the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAUser
        The username to authenticate to the SDDC Manager in the protected site.

        .PARAMETER sddcManagerAPass
        The password to authenticate to the SDDC Manager in the protected site.
        
        .PARAMETER sddcManagerBFqdn
        The fully qualified domain name of the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBUser
        The username to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER sddcManagerBPass
        The password to authenticate to the SDDC Manager in the recovery site.

        .PARAMETER rpName
        The name of the recovery plan to be removed.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerAPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcManagerBPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName
    )

    Try {
        if (Test-VCFConnection -server $sddcManagerAFqdn) {
            if (Test-VCFAuthentication -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass) {
                if (($siteAvCenterDetails = Get-vCenterServerDetail -server $sddcManagerAFqdn -user $sddcManagerAUser -pass $sddcManagerAPass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($siteAvCenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $siteAvCenterDetails.fqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass) {
                            $srmAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                            $vrmsAFqdn = (((Get-View -server $siteAvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                            if (Test-VCFConnection -server $sddcManagerBFqdn) {
                                if (Test-VCFAuthentication -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass) {
                                    if (($siteBvCenterDetails = Get-vCenterServerDetail -server $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPass -domainType MANAGEMENT)) {
                                        if (Test-VsphereConnection -server $($siteBvCenterDetails.fqdn)) {
                                            if (Test-VsphereAuthentication -server $siteBvCenterDetails.fqdn -user $siteBvCenterDetails.ssoAdmin -pass $siteBvCenterDetails.ssoAdminPass) {
                                                $srmBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcDr"}).Server.Url -Split "//" -Split ":")[2]
                                                $vrmsBFqdn = (((Get-View -server $siteBvCenterDetails.fqdn ExtensionManager).ExtensionList | Where-Object {$_.key -eq "com.vmware.vcHms"}).Server.Url -Split "//" -Split ":")[2]
                                                if ((Test-SrmConnection -server $srmAFqdn) -and (Test-SrmConnection -server $vrmsAFqdn)) {
                                                    if ((Test-SrmConnection -server $srmBFqdn) -and (Test-SrmConnection -server $vrmsBFqdn)) {
                                                        $srmAuth = Test-SrmAuthenticationREST -server $srmAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        $vrmsAuth = Test-VrmsAuthenticationREST -server $vrmsAFqdn -user $siteAvCenterDetails.ssoAdmin -pass $siteAvCenterDetails.ssoAdminPass -remoteUser $siteBvCenterDetails.ssoAdmin -remotePass $siteBvCenterDetails.ssoAdminPass
                                                        if (($srmAuth.srmAuthentication -eq $true) -and ($srmAuth.srmRemoteAuthentication -eq $true) -and ($vrmsAuth.vrmsAuthentication -eq $true) -and ($vrmsAuth.vrmsRemoteAuthentication -eq $true)) {
                                                            $srmRecoveryPlan = Get-SrmRecoveryPlan -rpName $rpName
                                                            $skip = $false
                                                            if (!$srmRecoveryPlan) {
                                                               Write-Warning "Recovery Plan $rpName not found: SKIPPING"
                                                                $skip = $true
                                                                break
                                                            }
                                                            if ($skip -eq $false) {
                                                                $newRecoveryPlan = Remove-SrmRecoveryPlan -rpName $rpName
                                                                if (!$newRecoveryPlan) {
                                                                    $PSCmdlet.ThrowTerminatingError(
                                                                        [System.Management.Automation.ErrorRecord]::new(
                                                                            ([System.Management.Automation.GetValueException]"Recovery Plan $rpName removal failed: POST_VALIDATION_FAILED"),
                                                                            'Add-RecoveryPlan',
                                                                            [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                            ""
                                                                        )
                                                                    )
                                                                } else {
                                                                    Write-Host "Remove recovery plan ($rpName): SUCCESSFUL"
                                                                }
                                                            }   
                                                        } else {
                                                            $PSCmdlet.ThrowTerminatingError(
                                                                [System.Management.Automation.ErrorRecord]::new(
                                                                    ([System.Management.Automation.GetValueException]"Unable to authenticate with vSphere Replication or Site Recovery Manager servers: PRE_VALIDATION_FAILED"),
                                                                    'Add-RecoveryPlan',
                                                                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                                                                    ""
                                                                )
                                                            )
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-RecoveryPlan

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region D E V E L O P E R R E A D Y I N F R A S T R U C T U R E F U N C T I O N S ###########

Function Add-NetworkSegment {
    <#
        .SYNOPSIS
        The Add-NetworkSegment cmdlet creates an NSX segment. The cmdlet connects to SDDC Manager using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Create the NSX segment if not already created in NSX Manager.

        .DESCRIPTION
        The Add-NetworkSegment cmdlet creates an NSX Segment

        .EXAMPLE
        Add-NetworkSegment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -segmentName sfo-w01-kub-seg01 -gatewayType Tier1 -connectedGateway sfo-w01-ec01-t1-gw01 -cidr 192.168.31.1/24 -transportZone overlay-tz-sfo-w01-nsx01.sfo.rainpole.io -segmentType Overlay
        This example creates an overlay-backed NSX segment in the workload domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER segmentName
        The NSX Segment name.

        .PARAMETER gatewayType
        The NSX Gateway type.

        .PARAMETER connectedGateway
        The NSX Gateway name.

        .PARAMETER cidr
        The NSX Segment CIDR.

        .PARAMETER transportZone
        The NSX Transport Zone name.

        .PARAMETER segmentType
        The NSX Segment type.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$segmentName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$connectedGateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cidr,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$transportZone,
        [Parameter (Mandatory = $true)] [ValidateSet("Tier0", "Tier1")] [String]$gatewayType,
        [Parameter (Mandatory = $true)] [ValidateSet("Overlay", "VLAN")] [String]$segmentType
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                            if (!(Get-NsxtSegment -name $segmentName)) {
                                if ($gatewayType -eq "Tier0") { $tierGatewayExists = Get-NsxtTier0Gateway -name $connectedGateway }
                                if ($gatewayType -eq "Tier1") { $tierGatewayExists = Get-NsxtTier1Gateway -name $connectedGateway }
                                if ($tierGatewayExists) {
                                    $validateTransportZone = Get-NsxtTransportZone -Name $transportZone -ErrorAction SilentlyContinue
                                    if ($validateTransportZone.display_name -eq $transportZone) {
                                        if ($validateTransportZone.tz_type -notmatch $segmentType.ToUpper()){
                                            Write-Error "NSX Transport Zone $transportZone does not match the defined segment Type $segmentType in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                                            Break
                                        }
                                    } else {
                                        Write-Error "Unable to find NSX Transport Zone ($transportZone) in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                                        Break
                                    }
                                    New-NsxtSegment -name $segmentName -connectedGateway $connectedGateway -cidr $cidr -transportZone $transportZone -gatewayType $gatewayType -segmentType $segmentType | Out-Null
                                    if (Get-NsxtSegment -name $segmentName) {
                                        Write-Output "Creating $segmentType-backed NSX segment in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($segmentName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Creating $segmentType-backed NSX segment in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($segmentName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find NSX $gatewayType Gateway $connectedGateway in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Creating $segmentType-backed NSX segment in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($segmentName), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NetworkSegment

Function Undo-NetworkSegment {
    <#
        .SYNOPSIS
        The Undo-NetworkSegment cmdlet removes an NSX segment. The cmdlet connects to SDDC Manager using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes the NSX segment if not already removed from NSX Manager.

        .DESCRIPTION
        The Undo-NetworkSegment cmdlet removes an NSX Segment from NSX Manager

        .EXAMPLE
        Undo-NetworkSegment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -segmentName sfo-w01-kub-seg01
        This example removes an NSX segment from the NSX Manager of Workload Domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER segmentName
        The NSX Segment name.

        .PARAMETER segmentType
        The NSX Segment type.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$segmentName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                            if (Get-NsxtSegment -name $segmentName) {
                                Remove-NsxtSegment -name $segmentName | Out-Null
                                if (!(Get-NsxtSegment -name $segmentName)) {
                                    Write-Output "Removing NSX segment in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($segmentName): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing NSX segment in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($segmentName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing NSX segment in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($segmentName), does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NetworkSegment

Function Add-PrefixList {
    <#
        .SYNOPSIS
        The Add-PrefixList cmdlet creates NSX Prefix List in the NSX Manager cluster. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Create an NSX Prefix List if not already created in NSX Manager.

        .DESCRIPTION
        The Add-PrefixList cmdlet creates an NSX Prefix List

        .EXAMPLE
        Add-PrefixList -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -tier0Gateway sfo-w01-ec01-t0-gw01 -prefixListName sfo-w01-ec01-t0-gw01-mgmt-prefixlist -subnetCIDR 192.168.20.0/24 -ingressSubnetCidr "192.168.21.0/24" -egressSubnetCidr "192.168.22.0/24" -GE "28" -LE "32" -action PERMIT
        This example creates an NSX Prefix List in the workload domain NSX Manager cluster.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER tier0Gateway
        The NSX Tier0 Gateway name.

        .PARAMETER prefixListName
        The NSX Prefix List name.

        .PARAMETER subnetCidr
        The NSX Prefix List subnet CIDR.

        .PARAMETER ingressSubnetCidr
        The NSX Prefix List ingress subnet CIDR.

        .PARAMETER egressSubnetCidr
        The NSX Prefix List egress subnet CIDR.

        .PARAMETER GE
        The NSX Prefix List greater than or equal to value.

        .PARAMETER LE
        The NSX Prefix List less than or equal to value.

        .PARAMETER action
        The NSX Prefix List action.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier0Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$prefixListName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$subnetCidr,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ingressSubnetCidr,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$egressSubnetCidr,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$GE,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$LE,
        [Parameter (Mandatory = $true)] [ValidateSet("PERMIT", "DENY")] [String]$action
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                            if (Get-NsxtTier0Gateway -name $tier0Gateway) {
                                if (!(Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName -ErrorAction SilentlyContinue)) {
                                    Get-NsxtTier0Gateway -name $tier0Gateway | New-NsxtPrefixList -name $prefixListName -subnetCidr $subnetCidr -action $action | Out-Null
                                    if (Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName -ErrorAction SilentlyContinue) {
                                        Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName | Add-NsxtPrefix -subnetCidr $ingressSubnetCidr -GE $GE -LE $LE -action $action | Out-Null
                                        Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName | Add-NsxtPrefix -subnetCidr $egressSubnetCidr -GE $GE -LE $LE -action $action | Out-Null
                                        Write-Output "Adding NSX IP Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding NSX IP Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding NSX IP Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find NSX Tier0 Gateway ($tier0Gateway) in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-PrefixList

Function Undo-PrefixList {
    <#
        .SYNOPSIS
        The Undo-PrefixList cmdlet removes the NSX Prefix List from NSX Manager. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes an NSX Prefix List if not already removed from NSX Manager.

        .DESCRIPTION
        The Undo-PrefixList cmdlet removes an NSX Prefix List

        .EXAMPLE
        Undo-PrefixList -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -tier0Gateway sfo-w01-ec01-t0-gw01 -prefixListName sfo-w01-ec01-t0-gw01-mgmt-prefixlist
        This example removes an NSX Prefix List in the Workload Domain NSX Manager cluster.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER tier0Gateway
        The NSX Tier0 Gateway to connect to.

        .PARAMETER prefixListName
        The NSX Prefix List name to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier0Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$prefixListName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                            if (Get-NsxtTier0Gateway -name $tier0Gateway) {
                                if (Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName -ErrorAction SilentlyContinue) {
                                    Remove-NsxtPrefixList -name $prefixListName -tier0Gateway $tier0Gateway | Out-Null
                                    if (!(Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName -ErrorAction SilentlyContinue)) {
                                        Write-Output "Removing NSX IP Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing NSX IP Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing NSX IP Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName), does not exist: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find NSX Tier0 Gateway ($tier0Gateway) in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-PrefixList

Function Add-RouteMap {
    <#
        .SYNOPSIS
        The Add-RouteMap cmdlet creates NSX Prefix List in the NSX Manager cluster. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Create an NSX Route Map if not already created in NSX Manager.

        .DESCRIPTION
        The Add-RouteMap cmdlet creates an NSX Route Map

        .EXAMPLE
        Add-RouteMap -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -tier0Gateway sfo-w01-ec01-t0-gw01 -routeMapName sfo-w01-ec01-t0-gw01-routemap -prefixListName sfo-w01-ec01-t0-gw01-mgmt-prefixlist -action PERMIT -applyPolicy:$true
        This example creates an NSX Route Map in workload domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER tier0Gateway
        The NSX Tier0 Gateway to connect to.

        .PARAMETER routeMapName
        The NSX Route Map name to create.

        .PARAMETER prefixListName
        The NSX Prefix List name to create.

        .PARAMETER action
        The NSX Route Map action to create.

        .PARAMETER applyPolicy
        Specifies whether to apply the NSX Route Map to the NSX Tier0 Gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier0Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$routeMapName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$prefixListName,
        [Parameter (Mandatory = $true)] [ValidateSet("PERMIT", "DENY")][String]$action,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Bool]$applyPolicy
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                            if (Get-NsxtTier0Gateway -name $tier0Gateway) {
                                if (!(Get-NsxtRouteMap -tier0Gateway $tier0Gateway -name $routeMapName -ErrorAction SilentlyContinue)) {
                                    if (Get-NsxtTier0Gateway -name $tier0Gateway | Get-NsxtPrefixList -name $prefixListName -ErrorAction SilentlyContinue) {
                                        Get-NsxtTier0Gateway -name $tier0Gateway | New-NsxtRouteMap -name $routeMapName -prefixList $prefixListName -action $Action | Out-Null
                                        if (Get-NsxtRouteMap -tier0Gateway $tier0Gateway -name $routeMapName -ErrorAction SilentlyContinue) {
                                            if ($applyPolicy -eq $true) {
                                                Get-NsxtRouteRedistributionPolicy -tier0Gateway $tier0Gateway | Set-NsxtRouteRedistributionPolicy -routeMap $routeMapName | Out-Null
                                            }
                                            Write-Output "Adding NSX Route Map in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($routeMapName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding NSX Route Map in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($routeMapName): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find NSX Prefix List in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($prefixListName): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding NSX Route Map in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($routeMapName), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find NSX Tier0 Gateway ($tier0Gateway) in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-RouteMap

Function Undo-RouteMap {
    <#
        .SYNOPSIS
        The Undo-RouteMap cmdlet removes NSX Route Map from the NSX Manager cluster. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes an NSX Route Map from NSX Manager.

        .DESCRIPTION
        The Undo-RouteMap cmdlet removes an NSX Route Map

        .EXAMPLE
        Undo-RouteMap -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -tier0Gateway sfo-w01-ec01-t0-gw01 -routeMapName sfo-w01-ec01-t0-gw01-routemap
        This example removes an NSX Route Map in the workload domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER tier0Gateway
        The NSX Tier0 Gateway to connect to.

        .PARAMETER routeMapName
        The NSX Route Map name to create.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier0Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$routeMapName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                            if (Get-NsxtTier0Gateway -name $tier0Gateway) {
                                if (Get-NsxtRouteMap -tier0Gateway $tier0Gateway -name $routeMapName -ErrorAction SilentlyContinue) {
                                    Remove-NsxtRouteMap -name $routeMapName -tier0Gateway $tier0Gateway | Out-Null
                                    if (!(Get-NsxtRouteMap -tier0Gateway $tier0Gateway -name $routeMapName -ErrorAction SilentlyContinue)) {
                                        Write-Output "Removing NSX Route Map in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($routeMapName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing NSX Route Map in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($routeMapName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing NSX Route Map in NSX Manager ($($vcfNsxtDetails.fqdn)) named ($routeMapName), does not exist: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find NSX Tier0 Gateway ($tier0Gateway) in NSX Manager ($($vcfNsxtDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-RouteMap

Function Set-DatastoreTag {
    <#
        .SYNOPSIS
        The Function Set-DatastoreTag cmdlet creates and applies a vSphere Tag to the primary datastore. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Creates and applies a vSphere Tag to the primary datastore.

        .DESCRIPTION
        The Set-DatastoreTag cmdlet creates and applies a vSphere Tag to the primary datastore

        .EXAMPLE
        Set-DatastoreTag -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -tagName vsphere-with-tanzu-tag -tagCategoryName vsphere-with-tanzu-category
        This example creates a new tag and assigns it to the primary datastore of Workload Domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER tagName
        The vSphere Tag name to create.

        .PARAMETER tagCategoryName
        The vSphere Tag Category name to create.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tagName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tagCategoryName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $datastore = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).primaryDatastoreName
                                if ($datastoreExist = Get-Datastore -Name $datastore -ErrorAction SilentlyContinue | Where-Object {$_.Name -eq $datastore}) {
                                    if (!(Get-TagAssignment -Entity $datastoreExist.Name -Category $tagCategoryName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue)) {
                                        if (!(Get-TagCategory -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $tagCategoryName })) {
                                            New-TagCategory -Name $tagCategoryName -EntityType Datastore -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                        }
                                        if (!(Get-Tag -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $tagName })) {
                                            New-Tag -Name $tagName -Category $tagCategoryName -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                        }
                                        Get-Datastore -Name $Datastore -Server $vcfVcenterDetails.fqdn | New-TagAssignment -Tag $tagName -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                        if ((Get-TagAssignment -Entity $datastoreExist.Name -Category $tagCategoryName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue)) {
                                            Write-Output "Creating vSphere Tag ($tagName) and applying to datastore ($datastore) in vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating vSphere Tag ($tagName) and applying to datastore ($datastore) in vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Creating vSphere Tag ($tagName) and applying to datastore ($datastore) in vCenter Server ($($vcfVcenterDetails.fqdn)), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to find datastore ($datastore) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-DatastoreTag

Function Undo-DatastoreTag {
    <#
        .SYNOPSIS
        The Function Undo-DatastoreTag cmdlet removes a vSphere Category and Tag. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes the vSphere Tag.

        .DESCRIPTION
        The Undo-DatastoreTag cmdlet removes the vSphere Tag

        .EXAMPLE
        Undo-DatastoreTag -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -tagName vsphere-with-tanzu-tag -tagCategoryName vsphere-with-tanzu-category
        This example removes the vSphere tag from the Workload Domain sfo-w01 vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER tagName
        The name of the tag to remove.

        .PARAMETER tagCategoryName
        The name of the tag category to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tagName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tagCategoryName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-Tag -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore | Where-Object { $_.Name -eq $tagName }) {
                                    Remove-Tag -Tag $tagName -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                    Remove-TagCategory -Category $tagCategoryName -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                    if (!(Get-Tag -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $tagName })) {                                            
                                        Write-Output "Removing vSphere Tag ($tagName) and vSphere Category ($tagCategoryName) from vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"                                        
                                    } else {
                                        Write-Error "Removing vSphere Tag ($tagName) and vSphere Category ($tagCategoryName) from vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing vSphere Tag ($tagName) and Category ($tagCategoryName) from vCenter Server ($($vcfVcenterDetails.fqdn)), does not exist: SKIPPED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-DatastoreTag

Function Add-StoragePolicy {
    <#
        .SYNOPSIS
        The Add-StoragePolicy cmdlet creates a vSphere Storage Policy. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Creates a VM vSphere Storage Policy.

        .DESCRIPTION
        The Add-StoragePolicy cmdlet creates a VM vSphere Storage Policy

        .EXAMPLE
        Add-StoragePolicy -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -policyName vsphere-with-tanzu-storage-policy -tagName vsphere-with-tanzu-tag
        This example creates a VM Storage Policy named vsphere-with-tanzu-policy in the Wrkload Domain vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER policyName
        The name of the storage policy to create.

        .PARAMETER tagName
        The name of the tag to use for the storage policy.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$policyName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tagName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (!(Get-SpbmStoragePolicy -Name $policyName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue)) {
                                    if (Get-Tag -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $tagName }) {
                                        New-SpbmStoragePolicy -Name $policyName -AnyOfRuleSets (New-SpbmRuleSet -AllOfRules (New-SpbmRule -AnyOfTags $tagName -Server $vcfVcenterDetails.fqdn)) -Server $vcfVcenterDetails.fqdn | Out-Null
                                        if (Get-SpbmStoragePolicy -Name $policyName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue) {
                                            Write-Output "Creating Storage Policy in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($policyName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating Storage Policy in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($policyName): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find vSphere Tag ($tagName) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Creating Storage Policy in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($policyName), already exists: SKIPPED"                                    
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-StoragePolicy

Function Undo-StoragePolicy {
    <#
        .SYNOPSIS
        The Undo-StoragePolicy cmdlet removes a vSphere Storage Policy. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes a VM vSphere Storage Policy.

        .DESCRIPTION
        The Undo-StoragePolicy cmdlet removes a VM vSphere Storage Policy

        .EXAMPLE
        Undo-StoragePolicy -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -policyName vsphere-with-tanzu-storage-policy
        This example removes a VM Storage Policy named vsphere-with-tanzu-storage-policy from the Wrkload Domain vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER policyName
        The name of the storage policy to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$policyName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-SpbmStoragePolicy -Name $policyName -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore) {
                                    Remove-SpbmStoragePolicy -StoragePolicy $policyName -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                    if (!(Get-SpbmStoragePolicy -Name $policyName -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore)) {
                                        Write-Output "Removing Storage Policy in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($policyName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing Storage Policy in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($policyName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing Storage Policy in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($policyName), does not exist: SKIPPED"                                    
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-StoragePolicy

Function Add-ContentLibrary {
    <#
        .SYNOPSIS
        Creates a content library
    
        .DESCRIPTION
        The Add-ContentLibrary cmdlet creates a subscribed or published content library. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Creates a content library
    
        .EXAMPLE
        Add-ContentLibrary -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -contentLibraryName sfo-w01-lib01 -published
        This example creates published content library named sfo-w01-lib01 on the primary datastore in workload domain sfo-w01
    
        .EXAMPLE
        Add-ContentLibrary -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -contentLibraryName sfo-w01-lib01 -datastore sfo-w01-ds-nfs01 -published
        This example creates published content library named sfo-w01-lib01 on a specific datastore in workload domain sfo-w01
    
        .EXAMPLE
        Add-ContentLibrary -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -contentLibraryName Kubernetes -subscriptionUrl "https://wp-content.vmware.com/v2/latest/lib.json"
        This example creates subscribed content library named Kubernetes on the primary datastore in workload domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER contentLibraryName
        The name of the content library to create.

        .PARAMETER datastore
        The datastore to create the content library on.

        .PARAMETER subscriptionUrl
        The subscription URL to create the content library from.

        .PARAMETER published
        The content library to be published.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$contentLibraryName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$datastore,
        [Parameter (ParameterSetName = 'Subscription', Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$subscriptionUrl,
        [Parameter (ParameterSetName = 'Local', Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$published
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($subscriptionUrl -like "https://wp-content.vmware.com*") {
                    $vcfVersion = ((Get-VCFManager).version -Split ('\.\d{1}\-\d{8}')) -split '\s+' -match '\S'
                    if ($vcfVersion -ge "5.0.0") {
                        Write-Warning "Adding the content library is not required for VMware Cloud Foundation $vcfVersion and later when enabling Tanzu."
                        Break
                    }
                }
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (!(Get-ContentLibrary -Name $contentLibraryName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue)) {
                                    if (!$PsBoundParameters.ContainsKey('datastore')) {
                                        $datastore = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).primaryDatastoreName
                                    }
                                    if (Get-Datastore -Name $datastore -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue | Where-Object {$_.Name -eq $datastore}) {
                                        if ($subscriptionUrl) {
                                            $uri = New-Object System.Uri($subscriptionUrl)
                                            $port = if ($uri.AbsolutePath.Contains(':')) {
                                                $uri.AbsolutePath.Split(':')[-1] 
                                            } else {
                                                $uri.Port 
                                            }
                                            if ($port -eq -1) {
                                                $defaultPorts = @{ 'http' = 80; 'https' = 443 }
                                                $port = $defaultPorts[$uri.Scheme]
                                            }
                                            $fqdn = $uri.Host
                                            $port = [int]$port
                                            $client = New-Object System.Net.Sockets.TcpClient($fqdn, $port)
                                            $stream = $client.GetStream()
                                            $sslStream = New-Object System.Net.Security.SslStream($stream, $false, { $true })
                                            $sslStream.AuthenticateAsClient($fqdn)
                                            $sslCertificate = $sslStream.RemoteCertificate
                                            $sslThumbprint = $sslCertificate.GetCertHashString()
                                            $sslThumbprint = $sslThumbprint -replace '(..(?!$))', '$1:'
                                            New-ContentLibrary -Name $contentLibraryName -AutomaticSync -Datastore $datastore -SubscriptionUrl $subscriptionUrl -SslThumbprint $sslThumbprint -Server $vcfVcenterDetails.fqdn | Out-Null
                                        } elseif ($published) {                                      
                                            New-ContentLibrary -Name $contentLibraryName -Published -Datastore $datastore -Server $vcfVcenterDetails.fqdn | Out-Null
                                        }
                                        if (Get-ContentLibrary -Name $contentLibraryName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue) {
                                            Write-Output "Creating Content Library in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($contentLibraryName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating Content Library in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($contentLibraryName): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find Datastore named ($datastore) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Creating Content Library in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($contentLibraryName), already exists: SKIPPED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-ContentLibrary

Function Undo-ContentLibrary {
    <#
        .SYNOPSIS
        Remove Content Library.

        .DESCRIPTION
        The Undo-ContentLibrary cmdlet removes a content library. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Deletes a content library

        .EXAMPLE
        Undo-ContentLibrary -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -contentLibraryName sfo-w01-lib01
        This example removes the content library from the Workload Domain vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER contentLibraryName
        The content library name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$contentLibraryName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-ContentLibrary -Name $contentLibraryName -ErrorAction Ignore) {
                                    Remove-ContentLibrary -ContentLibrary $contentLibraryName -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                    if (!(Get-ContentLibrary -Name $contentLibraryName -ErrorAction Ignore)) {
                                        Write-Output "Removing Content Library from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($contentLibraryName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing Content Library from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($contentLibraryName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing Content Library from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($contentLibraryName), does not exist: SKIPPED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-ContentLibrary

Function Enable-SupervisorCluster {
    <#
        .SYNOPSIS
        Enables Workload Management on a VCF cluster.

        .DESCRIPTION
        The Enable-SupervisorCluster cmdlet enables Workload Management on a VCF cluster. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Performs validation of in puts unless skipped using a switch
        - Enables Workload Management on the vSphere cluster

        .EXAMPLE
        $wmClusterInput = @{
            server = "sfo-vcf01.sfo.rainpole.io"
            user = "administrator@vsphere.local"
            pass = 'VMw@re1!'
            domain = "sfo-w01"
            cluster = "sfo-w01-cl01"
            sizeHint = "Tiny"
            managementVirtualNetwork = "sfo-w01-kub-seg01"
            managementNetworkMode = "StaticRange"
            managementNetworkStartIpAddress = "192.168.20.10"
            managementNetworkAddressRangeSize = 5
            managementNetworkGateway = "192.168.20.1"
            managementNetworkSubnetMask = "255.255.255.0"
            masterDnsName = "sfo-w01-cl01.sfo.rainpole.io"
            masterDnsServers = @("172.16.11.4", "172.16.11.5")
            masterNtpServers = @("172.16.11.253", "172.16.12.253")
            contentLibrary = "Kubernetes"
            ephemeralStoragePolicy = "vsphere-with-tanzu-storage-policy"
            imageStoragePolicy = "vsphere-with-tanzu-storage-policy"
            masterStoragePolicy = "vsphere-with-tanzu-storage-policy"
            nsxEdgeCluster = "sfo-w01-ec01"
            distributedSwitch = "sfo-w01-cl01-vds01"
            podCIDRs = "100.100.0.0/20"
            serviceCIDR = "100.200.0.0/22"
            externalIngressCIDRs = "192.168.21.0/24"
            externalEgressCIDRs = "192.168.22.0/24"
            workerDnsServers = @("172.16.11.4", "172.16.11.5")
            masterDnsSearchDomain = "sfo.rainpole.io"
        }

        .EXAMPLE
        Enable-SupervisorCluster @wmClusterInput
        This example enables Workload Management on a vSphere Cluster in workload domain sfo-w01

        .EXAMPLE
        Enable-SupervisorCluster -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -sizeHint Tiny -managementVirtualNetwork sfo-w01-kub-seg01 -managementNetworkMode StaticRange -managementNetworkStartIpAddress 192.168.20.10 -managementNetworkAddressRangeSize 5 -managementNetworkGateway 192.168.20.1 -managementNetworkSubnetMask 255.255.255.0 -cluster sfo-w01-cl01 -contentLibrary Kubernetes -ephemeralStoragePolicy vsphere-with-tanzu-storage-policy -imageStoragePolicy vsphere-with-tanzu-storage-policy -masterStoragePolicy vsphere-with-tanzu-storage-policy -nsxEdgeCluster sfo-w01-ec01 -distributedSwitch sfo-w01-sfo-w01-vc01-sfo-w01-cl01-vds01 -podCIDRs "100.100.0.0/20" -serviceCIDR "100.200.0.0/22" -externalIngressCIDRs "192.168.21.0/24" -externalEgressCIDRs "192.168.22.0/24" -masterNtpServers @("172.16.11.253", "172.16.12.253") -masterDnsServers @("172.16.11.4", "172.16.11.5") -masterDnsName sfo-w01-cl01.sfo.rainpole.io -masterDnsSearchDomain sfo.rainpole.io -workerDnsServers @("172.16.11.4", "172.16.11.5")
        This example enables Workload Management on a vSphere Cluster in workload domain sfo-w01.

        .PARAMETER server
        The IP or FQDN of the SDDC Manager.

        .PARAMETER user
        The username used to connect to SDDC Manager.

        .PARAMETER pass
        The password used to connect to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain.

        .PARAMETER cluster
        The name of the vSphere cluster.

        .PARAMETER sizeHint
        The size of the vSphere cluster.

        .PARAMETER managementVirtualNetwork
        The name of the management virtual network.

        .PARAMETER managementNetworkMode
        The management network mode.

        .PARAMETER managementNetworkStartIpAddress
        The management network starting IP address.

        .PARAMETER managementNetworkAddressRangeSize
        The management network address range size.

        .PARAMETER managementNetworkGateway
        The management network gateway.

        .PARAMETER managementNetworkSubnetMask
        The management network subnet mask.

        .PARAMETER masterDnsName
        The master DNS name.

        .PARAMETER masterNtpServers
        The master NTP servers.

        .PARAMETER masterDnsServers
        The master DNS servers.

        .PARAMETER contentLibrary
        The name of the content library.

        .PARAMETER ephemeralStoragePolicy
        The name of the ephemeral storage policy.

        .PARAMETER imageStoragePolicy
        The name of the image storage policy.

        .PARAMETER masterStoragePolicy
        The name of the master storage policy.

        .PARAMETER nsxEdgeCluster
        The name of the NSX Edge cluster.

        .PARAMETER distributedSwitch
        The name of the distributed switch.

        .PARAMETER podCIDRs
        The pod CIDRs.

        .PARAMETER serviceCIDR
        The service CIDR.

        .PARAMETER externalIngressCIDRs
        The external ingress CIDRs.

        .PARAMETER externalEgressCIDRs
        The external egress CIDRs.

        .PARAMETER masterDnsSearchDomain
        The master DNS search domain.

        .PARAMETER workerDnsServers
        The worker DNS servers.

        .PARAMETER ConfigurationTimeoutSeconds
        The timeout in seconds for the configuration to complete.

        .PARAMETER skipValidation
        Skips the input parameter validation.

        .PARAMETER validateOnly
        Validates the input parameters and exits.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateSet("Tiny", "Small", "Medium", "Large")] [String]$sizeHint,
        [Parameter (Mandatory = $true)] [ValidateSet("DHCP", "StaticRange")][String]$managementNetworkMode,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$managementVirtualNetwork,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$managementNetworkStartIpAddress,
        [Parameter (Mandatory = $true)] [ValidateRange(5,10)][int]$managementNetworkAddressRangeSize,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$managementNetworkGateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$managementNetworkSubnetMask,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$masterDnsName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$masterNtpServers,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$masterDnsServers,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$contentLibrary,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ephemeralStoragePolicy,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$imageStoragePolicy,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$masterStoragePolicy,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxEdgeCluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$distributedSwitch,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$podCIDRs,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceCIDR,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$externalIngressCIDRs,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$externalEgressCIDRs,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$masterDnsSearchDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$workerDnsServers,
        [Parameter (Mandatory = $false)] [ValidateRange(300,18000)]$ConfigurationTimeoutSeconds=3600,
        [Parameter (Mandatory = $false)] [Switch]$skipValidation,
        [Parameter (Mandatory = $false)] [Switch]$validateOnly
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (!(Get-WMCluster -cluster $cluster -ErrorAction Ignore)) {
                                Request-vSphereApiToken -Fqdn $vcfVcenterDetails.fqdn -Username $vcfVcenterDetails.ssoadmin -Password $vcfVcenterDetails.ssoAdminPass | Out-Null
                                if (($vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                                    if (Test-NSXTConnection -server $vcfNsxtDetails.fqdn) {
                                        if (Test-NSXTAuthentication -server $vcfNsxtDetails.fqdn -user $vcfNsxtDetails.adminUser -pass $vcfNsxtDetails.adminPass) {
                                            [bool]$inputParameterValidation = $true
                                            #Check SkipValidation parameter
                                            if (($SkipValidation.isPreset)) {
                                                # Validate if vCenter uses 'local'
                                                if ($vcfVcenterDetails.fqdn) {
                                                    if (($vcfVcenterDetails.fqdn.split(".")[$_.count-1] -eq "local") -and ($masterDnsSearchDomain.split(".")[$_.count-1] -ne "local")) {
                                                        Write-Warning "'local' domain detected in ($(vcfVcenterDetails.fqdn)), make sure you have provided masterDnsSearchDomain ($masterDnsSearchDomain) to match"
                                                    }
                                                }
                                                # Validate management network inputs
                                                # Valid Starting IP Address is an actual IPv4 address
                                                if ($managementNetworkStartIpAddress) {
                                                    if (!(Test-IPaddressArray -IPaddressArray $managementNetworkStartIpAddress)) {
                                                        Write-Error "Invalid Management Network Start IP address ($managementNetworkStartIpAddress): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Valid Subnet Mask
                                                if ($managementNetworkSubnetMask) {
                                                    if (!(Test-IPaddressArray -IPaddressArray $managementNetworkSubnetMask)) {
                                                        Write-Error "Management Network Subnet Mask ($managementNetworkSubnetMask) validation failed: PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate Gateway IP Address is an actual IPv4 address and exists in the same subnet as the management starting address
                                                if ($managementNetworkGateway) {
                                                    Try {
                                                        if (Test-IPaddressArray $managementNetworkGateway) {
                                                            #Validate the Gateway IP address and the starting IP address are in the same subnet
                                                            $checkManagementNetworkGatewayInSubnet = $null
                                                            Try {
                                                                $checkManagementNetworkGatewayInSubnet = Test-IpAddress -IpAddress $managementNetworkGateway -Subnet "$managementNetworkStartIpAddress/$managementNetworkCidr"
                                                            } Catch {}
                                                            if ($checkManagementNetworkGatewayInSubnet.Validated -eq $false) {
                                                                Write-Error "Cannot validate the gateway IP address for the Management Network ($managementNetworkGateway) is from the same subnet as the Management Network Starting IP Address ($managementNetworkStartIpAddress/$managementNetworkCidr): PRE_VLALIDATION_FAILED"
                                                                $inputParameterValidation = $false
                                                            }
                                                        }
                                                    } Catch {
                                                        Write-Error "Invalid IP address ($managementNetworkGateway) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate Management Virtual Network (dvPortGroup) exists
                                                if ($ManagementVirtualNetwork) {
                                                    Try {
                                                        $checkManagementVirtualNetwork = Get-VirtualNetwork -Name $ManagementVirtualNetwork -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        #Do nothing
                                                    }
                                                    if (!$checkManagementVirtualNetwork -or !$managementVirtualNetwork) {
                                                        Write-Error "Invalid Management Virtual Network ($ManagementVirtualNetwork): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    } 
                                                }
                                                # Validate Ephemeral Storage Policy exists
                                                if ($ephemeralStoragePolicy){
                                                    $checkEphemeralStoragePolicy = $null
                                                    Try {
                                                        $checkEphemeralStoragePolicy = Get-SpbmStoragePolicy -Name $EphemeralStoragePolicy -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        #Do nothing
                                                    }
                                                    if (!$checkEphemeralStoragePolicy -or !$ephemeralStoragePolicy) {
                                                        Write-Error "Invalid Ephemeral Storage Policy ($EphemeralStoragePolicy): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate Image Storage Policy exists
                                                if ($imageStoragePolicy) {
                                                    $checkImageStoragePolicy = $null
                                                    Try {
                                                        $checkImageStoragePolicy = Get-SpbmStoragePolicy -Name $ImageStoragePolicy -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        #Do nothing
                                                    }
                                                    if (!$checkImageStoragePolicy -or !$imageStoragePolicy) {
                                                        Write-Error "Invalid Image Storage Policy ($ImageStoragePolicy): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate Master Storage Policy exists
                                                if ($masterStoragePolicy) {
                                                    $checkMasterStoragePolicy = $null
                                                    Try {
                                                        $checkMasterStoragePolicy = Get-SpbmStoragePolicy -Name $MasterStoragePolicy -ErrorAction SilentlyContinue
                                                    }Catch {
                                                        #Do nothing
                                                    }
                                                    if (!$checkMasterStoragePolicy -or !$masterStoragePolicy) {
                                                        Write-Error "Invalid Master Storage Policy ($MasterStoragePolicy): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate NSX Edge Cluster exists and lookup ID. TBD chech status of the Edge Cluster and TNs
                                                if ($nsxEdgeCluster) {
                                                    $nsxEdgeClusterId = $null
                                                    $checkNsxEdgeCluster = $null
                                                    Try {
                                                        $checkNsxEdgeCluster = Get-NsxEdgeCluster -Name $nsxEdgeCluster -ErrorAction SilentlyContinue
                                                        $nsxEdgeClusterId = $checkNsxEdgeCluster.Id
                                                    } Catch {
                                                        #Do nothing
                                                    }
                                                    if (!$nsxEdgeClusterId -or !$nsxEdgeCluster) {
                                                        Write-Error "Invalid NSX Edge Cluster ($NsxEdgeCluster): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate control plane NTP servers exist and are functional
                                                if ($masterNtpServers) {
                                                    Foreach ($masterNtpServer in $masterNtpServers) {
                                                        $checkNtpServer = $null
                                                        $checkNtpServer = Test-ntpServer $masterNtpServer
                                                        if (!($checkNtpServer)) {
                                                            Write-Error "Invalid master NTP server ($masterNtpServer) : PRE_VALIDATION_FAILED"
                                                            $inputParameterValidation = $false
                                                        }
                                                    }
                                                }
                                                # Validate control plane DNS servers exist and are functional
                                                if ($masterDnsServers) {
                                                    $checkDnsServers = $null
                                                    $checkDnsServers = Test-DnsServers $masterDnsServers
                                                    if (!($checkDnsServers)) {
                                                        Write-Error "Invalid master dns servers ($masterDnsServers) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate worker DNS servers exist and are functional
                                                if ($workerDnsServers) {
                                                    $checkDnsServers = $null
                                                    $checkDnsServers = Test-DnsServers $workerDnsServers
                                                    if (!($checkDnsServers)) {
                                                        Write-Error "Invalid worker dns servers ($workerDnsServers) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate ContentLibrary exists
                                                #Full validation (checking type, subscription, etc.) is TBD
                                                if ($contentLibrary) {
                                                    $checkContentLibrary = $null
                                                    Try {
                                                        $checkContentLibrary = Get-SubscribedLibrary -Name $contentLibrary -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        Debug-ExceptionWriter -object $_
                                                    }
                                                    if ($checkContentLibrary.Name -ne $contentLibrary -or !$contentLibrary) {
                                                        Write-Error "Invalid Content Library ($contentLibrary): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    } 
                                                }
                                                # Validate Distributed Virtual Switch exists
                                                if ($distributedSwitch) {
                                                    $checkDistributedSwitch = $null
                                                    Try {
                                                        $checkDistributedSwitch = Get-VDSwitch -Name $distributedSwitch -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        Debug-ExceptionWriter -object $_
                                                    }
                                                    if ($checkDistributedSwitch.Name -ne $distributedSwitch -or !$distributedSwitch) {
                                                        Write-Error "Invalid Virtual Distributed Switch ($distributedSwitch): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    } 
                                                } 
                                                # Validates Pod subnet inputs are formatted correctly and sized to meet minimum requirements
                                                if ($podCIDRs) {
                                                    $checkPodCidr = $null
                                                    $checkPodCidr = Test-WMSubnetInput -Subnet $podCIDRs -SubnetType "Pod"
                                                    if (!($checkPodCidr)) {
                                                        Write-Error "Invalid podCIDRs ($podCIDRs) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validates Service subnet inputs are formatted correctly and sized to meet minimum requirements
                                                if ($serviceCIDR) {
                                                    $checkServiceCidr = $null
                                                    $checkServiceCidr = Test-WMSubnetInput -Subnet $serviceCIDR -SubnetType "Service"
                                                    if (!($checkServiceCidr)) {
                                                        Write-Error "Invalid ServiceCIDR ($serviceCIDR) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validates Ingress subnet inputs are formatted correctly and sized to meet minimum requirements
                                                if ($externalIngressCIDRs) {
                                                    $checkIngressCidr = $null
                                                    $checkIngressCidr = Test-WMSubnetInput -Subnet $serviceCIDR -SubnetType "Ingress"
                                                    if (!($checkIngressCidr)) {
                                                        Write-Error "Invalid IngressCIDR ($externalIngressCIDRs) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validates Egress subnet inputs are formatted correctly and sized to meet minimum requirements
                                                if ($externalEgressCIDRs) {
                                                    $checkEgressCidr = $null
                                                    $checkEgressCidr = Test-WMSubnetInput -Subnet $externalEgressCIDRs -SubnetType "Egress"
                                                    if (!($checkEgressCidr)) {
                                                        Write-Error "Invalid EgressCIDR ($externalEgressCIDRs) : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate control plane Kubernetes API endpoint is valid and in DNS
                                                # TBD as this is not mandatory parameter
                                                if ($masterDnsName) {
                                                    foreach ($dnsName in $masterDnsName) {
                                                        $checkDnsName = $null
                                                        Try {
                                                            $checkDnsName = Resolve-DnsName -Name $DnsName -Type A -QuickTimeout -ErrorAction Stop
                                                        } Catch [System.ComponentModel.Win32Exception] {
                                                            Write-Error "Invalid control plane DNS name ($DnsName): PRE_VALIDATION_FAILED"
                                                            $inputParameterValidation = $false
                                                        }
                                                        if ($checkDnsName) {
                                                            $checkMasterIpAddress = $null
                                                            Try {
                                                                $checkMasterIpAddress = Test-IpAddress -IpAddress $checkDnsName.Answers[0].Address.IPAddressToString -Subnet $externalIngressCIDRs
                                                            } Catch {
                                                                #Do nothing
                                                            }
                                                            if ($checkMasterIpAddress.Validated -eq $false) {
                                                                Write-Error -Message "Cannot validate the IP address for $DnsName ($DnsNameIpAddress) is from the external ingress CIDR ($externalIngressCIDRs). : PRE_VALIDATION_FAILED"
                                                                $inputParameterValidation = $false
                                                            }
                                                        }
                                                    }
                                                }
                                                # Validate master DNS search domain is formatted correctly and exists in DNS
                                                if ($masterDnsSearchDomain) {
                                                    $checkMasterDnsSearchDomain = $null
                                                    Try {
                                                        $checkMasterDnsSearchDomain = Resolve-DnsName -Name $masterDnsSearchDomain -Type A -QuickTimeout -ErrorAction Stop
                                                    } Catch [System.ComponentModel.Win32Exception] {
                                                        Write-Error "Invalid control plane DNS search domain ($masterDnsSearchDomain): PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # Validate vSphere license is in place
                                                Try {
                                                    $checkLicense = Get-WMLicenseStatus -server $server -domain $domain -ErrorAction SilentlyContinue
                                                    if ($checkLicense.namespaces_licensed -eq $false) {
                                                        Write-Error -Message "The vSphere license applied to cluster $cluster does not support Workload Management or is expired. Please resolve this and try again : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    } elseif ($checklicense.namespaces_supported -eq $false) {
                                                        Write-Error -Message "The cluster $cluster does not support Workload Management. Please resolve this and try again. : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                } Catch {
                                                    Debug-ExceptionWriter -object $_
                                                }
                                                # Validate the cluster is present
                                                if ($cluster) {
                                                    $checkCluster = $null
                                                    Try {
                                                        $checkCluster = Get-Cluster -Name $cluster -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        #Do nothing
                                                    }
                                                    if (!$checkCluster -or ($checkCluster.Name -ne $cluster)) {
                                                        Write-Error "Invalid vSphere cluster $cluster. : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                    $checkWmCluster = $null
                                                    Try {
                                                        $checkWmCluster = Get-WMCluster -Cluster $cluster -ErrorAction SilentlyContinue
                                                    } Catch {
                                                        #Do nothing
                                                    }
                                                    if ($checkWmCluster) {
                                                        Write-Error "Cluster $cluster is already enabled for Workload management : PRE_VALIDATION_FAILED"
                                                        $inputParameterValidation = $false
                                                    }
                                                }
                                                # If any of the prevalidation failed
                                                if ($inputParameterValidation) {
                                                    Write-Output "Pre-validation : SUCESSFULL" 
                                                } else {
                                                    Write-Error "At least one input parameter validation failed : PRE_VALIDATION_FAILED"
                                                    Break
                                                }
                                            }
                                            # TBD MasterDnsServerIpAddress = $masterDnsServers
                                            if ($inputParameterValidation) {
                                                $internalWMClusterInput = @{
                                                    SizeHint                          = $SizeHint
                                                    ManagementVirtualNetwork          = (Get-VirtualNetwork -Name $managementVirtualNetwork)
                                                    ManagementNetworkMode             = $managementNetworkMode
                                                    ManagementNetworkStartIpAddress   = $managementNetworkStartIpAddress
                                                    ManagementNetworkAddressRangeSize = $managementNetworkAddressRangeSize
                                                    ManagementNetworkGateway          = $managementNetworkGateway
                                                    ManagementNetworkSubnetMask       = $managementNetworkSubnetMask
                                                    MasterDnsNames                    = $masterDnsName
                                                    MasterNtpServer                   = $masterNtpServers
                                                    Cluster                           = (Get-Cluster -Name $cluster)
                                                    ContentLibrary                    = $contentLibrary
                                                    EphemeralStoragePolicy            = (Get-SpbmStoragePolicy -Name $ephemeralStoragePolicy)
                                                    ImageStoragePolicy                = (Get-SpbmStoragePolicy -Name $imageStoragePolicy)
                                                    MasterStoragePolicy               = (Get-SpbmStoragePolicy -Name $masterStoragePolicy)
                                                    NsxEdgeClusterId                  = ((Get-NsxEdgeCluster -Name $nsxEdgeCluster).id)
                                                    DistributedSwitch                 = (Get-VDSwitch -Name $distributedSwitch)
                                                    PodCIDRs                          = $podCIDRs
                                                    ServiceCIDR                       = $serviceCIDR
                                                    ExternalIngressCIDRs              = $externalIngressCIDRs
                                                    ExternalEgressCIDRs               = $externalEgressCIDRs
                                                    WorkerDnsServer                   = $workerDnsServers
                                                    MasterDnsServerIpAddress          = $masterDnsServers
                                                    MasterDnsSearchDomain             = $masterDnsSearchDomain
                                                }
                                            }
                                            if ($ValidateOnly.isPresent) {
                                                Write-Output "Validation completed : SUCCESSFUL"
                                            } else {
                                                Enable-WMCluster @internalWMClusterInput -RunAsync -ConfigurationTimeoutSeconds $ConfigurationTimeoutSeconds | Out-Null
                                                Write-Output  "Submitted Creation of Supervisor Cluster $cluster in vCenter Server $($vcfVcenterDetails.fqdn). This may take a while to complete. Operation will timeout after ($ConfigurationTimeoutSeconds) seconds"
                                                $startSleep = 300
                                                $SleepTime = 60
                                                Start-Sleep $startSleep
                                                if (Get-WMCluster -Cluster $cluster -ErrorAction SilentlyContinue) {
                                                    Watch-WmClusterConfigStatus -wmClusterName $cluster -sleepTime $SleepTime -retriesCount (($ConfigurationTimeoutSeconds-$startSleep)/$sleepTime)
                                                }
                                            }
                                        }
                                    }
                                }
                            } else {
                                Write-Warning "Deploying Kubernetes Supervisor Cluster, already deployed: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Enable-SupervisorCluster

Function Undo-SupervisorCluster {
    <#
        .SYNOPSIS
        Remove Supervisor Cluster.

        .DESCRIPTION
        The Undo-SupervisorCluster cmdlet removes the Supervisor Cluster from a Workload Domain. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Performs validation of in puts unless skipped using a switch
        - Disables Workload Management on the vSphere cluster

        .EXAMPLE
        Undo-SupervisorCluster -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -cluster sfo-w01-cl01
        This example disables Workload Management on a vSphere Cluster in workload domain sfo-w01.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username of the SDDC Manager account with permissions to request a certificate.

        .PARAMETER pass
        The password of the SDDC Manager account with permissions to request a certificate.

        .PARAMETER domain
        The name of the Workload Domain.

        .PARAMETER cluster
        The name of the vSphere Cluster.

        .PARAMETER RunAsync
        Run the cmdlet in the background.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$RunAsync
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Test-vSphereApiConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-vSphereApiAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        if (Get-WMCluster -cluster $cluster -ErrorAction Ignore) {
                                            if (!$PsBoundParameters.ContainsKey("RunAsync")) {
                                                Disable-WMCluster -WMCluster $cluster -RunAsync -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                            } else {
                                                Disable-WMCluster -WMCluster $cluster -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                            }
                                            if (!(Get-WMCluster -cluster $cluster -ErrorAction Ignore)) {
                                                Write-Output "Removing Supervisor Cluster ($cluster) from vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removing Supervisor Cluster ($cluster) from vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Removing Supervisor Cluster ($cluster) from vCenter Server ($($vcfVcenterDetails.fqdn)), does not exist: SKIPPED"
                                        }
                                    }
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SupervisorCluster

Function New-SupervisorClusterCSR {
    <#
        .SYNOPSIS
        Create a new certificate signing request for the defined Supervisor Cluster.

        .DESCRIPTION
        The New-SupervisorClusterCSR cmdlet creates a new certificate signing request for the defined Supervisor
        Cluster. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Requests the certificate signing request file

        .EXAMPLE
        New-SupervisorClusterCSR -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -cluster sfo-w01-cl01 -commonName sfo-m01-cl01.sfo.rainpole.io -organization Rainpole -organizationalUnit Rainpole -country US -stateOrProvince California -locality "Palo Alto" -adminEmailAddress admin@rainpole.io -keySize 2048 -filePath ".\SupervisorCluster.csr"
        This example returns a certificate signing request for the Supervisor Cluster sfo-w01-cl01 in Workload domain sfo-w01.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username of the SDDC Manager account with permissions to request a certificate.

        .PARAMETER pass
        The password of the SDDC Manager account with permissions to request a certificate.

        .PARAMETER domain
        The name of the Workload Domain.

        .PARAMETER cluster
        The name of the vSphere Cluster.

        .PARAMETER commonName
        The common name of the certificate.

        .PARAMETER organization
        The organization name of the certificate.

        .PARAMETER organizationalUnit
        The organizational unit name of the certificate.

        .PARAMETER country
        The country name of the certificate.

        .PARAMETER stateOrProvince
        The state or province name of the certificate.

        .PARAMETER locality
        The locality name of the certificate.

        .PARAMETER adminEmailAddress
        The email address of the certificate administrator.

        .PARAMETER keySize
        The key size of the certificate.

        .PARAMETER filePath
        The file path of the certificate signing request file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$commonName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$organization,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$organizationalUnit,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$country,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$stateOrProvince,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$locality,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adminEmailAddress,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$keySize,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$filePath
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Test-vSphereApiConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-vSphereApiAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        if ($PsBoundParameters.ContainsKey("keySize")) {
                                            Request-WMClusterCSR -cluster $cluster -commonName $commonName -organization $organization -organizationalUnit $organizationalUnit -country $country -stateOrProvince $stateOrProvince -locality $locality -adminEmailAddress $adminEmailAddress -keySize $keySize -filePath $filePath | Out-Null
                                        } else {
                                            Request-WMClusterCSR -cluster $cluster -commonName $commonName -organization $organization -organizationalUnit $organizationalUnit -country $country -stateOrProvince $stateOrProvince -locality $locality -adminEmailAddress $adminEmailAddress -filePath $filePath | Out-Null
                                        }
                                        if (Test-Path -Path $filePath) {
                                            Write-Output "Creating Certificate Signing Request (.csr) file for ($commonName) to file ($filePath): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating Certificate Signing Request (.csr) file for ($commonName) to file ($filePath): POST_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-SupervisorClusterCSR

Function Request-SignedCertificate {
    <#
        .SYNOPSIS
        Request a Signed Certificate from a Microsoft Enterprise Certificate Authority by providing generated
        Certificate Signing Request (CSR) file.

        .DESCRIPTION
        The Request-SignedCertificate cmdlet requests a Signed Certificate from a Microsoft Enterprise Certificate
        Authority by providing Certificate Signing Request (CSR) file. Issued certificate is written to Base64-encoded
        output file.

        .EXAMPLE
        Request-SignedCertificate -mscaComputerName dc-rpl01.rainpole.io -mscaName rainpole-DC-RPL01-CA -domainUsername "administrator@rainpole.io" -domainPassword "VMw@re1!" -certificateTemplate VMware -certificateRequestFile "c:\temp\SupervisorCluster.csr" -CertificateFile "c:\temp\SupervisorCluster.cer"
        This example requests a Signed Certificate from a Microsoft Enterprise Certificate Authority providing certificate signing request in file "c:\temp\SupervisorCluster.csr" and if the CA policy is configured to automaticaly issue certificate the certificate will be issued to Base64-encoded output file "c:\temp\SupervisorCluster.cer" .

        .PARAMETER mscaComputerName
        The IP address or FQDN of the Microsoft Enterprise Certificate Authority.

        .PARAMETER mscaName
        The name of the Microsoft Enterprise Certificate Authority.

        .PARAMETER domainUsername
        The username of the domain account with permissions to request a certificate from the Microsoft Enterprise Certificate Authority.

        .PARAMETER domainPassword
        The password of the domain account with permissions to request a certificate from the Microsoft Enterprise Certificate Authority.

        .PARAMETER certificateTemplate
        The name of the certificate template to use when requesting a certificate from the Microsoft Enterprise Certificate Authority.

        .PARAMETER certificateRequestFile
        The path to the certificate signing request file.

        .PARAMETER certificateFile
        The path to the Base64-encoded output file.

        .PARAMETER SkipValidation
        Skip pre-validation checks.

        .PARAMETER ValidateOnly
        Only perform pre-validation checks.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$mscaComputerName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$mscaName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainUsername,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainPassword,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificateTemplate = "webserver",
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateRequestFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateFile,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$SkipValidation,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$ValidateOnly
    )

    Try {
        [Bool]$preValidation = $true
        if (!($SkipValidation.IsPresent)) {
            # Validate if CSR exists
            if (!(Test-Path -Path $certificateRequestFile -ErrorAction SilentlyContinue)) {
                Write-Error "Certificate Signning Request (CSR) file ($certificateRequestFile) not found: PRE_VALIDATION_FAILED"
                $preValidation = $false
            }
            # Validate if output file exisits
            if ((Test-Path -Path $certificateFile -ErrorAction SilentlyContinue)) {
                Write-Error "Certificate file ($certificateFile) already exists: PRE_VALIDATION_FAILED"
                $preValidation = $false
            }
            # Validate if can get Win32_ComputerSystem
            $cimPass = ConvertTo-SecureString -String $domainPassword -AsPlainText -Force
            $cimCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $domainUsername, $cimPass
            $cimCreds | Export-Clixml -Path "$(Get-Location)\cimCreds.xml"
            $importedCimCreds = Import-Clixml -Path "$(Get-Location)\cimCreds.xml"
            $cimSession = New-CimSession -ComputerName $mscaComputerName -Credential $importedCimCreds
            $cimInstance = Get-CimInstance -CimSession $cimSession -ClassName Win32_ComputerSystem
            Remove-Item -Path "$(Get-Location)\cimCreds.xml"
            if ($cimInstance.PSComputerName -ne $mscaComputerName){
                Write-Error "Getting Win32_ComputerSystem object for ($mscaComputerName): PRE_VALIDATION_FAILED"
                $preValidation = $false
            }
            # Validate if can connect on port 135
            if ((Test-NetConnection -ComputerName $mscaComputerName -Port 135 -ErrorAction SilentlyContinue).TcpTestSucceeded -ne $true) {
                Write-Error "Connecting to ($mscaComputerName) on port 135: PRE_VALIDATION_FAILED"
                $preValidation = $false
            }
        }
        if ($preValidation) {
            if (!($ValidateOnly.isPresent)) {
                $CertificateAttributes = "CertificateTemplate:$certificateTemplate"
                $commandToExecute = "certreq -submit -f -q -UserName $domainUsername -p $domainPassword -config `"$mscaComputerName`\$mscaName`" -attrib `"$CertificateAttributes`" $certificateRequestFile $certificateFile"
                $resultExecution = Invoke-Expression -Command $commandToExecute
                Start-Sleep 5
                if ($resultExecution -match "(Issued)") {
                    Write-Output "Issued certificate ($certificateFile): SUCCESSFUL"
                } else {
                    Write-Error "Certificate issuing to file ($certificateFile) failed with ($resultExecution): FAILED"
                    Break
                }
            } else {
                Write-Output "Pre-validate Only: SUCCESSFUL"
            }
        } else {
            Write-Error "At least one Pre-Validation check failed: PRE_VALIDATION_FAILED"
            Break
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Request-SignedCertificate

Function Install-SupervisorClusterCertificate {
    <#
        .SYNOPSIS
        Add a signed TLS certificate for the defined Supervisor Cluster.

        .DESCRIPTION
        The Install-SupervisorClusterCertificate cmdlet adds a signed TLS certificate for the defined Supervisor
        Cluster. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Installs the Signed Certificate to the Supervisor Cluster

        .EXAMPLE
        Install-SupervisorClusterCertificate -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -Cluster sfo-w01-cl01 -FilePath ".\SupervisorCluster.cer"
        This example applies the signed TLS certificate to Supervisor Cluster sfo-w01-cl01 in Workload domain sfo-w01.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the Workload Domain.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER filePath
        The path to the signed TLS certificate file (.cer).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$filePath
    )

    if (!$PsBoundParameters.ContainsKey("filePath")) {
        $filePath = Get-ExternalFileName -title "Select the Supervisor Cluster Certificate File (.cer)" -fileType "cer" -location "default"
    } elseif ($PsBoundParameters.ContainsKey("filePath")) {
        if (!(Test-Path -Path $filePath)) {
            Write-Error "Certificate (cer) file for the Supervisor Cluster '$filePath' File Not Found"
            Break
        }
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                Request-vSphereApiToken -fqdn $vcfVcenterDetails.fqdn -username $vcfVcenterDetails.ssoAdmin -password $vcfVcenterDetails.ssoAdminPass | Out-Null
                                $response = Install-WMClusterCertificate -cluster $cluster -filePath $filePath
                                if ($response -match "successfully applied") {
                                    Write-Output "Installing Signed Certificate ($filePath) to Supervisor Cluster ($cluster): SUCCESSFUL"
                                } else {
                                    Write-Error "Installing Signed Certificate ($filePath) to Supervisor Cluster ($cluster): POST_VALIDATION_FAILED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-SupervisorClusterCertificate

Function Add-SupervisorClusterLicense {
    <#
        .SYNOPSIS
        Adds a Supervisor Cluster license.

        .DESCRIPTION
        The Add-SupervisorClusterLicense cmdlet adds a Supervisor Cluster licence. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Adds a new Supervisor Cluster license

        .EXAMPLE
        Add-SupervisorClusterLicense -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -Cluster sfo-w01-cl01 -LicenseKey "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
        This example adds a license to the Supervisor Cluster sfo-w01-cl01 in Workload domain sfo-w01.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the Workload Domain.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER licenseKey
        The license key to add to the Supervisor Cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$licenseKey
    )
    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if ($clusterId = ((Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).clusters | Where-Object {$_.id -eq (Get-VCFCluster | Where-Object {$_.name -eq $cluster}).id}).id){
                            if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                    Connect-vSphereMobServer -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass | Out-Null
                                    if (!(Get-VCFLicenseKey | Where-Object {$_.key -eq $licenseKey})) {
                                        New-VCFLicenseKey -key $licenseKey -productType WCP -description "WCP license"
                                        Start-Sleep 10
                                        if (Get-VCFLicenseKey | Where-Object {$_.key -eq $licenseKey}) {
                                            Write-Output "Adding Tanzu License Key ($licenseKey) in SDDC Manager ($sddcManager): SUCCESSFUL"
                                            $clusterId = ((Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).clusters | Where-Object {$_.id -eq (Get-VCFCluster | Where-Object {$_.name -eq $cluster}).id}).id
                                            $uri = "https://$sddcManager/v1/wcps/$clusterId/licensing"
                                            $json = '{"licenseKey": "'+ $licenseKey +'"}'
                                            $response = Invoke-RestMethod -Method POST -URI $uri -headers $headers -ContentType application/json -body $json
                                            Try {
                                                Do {
                                                    $taskStatus = (Get-VCFTask -id $response.id).status
                                                    Start-Sleep 10
                                                } While ($taskStatus -eq "In Progress")
                                                if ($taskStatus -eq "Successful") {
                                                    Write-Output "Assign license key ($licenseKey) to Supervisior cluster ($cluster): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Unable to validate license key ($licenseKey) was properly added to Supervisor Cluster ($cluster): POST_VALIDATION_FAILED"
                                                } 
                                            } Catch {
                                                Debug-ExceptionWriter -object $_
                                            }
                                        } else {
                                            Write-Error "Adding Tanzu License Key ($licenseKey) in SDDC Manager ($sddcManager): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Adding Tanzu License Key ($licenseKey) in SDDC Manager ($sddcManager), already exists: SKIPPED"
                                    }
                                }
                                Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                            }
                        } else {
                            Write-Error "Unable to find cluster named ($cluster) in the Workload Domain named ($domain) in the invenotry of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-SupervisorClusterLicense

Function Add-Namespace {
    <#
        .SYNOPSIS
        Creates a Namespace and applies extra configuration to it.

        .DESCRIPTION
        The Add-Namespace cmdlet creates a Namespace and applies its configuration. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Creates the Namespace

        .EXAMPLE
        Add-Namespace -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -cluster sfo-w01-cl01 -namespace sfo-w01-ns01 -storagePolicy vsphere-with-tanzu-storage-policy
        This example creates a Namespace named sfo-w01-ns01 in the Supervisor Cluster sfo-w01-cl01 with a vSphere Storage Policy vsphere-with-tanzu-storage-policy.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The Active Directory domain.

        .PARAMETER cluster
        The vSphere Cluster name.

        .PARAMETER namespace
        The Namespace name.

        .PARAMETER storagePolicy
        The vSphere Storage Policy name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$storagePolicy
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (!(Get-WMNamespace -Name $namespace -ErrorAction SilentlyContinue)) {
                                    if (Get-Cluster -Name $cluster -ErrorAction SilentlyContinue) {
                                        if (Get-SpbmStoragePolicy -Name $storagePolicy -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue) {
                                            New-WMNamespace -Name $namespace -Cluster $cluster | Out-Null
                                            if (Get-WMNamespace -Name $namespace -ErrorAction SilentlyContinue) {
                                                New-WMNamespaceStoragePolicy -Namespace $namespace -StoragePolicy $storagePolicy | Out-Null
                                                Write-Output "Creating Namespace ($namespace) in Supervisor Cluster ($cluster) in vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Creating Namespace ($namespace) in Supervisor Cluster ($cluster) in vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Unable to find vSphere Storage Policy ($storagePolicy) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error  "Unable to find Cluster ($cluster) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Creating Namespace ($namespace) in Supervisor Cluster ($cluster) in vCenter Server ($($vcfVcenterDetails.fqdn)), already exists: SKIPPED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-Namespace

Function Undo-Namespace {
    <#
        .SYNOPSIS
        Remove a Namespace.

        .DESCRIPTION
        The Undo-Namespace cmdlet removes a Namespace from the Supervisor Cluster. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes a Namespace

        .EXAMPLE
        Undo-Namespace -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -namespace sfo-w01-ns02
        This example removes the Namespace named sfo-w01-ns02.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The Active Directory domain.

        .PARAMETER namespace
        The Namespace name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-WMNamespace -Name $namespace -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore) {
                                    Remove-WMNamespace -Namespace $namespace -Server $vcfVcenterDetails.fqdn -Confirm:$false | Out-Null
                                    if (!(Get-WMNamespace -Name $namespace -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore)) {
                                        Write-Output "Removing Namespace ($namespace) from vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing Namespace ($namespace) from vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing Namespace ($namespace) from vCenter Server ($($vcfVcenterDetails.fqdn)), does not exist: SKIPPED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-Namespace

Function Add-NamespacePermission {
    <#
        .SYNOPSIS
        Adds permissions to a Namespace.

        .DESCRIPTION
        The Add-NamespacePermission cmdlet adds permissions to a Namespace. The cmdlet connects to SDDC Manager using
        the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Assigns permissions to a Namespace

        .EXAMPLE
        Add-NamespacePermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-w01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -namespace sfo-w01-ns01 -principal gg-kub-admins -role edit -type group
        This example adds the edit role to the group gg-kub-admins in the domain sfo.rainpole.io to the Namespace sfo-w01-ns01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The SDDC Manager domain.

        .PARAMETER domain
        The Active Directory domain.

        .PARAMETER domainBindUser
        The Active Directory user account.

        .PARAMETER domainBindPass
        The Active Directory user password.

        .PARAMETER namespace
        The Namespace name.

        .PARAMETER principal
        The Active Directory group or user name.

        .PARAMETER role
        The role to assign to the group or user.

        .PARAMETER type
        The type of the principal (group or user).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("edit", "view")] [String]$role,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type
    )

    Try {
        $checkAdAuthentication = Test-ADAuthentication -user $domainBindUser -pass $domainBindPass -server $domain -domain $domain -ErrorAction SilentlyContinue
        if ($checkAdAuthentication[1] -match "Authentication Successful") {
            $securePass = ConvertTo-SecureString -String $domainBindPass -AsPlainText -Force
            $domainCreds = New-Object System.Management.Automation.PSCredential ($domainBindUser, $securePass)
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $sddcDomain }) {
                        if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                            if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                    if (Get-WMNamespace -Name $namespace -ErrorAction SilentlyContinue) {
                                        if ($type -eq "group") { $adObjectCheck = (Get-ADGroup -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal }) }
                                        elseif ($type -eq "user") { $adObjectCheck = (Get-ADUser -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal }) }
                                        if ($adObjectCheck) {
                                            # TODO: A temporary fix until issue with Get-WMNamespacePermission is resolved.
                                            # if (!(Get-WMNamespacePermission -Namespace $namespace -Domain $domain -PrincipalName $principal)) {
                                            Request-vSphereApiToken -fqdn $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass | Out-Null
                                            $uri = "https://$($vcfVcenterDetails.fqdn)/api/vcenter/namespaces/instances/$namespace"
                                            $getWMNamespace = Invoke-RestMethod -Method 'GET' -URI $uri -Headers $vcApiHeaders
                                            if (($getWMNamespace.access_list.subject -contains $principal) -eq $false){
                                                # TODO: A temporary fix until issue with Get-WMNamespacePermission is resolved.
                                                # New-WMNamespacePermission -Namespace $namespace -Role $role -Domain $domain -PrincipalType $type -PrincipalName $principal | Out-Null
                                                $type = $type.ToUpper()
                                                $role = $role.ToUpper()
                                                $uri = "https://$($vcfVcenterDetails.fqdn)/api/vcenter/namespaces/instances/$namespace/access/$domain/"+ $principal +"?type=$type"
                                                $json = '{"role": "'+ $role +'"}'
                                                Invoke-RestMethod -Method 'POST' -URI $uri -Body $json -Headers $vcApiHeaders | Out-Null
                                                $getWMNamespacePost = Invoke-RestMethod -Method 'GET' -URI https://$($vcfVcenterDetails.fqdn)/api/vcenter/namespaces/instances/$namespace -Headers $vcApiHeaders
                                                if (($getWMNamespacePost.access_list.subject -contains $principal) -eq $true) {
                                                    Write-Output "Assigning Role ($role) to $type ($principal) in Namespace ($namespace): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Assigning Role ($role) to $type ($principal) in Namespace ($namespace): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Warning "Assigning Role ($role) to $type ($principal) in Namespace ($namespace), already assigned: SKIPPED"
                                            }
                                        } else {
                                            Write-Error "Active Directory $type ($principal) not found in the Active Directory Domain: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find Namespace ($namespace) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                    }
                                }
                                Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    } else {
                        Write-Error "Unable to find Workload Domain named ($sddcDomain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                    }
                }
            }
        } else {
            Write-Error "Unable to authenticate to Active Directory with user ($domainBindUser) and password ($domainBindPass), check details: PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NamespacePermission

Function Undo-NamespacePermission {
    <#
        .SYNOPSIS
        Remove permissions from a Namespace.

        .DESCRIPTION
        The Undo-NamespacePermission cmdlet removes a permissions from a Namespace. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes permissions from a Namespace

        .EXAMPLE
        Undo-NamespacePermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-w01 -namespace sfo-w01-ns01 -principal gg-kub-admins
        This example removes the edit role from the Namespace sfo-w01-ns01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the workload domain to run against.

        .PARAMETER namespace
        The Namespace name.

        .PARAMETER principal
        The Active Directory group or user name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $sddcDomain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-WMNamespace -Name $namespace -ErrorAction SilentlyContinue) {
                                    if (Get-WMNamespacePermission -Namespace $namespace -PrincipalName $principal) {
                                        Get-WMNamespacePermission -Namespace $namespace -PrincipalName $principal | Remove-WMNamespacePermission -Confirm:$false | Out-Null
                                        if (!(Get-WMNamespacePermission -Namespace $namespace -PrincipalName $principal)) {
                                            Write-Output "Removing access for principal ($principal) from Namespace ($namespace): SUCCESSFUL"
                                        } else {
                                            Write-Error "Removing access for principal ($principal) from Namespace ($namespace): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Removing access for principal ($principal) from Namespace ($namespace), does not exist: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to find Namespace ($namespace) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($sddcDomain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NamespacePermission

Function Enable-Registry {
    <#
        .SYNOPSIS
        Enable the embedded Harbor Registry on a Supervisor Cluster.

        .DESCRIPTION
        The Enable-Registry cmdlet enables the embedded Harbor Registry on a Supervisor Cluster. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Enables the embedded Harbour Registry on the Supervisor Cluster

        .EXAMPLE
        Enable-Registry -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -storagePolicy vsphere-with-tanzu-storage-policy
        This example enables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01 with vSPhere Storage Policy vsphere-with-tanzu-policy.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER storagePolicy
        The vSphere Storage Policy name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$storagePolicy
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Test-vSphereApiConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-vSphereApiAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.Name -eq $domain }).clusters.id) }).Name
                                        if (!(Get-WMRegistry -cluster $cluster -ErrorAction SilentlyContinue)) {
                                            if (Get-SpbmStoragePolicy -Name $storagePolicy -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue) {
                                                Enable-WMRegistry -cluster $cluster -StoragePolicy $storagePolicy | Out-Null
                                                Do {
                                                    $configStatus = Get-WMRegistry -cluster $cluster | Get-WMRegistryHealth
                                                } Until ($configStatus -eq "RUNNING")
                                                if (Get-WMRegistry -cluster $cluster -ErrorAction SilentlyContinue) {
                                                    Write-Output "Enabling Embedded Harbour Registry in vCenter Server ($($vcfVcenterDetails.fqdn)) for Cluster ($cluster): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Enabling Embedded Harbour Registry in vCenter Server ($($vcfVcenterDetails.fqdn)) for Cluster ($cluster): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Error "Unable to find vSphere Storage Policy ($storagePolicy) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Enabling Embedded Harbour Registry in vCenter Server ($($vcfVcenterDetails.fqdn)) for Cluster ($cluster), already performed: SKIPPED"
                                        }
                                    }
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Enable-Registry

Function Undo-Registry {
    <#
        .SYNOPSIS
        Disable the embedded Harbor Registry on a Supervisor Cluster.

        .DESCRIPTION
        The Undo-Registry cmdlet disables the embedded Harbor Registry on a Supervisor Cluster. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Disables the Harbour Registry on the Supervisor Cluster

        .EXAMPLE
        Undo-Registry -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01
        This example disables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01 with vSPhere Storage Policy vsphere-with-tanzu-policy.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Test-vSphereApiConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-vSphereApiAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.Name -eq $domain }).clusters.id) }).Name
                                        if (Get-WMRegistry -cluster $cluster -ErrorAction Ignore) {
                                            Remove-WMRegistry -cluster $cluster | Out-Null
                                            Do {
                                                $configStatus = Get-WMRegistry -cluster $cluster -ErrorAction Ignore #| Get-WMRegistryHealth -ErrorAction Ignore
                                            } Until (!($configStatus))
                                            if (!(Get-WMRegistry -cluster $cluster -ErrorAction Ignore)) {
                                                Write-Output "Disabling Embedded Harbour Registry in vCenter Server ($($vcfVcenterDetails.fqdn)) for Cluster ($cluster): SUCCESSFUL"
                                            } else {
                                                Write-Error "Disabling Embedded Harbour Registry in vCenter Server ($($vcfVcenterDetails.fqdn)) for Cluster ($cluster): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Disabling Embedded Harbour Registry in vCenter Server ($($vcfVcenterDetails.fqdn)) for Cluster ($cluster), already performed: SKIPPED"
                                        }
                                    }
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-Registry

Function Add-NamespaceVmClass {
    <#
        .SYNOPSIS
        Add a Virtual Machine class to a Namespace.

        .DESCRIPTION
        The Add-NamespaceVmClass cmdlet adds a Virtual Machine Class to a Namespace. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Adds a VM Class to the Namespace

        .EXAMPLE
        Add-NamespaceVmClass -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -namespace sfo-w01-tkc01 -vmClass guaranteed-small
        This example adds the VM Class guaranteed-small to Supervisor Namespace sfo-tkc-01 in Workload domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER namespace
        The Supervisor Namespace name.

        .PARAMETER vmClass
        The Virtual Machine Class to add to the Namespace.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $false)] [ValidateSet("guaranteed-medium","guaranteed-large","guaranteed-xlarge","best-effort-4xlarge","guaranteed-small","best-effort-medium","best-effort-2xlarge","guaranteed-2xlarge","best-effort-large","guaranteed-4xlarge","best-effort-8xlarge","best-effort-xsmall","guaranteed-xsmall","best-effort-xlarge","guaranteed-8xlarge","best-effort-small")] [String]$vmClass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Test-vSphereApiConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-vSphereApiAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        if (Get-WMNamespace -Name $namespace -ErrorAction Ignore) {
                                            if (!(Get-VMClass -namespace $namespace | Where-Object {$_ -eq $vmClass})) {
                                                Add-VMClass -namespace $namespace -vmClass $vmClass | Out-Null
                                                if (Get-VMClass -namespace $namespace | Where-Object {$_ -eq $vmClass}) {
                                                    Write-Output "Adding Virtual Machine Class ($vmClass) to Namespace ($namespace): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Adding Virtual Machine Class ($vmClass) to Namespace ($namespace): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Warning "Adding Virtual Machine Class ($vmClass) to Namespace ($namespace), already exists: SKIPPED"
                                            }                      
                                        } else {
                                            Write-Error "Unable to find Namespace ($namespace) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Response
    }
}
Export-ModuleMember -Function Add-NamespaceVmClass

Function Add-TanzuKubernetesCluster {
    <#
        .SYNOPSIS
        Create a new Tanzu Kubernetes Cluster on a Supervisor Cluster.

        .DESCRIPTION
        The Add-TanzuKubernetesCluster cmdlet creates a new Tanzu Kubernetes Cluster on a Supervisor Cluster. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Creates a Tanzu Kubernetes Cluster

        .EXAMPLE
        Add-TanzuKubernetesCluster -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -cluster sfo-w01-cl01 -yaml .\SampleYaml\sfo-w01-tkc01-cluster.yaml
        This example creates a Tanzu Kubernetes cluster based on the YAML file .\SampleYaml\sfo-w01-tkc01-cluster.yaml as the vSphere SSO user administrator@vsphere.local on Supervisor Cluster sfo-w01-cl01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER cluster
        The Supervisor Cluster name.

        .PARAMETER yaml
        The YAML file to use to create the Tanzu Kubernetes Cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$yaml
    )

    if (!$PsBoundParameters.ContainsKey("yaml")) {
        $yaml = Get-ExternalFileName -title "Select the YAML File (.yaml)" -fileType "yaml" -location "default"
    } else {
        if (!(Test-Path -Path $yaml)) {
            Write-Error  "YAML File '$yaml' File Not Found"
            Break
        }
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                Connect-WMCluster -cluster $cluster -user $user -pass $pass | Out-Null
                                New-TanzuKubernetesCluster -YAML $yaml | Out-Null
                                Write-Output "Creating Tanzu Kubernetes Cluster in Supervisor Cluster ($cluster) using YAML ($yaml): SUCCESSFUL"
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                            Disconnect-WMCluster | Out-Null
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-TanzuKubernetesCluster

Function Undo-TanzuKubernetesCluster {
    <#
        .SYNOPSIS
        Remove a Tanzu Kubernetes Cluster.

        .DESCRIPTION
        The Undo-TanzuKubernetesCluster cmdlet removes a new Tanzu Kubernetes Cluster. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes a Tanzu Kubernetes Cluster

        .EXAMPLE
        Undo-TanzuKubernetesCluster -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -cluster sfo-w01-cl01 -namespace sfo-w01-tkc01 -tkc sfo-w01-tkc01
        This example removes a Tanzu Kubernetes Cluster from the a Supervisor Cluster .

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER cluster
        The Supervisor Cluster name.

        .PARAMETER namespace
        The Supervisor Namespace name.

        .PARAMETER tkc
        The Tanzu Kubernetes Cluster name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tkc
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-WMCluster -cluster $cluster -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore) {
                                    Connect-WMCluster -cluster $cluster -user $user -pass $pass | Out-Null
                                    if (Get-TanzuKubernetesCluster -name $namespace -tkc $tkc -ErrorAction Ignore | Out-Null ) {
                                        Remove-TanzuKubernetesCluster -cluster $tkc -namespace $namespace | Out-Null
                                        if (!(Get-TanzuKubernetesCluster -name $namespace -tkc $tkc -ErrorAction Ignore | Out-Null )) {
                                            Write-Output "Removing Tanzu Kubernetes Cluster from Supervisor Cluster ($cluster) Namespace ($namespace) called ($tkc): SUCCESSFUL"
                                        } else {
                                            Write-Error "Removing Tanzu Kubernetes Cluster from Supervisor Cluster ($cluster) Namespace ($namespace) called ($tkc): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Removing Tanzu Kubernetes Cluster from Supervisor Cluster ($cluster) Namespace ($namespace) called ($tkc), does not exist: SKIPPED"
                                    }
                                } else {
                                    Write-Warning "Workload Management is not enabled on Cluster ($server) in vCenter Server ($($vcfVcenterDetails.fqdn))"
                                }
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                            Disconnect-WMCluster | Out-Null
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-TanzuKubernetesCluster

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region I N T E L L I G E N T L O G G I N G & A N A L Y T I C S F U N C T I O N S ###########

Function Export-IlaJsonSpec {
    <#
        .SYNOPSIS
        Create JSON specification for Intelligent Logging and Analytics.

        .DESCRIPTION
        The Export-IlaJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation workbook
        to deploy the Intelligent Logging and Analytics for VMware Cloud Foundation validated solution:
        - Validates that the Planning and Preparation is available
        - Generates the JSON specification file using the Planning and Preparation workbook

        .EXAMPLE
        Export-IlaJsonSpec -workbook .\pnp-workbook.xlsx -jsonFile .\ilaDeploySpec.json
        This example creates a JSON specification Intelligent Logging and Analytics using the Planning and Preparation Workbook.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER jsonFile
        The path to the JSON specification file to be created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        }
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Generation of Intelligent Logging and Analytics JSON (.json) Specification File"
        if (Test-Path -Path $workbook) {
            $pnpWorkbook = Open-ExcelPackage -Path $Workbook
            $jsonObject = @()
            $jsonObject += [pscustomobject]@{
                'sddcManagerFqdn'               = $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value
                'sddcManagerUser'               = $pnpWorkbook.Workbook.Names["sso_default_admin"].Value
                'sddcManagerPass'               = $pnpWorkbook.Workbook.Names["administrator_vsphere_local_password"].Value
                'mgmtSddcDomainName'            = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value
                'contentLibraryName'            = $pnpWorkbook.Workbook.Names["vrslcm_xreg_content_library"].Value
                'licenseAlias'                  = $pnpWorkbook.Workbook.Names["vrli_license_alias"].Value
                'licenseKey'                    = if ($pnpWorkbook.Workbook.Names["vrs_license"].Value) { $pnpWorkbook.Workbook.Names["vrs_license"].Value } else { $pnpWorkbook.Workbook.Names["vrli_license"].Value }
                'certificateAlias'              = $pnpWorkbook.Workbook.Names["region_vrli_virtual_hostname"].Value
                'adminPasswordAlias'            = $pnpWorkbook.Workbook.Names["region_vrli_admin_password_alias"].Value
                'adminPassword'                 = $pnpWorkbook.Workbook.Names["region_vrli_admin_password"].Value
                'adminUsername'                 = $pnpWorkbook.Workbook.Names["region_vrli_admin_user"].Value
                'environemntName'               = $pnpWorkbook.Workbook.Names["vrslcm_reg_env"].Value
                'datacenter'                    = $pnpWorkbook.Workbook.Names["vrslcm_reg_dc"].Value
                'vcenterFqdn'                   = $pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value
                'vcenterDatacenter'             = $pnpWorkbook.Workbook.Names["mgmt_datacenter"].Value
                'vcenterCluster'                = $pnpWorkbook.Workbook.Names["mgmt_cluster"].Value
                'vcenterDatastore'              = $pnpWorkbook.Workbook.Names["mgmt_vsan_datastore"].Value
                'network'                       = $pnpWorkbook.Workbook.Names["reg_seg01_name"].Value
                'gateway'                        = $pnpWorkbook.Workbook.Names["reg_seg01_gateway_ip"].Value
                'netmask'                        = $pnpWorkbook.Workbook.Names["reg_seg01_mask_overlay_backed"].Value
                'domain'                        = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'searchpath'                    = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'dns'                           = ($pnpWorkbook.Workbook.Names["region_dns1_ip"].Value + "," + $pnpWorkbook.Workbook.Names["region_dns2_ip"].Value)
                'ntp'                            = $pnpWorkbook.Workbook.Names["region_ntp1_server"].Value
                'nodeSize'                      = $pnpWorkbook.Workbook.Names["region_vrli_appliance_size"].Value.ToLower()
                'adminEmail'                    = $pnpWorkbook.Workbook.Names["region_vrli_admin_email"].Value
                'clusterFqdn'                    = $pnpWorkbook.Workbook.Names["region_vrli_virtual_fqdn"].Value
                'clusterIp'                     = $pnpWorkbook.Workbook.Names["region_vrli_virtual_ip"].Value
                'vmNameNodeA'                   = $pnpWorkbook.Workbook.Names["region_vrli_nodea_hostname"].Value
                'hostNameNodeA'                 = $pnpWorkbook.Workbook.Names["region_vrli_nodea_fqdn"].Value
                'ipNodeA'                       = $pnpWorkbook.Workbook.Names["region_vrli_nodea_ip"].Value
                'vmNameNodeB'                   = $pnpWorkbook.Workbook.Names["region_vrli_nodeb_hostname"].Value
                'hostNameNodeB'                 = $pnpWorkbook.Workbook.Names["region_vrli_nodeb_fqdn"].Value
                'ipNodeB'                       = $pnpWorkbook.Workbook.Names["region_vrli_nodeb_ip"].Value
                'vmNameNodeC'                   = $pnpWorkbook.Workbook.Names["region_vrli_nodec_hostname"].Value
                'hostNameNodeC'                 = $pnpWorkbook.Workbook.Names["region_vrli_nodec_fqdn"].Value
                'ipNodeC'                       = $pnpWorkbook.Workbook.Names["region_vrli_nodec_ip"].Value
                'vmFolder'                      = $pnpWorkbook.Workbook.Names["region_vrli_vm_folder"].Value
                'vmList'                        = $pnpWorkbook.Workbook.Names["region_vrli_nodea_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["region_vrli_nodeb_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["region_vrli_nodec_hostname"].Value
                'drsVmGroupNameAz'              = $pnpWorkbook.Workbook.Names["mgmt_az1_vm_group_name"].Value 
                'smtpServer'                    = $pnpWorkbook.Workbook.Names["smtp_server"].Value
                'port'                          = $pnpWorkbook.Workbook.Names["smtp_server_port"].Value -as [Int]
                'sender'                        = $pnpWorkbook.Workbook.Names["xreg_vra_smtp_sender_email_address"].Value
                'smtpUser'                      = $pnpWorkbook.Workbook.Names["smtp_sender_username"].Value
                'smtpPass'                      = $pnpWorkbook.Workbook.Names["smtp_sender_password"].Value
                'emailAddress'                  = $pnpWorkbook.Workbook.Names["region_vrli_admin_email"].Value
                'retentionNotificationDays'     = $pnpWorkbook.Workbook.Names["region_vrli_log_retention_notification"].Value.Split(" ")[0]
                'retentionInterval'             = $pnpWorkbook.Workbook.Names["region_vrli_log_retention_notification"].Value.Split(" ")[1]
                'retentionPeriodDays'           = $pnpWorkbook.Workbook.Names["region_vrli_log_retention_period"].Value -as [Int]
                'archiveLocation'               = $pnpWorkbook.Workbook.Names["region_vrli_archive_location"].Value
                'domainFqdn'                    = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'domainBindUser'                = $pnpWorkbook.Workbook.Names["svc_ila_ad_user"].Value
                'domainBindPass'                = $pnpWorkbook.Workbook.Names["svc_ila_ad_password"].Value
                'domainServers'                 = ($pnpWorkbook.Workbook.Names["domain_controller_hostname"].Value + "." + $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value)
                'logsAdminGroup'                = $pnpWorkbook.Workbook.Names["group_gg_vrli_admins"].Value
                'logsUserGroup'                 = $pnpWorkbook.Workbook.Names["group_gg_vrli_users"].Value
                'logsViewerGroup'               = $pnpWorkbook.Workbook.Names["group_gg_vrli_viewers"].Value
                'logsAdGroups'                  = "$($pnpWorkbook.Workbook.Names["group_gg_vrli_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrli_users"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrli_viewers"].Value)"
                'parentDomain'                  = $pnpWorkbook.Workbook.Names["parent_dns_zone"].Value
                'childDomain'                   = $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
                'vmNameNode1'                   = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_hostname"].Value
                'vmNameNode2'                   = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_hostname"].Value
                'vmNameNode3'                   = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_hostname"].Value
                'stretchedCluster'              = $pnpWorkbook.Workbook.Names["mgmt_stretched_cluster_chosen"].Value
                'agentGroupNameWsa'             = $pnpWorkbook.Workbook.Names["region_vrli_agent_group_wsa"].Value
                'agentGroupNamePhoton'          = $pnpWorkbook.Workbook.Names["region_vrli_agent_group_photon"].Value
                'gitHubToken'                   = $pnpWorkbook.Workbook.Names["ila_github_token"].Value
            }
            Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
            $jsonObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonFile
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            Foreach ($jsonValue in $jsonInput.psobject.properties) {
                if ($jsonValue.value -eq "Value Missing" -or $null -eq $jsonValue.value ) {
                    $issueWithJson = $true
                }
            }
            if ($issueWithJson) {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Creation of JSON Specification file for Intelligent Logging and Analytics, missing data: POST_VALIDATION_FAILED"
            } else { 
                Show-PowerValidatedSolutionsOutput -message "Creation of JSON Specification file for Intelligent Logging and Analytics: SUCCESSFUL"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-IlaJsonSpec

Function Invoke-IlaDeployment {
    <#
        .SYNOPSIS
        End-to-end Deployment of Intelligent Logging and Analytics.

        .DESCRIPTION
        The Invoke-IlaDeployment cmdlet is a single function to implement the configuration of the Intelligent Logging
        and Analytics for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-IlaDeployment -jsonFile .\ilaDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\"
        This example configures Intelligent Logging and Analytics for VMware Cloud Foundation using the JSON spec supplied

        .EXAMPLE
        Invoke-IlaDeployment -jsonFile .\ilaDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\" -useContentLibrary -contentLibrary Operations
        This example configures Intelligent Logging and Analytics for VMware Cloud Foundation using the JSON spec supplied deploying the OVA using a vSphere Content Library

        .PARAMETER jsonFile
        The JSON (.json) file created.

        .PARAMETER certificates
        The folder containing the certificates.

        .PARAMETER binaries
        The folder containing the binaries.

        .PARAMETER useContentLibrary
        Use a vSphere Content Library to deploy the OVA.

        .PARAMETER contentLibrary
        The name of the vSphere Content Library to use.
    #>
  

    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificates,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$binaries,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    $solutionName       = "Intelligent Logging and Analytics for VMware Cloud Foundation"
    $logsProductName    = "VMware Aria Operations for Logs"
    $lcmProductName     = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Deployment of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            $operationsForLogsPem = $certificates + $jsonInput.certificateAlias + ".2.chain.pem"
            if (Test-Path -Path $operationsForLogsPem) {
                if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn ) {
                    if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                        if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $allWorkloadDomains     = Get-VCFWorkloadDomain
                                $failureDetected = $false

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Creating a vSphere Content Library for Operational Management"
                                    $StatusMsg = Add-ContentLibrary -Server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ContentLibraryName $jsonInput.contentLibraryName -published -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                        $opsforlogsOvaPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match "Log-Insight"}).name
                                        if ((([regex]::Match(((Split-Path $opsforlogsOvaPath -leaf)), "(?<=-)\d+\.\d+\.\d+").Value) -notin (Get-vRSLCMProductVersion -productId vrli))) {
                                            Show-PowerValidatedSolutionsOutput -type ERROR -message "$logsProductName OVA ($binaryFile) does not match a supported version: PRE_VALIDATION_FAILED"; $failureDetected = $true
                                        } elseif (($opsforlogsOvaPath -match "Log-Insight")) {
                                            Show-PowerValidatedSolutionsOutput -message "Importing $logsProductName OVA into vSphere Content Library"
                                            $StatusMsg = Import-ContentLibraryItem -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibrary $jsonInput.contentLibraryName -file $opsforlogsOvaPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        } else {
                                            Show-PowerValidatedSolutionsOutput -type ERROR -message "$logsProductName OVA ($automationOvaPath) File Not Found: PRE_VALIDATION_FAILED"
                                        }
                                    }
                                    $allDatacenters = Get-vRSLCMDatacenter
                                    foreach ($datacenter in $allDatacenters) {
                                        Sync-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid -vcenterName (Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid).vcenterName | Out-Null
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Adding $logsProductName License to $lcmProductName"
                                    $StatusMsg = New-vRSLCMLockerLicense -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.licenseAlias -license $jsonInput.licenseKey -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Importing the $logsProductName Certificate to $lcmProductName"
                                    $StatusMsg = Import-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -certChainPath $operationsForLogsPem -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Adding the $logsProductName Admin Password to $lcmProductName"
                                    $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.adminPasswordAlias -password $jsonInput.adminPassword -userName $jsonInput.adminUsername -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Deploying $logsProductName By Using $lcmProductName"
                                    if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                        $StatusMsg = New-vRLIDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -useContentLibrary -contentLibrary $contentLibrary -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    } else {
                                        $StatusMsg = New-vRLIDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    }
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -Type INFO -Message "$StatusMsg" } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -Type WARNING -Message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                    if ( $StatusMsg -match "FAILED" -or $WarnMsg -match "FAILED" ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message "Deployment of $logsProductName FAILED"; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Creating Virtual Machine and Template Folder for $logsProductName"
                                    $StatusMsg = Add-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -folderName $jsonInput.vmFolder -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Moving the $logsProductName Virtual Machines to the Dedicated Folder"
                                    $StatusMsg = Move-VMtoFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -vmList $jsonInput.vmList -folder $jsonInput.vmFolder -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg -match "SUCCESSFUL" ) { Show-PowerValidatedSolutionsOutput -Type INFO -Message "Relocating $logsProductName Virtual Machines to Dedicated Folder: SUCCESSFUL" } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -Type WARNING -Message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Activating Authentication for VMware Aria Operations for Logs by Using Active Directory over LDAP"
                                    $StatusMsg = Add-vRLIAuthenticationAD -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUser -domainBindPass $jsonInput.domainBindPass -domainServers $jsonInput.domainServers -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    if ($stretchedCluster -eq "Include") {
                                        Show-PowerValidatedSolutionsOutput -message "Adding the $logsProductName Virtual Machines to the First Availability Zone VM Group"
                                        $StatusMsg = Add-VmGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -name $jsonInput.drsVmGroupNameAz -vmList $jsonInput.vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Configuring SMTP for $logsProductName"
                                    $StatusMsg = Add-vRLISmtpConfiguration -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -smtpServer $jsonInput.smtpServer -port $jsonInput.port -sender $jsonInput.sender -smtpUser $jsonInput.smtpUser -smtpPass $jsonInput.smtpPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    if (!($archiveLocation -match "Value Missing")) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring Log Retention and Archiving for $logsProductName"
                                        $StatusMsg = Add-vRLILogArchive -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -emailAddress $jsonInput.emailAddress -retentionNotificationDays $jsonInput.retentionNotificationDays -retentionInterval $jsonInput.retentionInterval -retentionPeriodDays $jsonInput.retentionPeriodDays -archiveLocation $jsonInput.archiveLocation -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Connecting VI Workload Domains to $logsProductName"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        if ($sddcDomain.type -eq "VI") {
                                            $StatusMsg = Register-vRLIWorkloadDomain -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -status ENABLED -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Assigning $logsProductName Roles to Active Directory Groups"
                                    $StatusMsg = Add-vRLIAuthenticationGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -group $jsonInput.logsAdminGroup -role 'Super Admin' -authProvider ad -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Add-vRLIAuthenticationGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -group $jsonInput.logsUserGroup -role 'User' -authProvider ad  -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Add-vRLIAuthenticationGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -group $jsonInput.logsViewerGroup -role 'View Only Admin' -authProvider ad  -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -type NOTE -message "Install Workspace ONE Access Content Pack"
                                    $StatusMsg = Enable-vRLIContentPack -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -token $jsonInput.gitHubToken -contentPack WSA -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Configuring the NSX Edge Nodes to Forward Log Events to $logsProductName"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        $StatusMsg = Add-NsxtNodeProfileSyslogExporter -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }

                                if (Get-VCFWSA) {
                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Installing and Configuring the $logsProductName Agent on the Clustered Workspace ONE Access Nodes"
                                        $wsaNodes = (Get-vRSLCMProductNode -environmentName globalenvironment -product vidm)
                                        foreach ($node in $wsaNodes) {
                                            Show-PowerValidatedSolutionsOutput -message "Installing and Configuring the $logsProductName Agent on Workspace ONE Access Node ($($node.vmName))"
                                            $wsaRootPass = (Get-VCFCredential | Where-Object {$_.resource.resourceName -eq $node.hostname -and $_.username -eq "root"}).password
                                            $StatusMsg = Install-vRLIPhotonAgent -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vmName $node.vmName -vmRootPass $wsaRootPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }

                                    if (((Invoke-Expression Get-VCFWSA).nodes).Count -gt 1) {
                                        $agentGroupVmListWsa      = "$($jsonInput.vmNameNode1).$($jsonInput.parentDomain)","$($jsonInput.vmNameNode2).$($jsonInput.parentDomain)","$($jsonInput.vmNameNode3).$($jsonInput.parentDomain)"
                                        $agentGroupVmListPhoton   = "$($jsonInput.sddcManagerFqdn)","$((Get-VCFVrslcm).fqdn)","$($jsonInput.vmNameNode1).$($jsonInput.parentDomain)","$($jsonInput.vmNameNode2).$($jsonInput.parentDomain)","$($jsonInput.vmNameNode3).$($jsonInput.parentDomain)"
                                    } else {
                                        $agentGroupVmListWsa      = "$($jsonInput.vmNameNode1).$($jsonInput.parentDomain)"
                                        $agentGroupVmListPhoton   = "$($jsonInput.sddcManagerFqdn)","$((Get-VCFVrslcm).fqdn)","$($jsonInput.vmNameNode1).$($jsonInput.parentDomain)"
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring the $logsProductName Agent Group for the Clustered Workspace ONE Access"
                                        $StatusMsg = Add-vRLIAgentGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -agentGroupName $jsonInput.agentGroupNameWsa -agentGroupType wsa -criteria $agentGroupVmListWsa -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Creating a $logsProductName Photon OS Agent Group for the Management Nodes"
                                        $StatusMsg = Add-vRLIAgentGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass $jsonInput.agentGroupNamePhoton -agentGroupType photon -criteria $agentGroupVmListPhoton -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                } else {
                                    Show-PowerValidatedSolutionsOutput -type ERROR -message "Implementation of Workspace ONE Access in $lcmProductName Not Found: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }
            } else {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Certificate File (.pem) for $logsProductName ($operationsForLogsPem): File Not Found"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $solutionName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-IlaDeployment

Function Invoke-UndoIlaDeployment {
    <#
        .SYNOPSIS
        End-to-end removal of Intelligent Logging and Analytics.

        .DESCRIPTION
        The Invoke-UndoIlaDeployment cmdlet is a single function to remove the configuration of the Intelligent Logging
        and Analytics for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-UndoIlaDeployment -jsonFile .\ilaDeploySpec.json
        This example removes the configuration of Intelligent Logging and Analytics for VMware Cloud Foundation using the
        JSON specification provided.

        .PARAMETER jsonFile
        The JSON (.json) file created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    $solutionName       = "Intelligent Logging and Analytics for VMware Cloud Foundation"
    $logsProductName    = "VMware Aria Operations for Logs"
    $lcmProductName     = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Removal of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn ) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domainType "MANAGEMENT")) {
                        if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $allWorkloadDomains = Get-VCFWorkloadDomain
                                $failureDetected = $false

                                if (Get-VCFVrli) {
                                    if (Get-VCFWSA) {
                                        Show-PowerValidatedSolutionsOutput -message "Removing the $logsProductName Agent on the Clustered Workspace ONE Access Nodes"
                                        $wsaNodes = (Get-vRSLCMProductNode -environmentName globalenvironment -product vidm)
                                        foreach ($node in $wsaNodes) {
                                            Show-PowerValidatedSolutionsOutput -message "Removing the $logsProductName Agent from Workspace ONE Access Node ($($node.vmName))"
                                            $wsaRootPass = (Get-VCFCredential | Where-Object {$_.resource.resourceName -eq $node.hostname -and $_.username -eq "root"}).password
                                            $StatusMsg = Undo-vRLIPhotonAgent -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vmName $node.vmName -vmRootPass $wsaRootPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    } else {
                                        Show-PowerValidatedSolutionsOutput -type ERROR -message "Implementation of Workspace ONE Access in $lcmProductName Not Found: PRE_VALIDATION_FAILED"
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing the $logsProductName Configuration from the NSX Edge Nodes"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        $StatusMsg = Undo-NsxtNodeProfileSyslogExporter -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }

                                if (!$failureDetected) {
                                    if (Get-VCFVrli) {
                                        Show-PowerValidatedSolutionsOutput -message "Disconnecting VI Workload Domains from $logsProductName"
                                        foreach ($sddcDomain in $allWorkloadDomains) {
                                            if ($sddcDomain.type -eq "VI") {
                                                $StatusMsg = Register-vRLIWorkloadDomain -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -status DISABLED -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                            foreach ($vm in ($jsonInput.vmList -Split ',')) {
                                                if (Get-VM -name $vm -ErrorAction SilentlyContinue ) {
                                                    Get-VM -name $vm | Stop-VM -RunAsync -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                    Do {$powerState = (Get-VM -name $vm | Select-Object PowerState).PowerState } Until ($powerState -eq "PoweredOff")
                                                    Get-VM -name $vm | Remove-VM -DeletePermanently -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                }
                                            }
                                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                            Show-PowerValidatedSolutionsOutput -message "Deleting $logsProductName from $lcmProductName"
                                            $StatusMsg = Undo-vRLIDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -environmentName $jsonInput.environemntName -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Deleting the Virtual Machine and Template Folder for $logsProductName"
                                    $StatusMsg = Undo-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -foldername $jsonInput.vmFolder -folderType VM -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Deleting the $logsProductName Admin Password from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.adminPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Deleting the $logsProductName Certificate from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Deleting $logsProductName License from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerLicense -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.licenseAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $solutionName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-UndoIlaDeployment

Function Export-vRLIJsonSpec {
    <#
        .SYNOPSIS
        Create VMware Aria Operations for Logs Deployment JSON specification.

        .DESCRIPTION
        The Export-vRLIJsonSpec cmdlet creates the JSON specification file using the Intelligent Logging and Analytics
        JSON specification file generated from the Planning and Preparation workbook to deploy VMware Aria Operations
        for Logs using VMware Aria Suite Lifecycle. The cmdlet connects to SDDC Manager using the -server, -user, and
        -password values.
        - Validates that the JSON specification file for Intelligent Logging and Analytics
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Suite Lifecycle has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the License, Certificate and Password have been created in VMware Aria Suite Lifecycle locker
        - Generates the deployment JSON specification file using the JSON specification file for Intelligent Logging
        and Analytics for use with VMware Aria Suite Lifecycle named '<management_domain_name>-logsDeploySpec.json.json'

        .EXAMPLE
        Export-vRLIJsonSpec -jsonFile .\ilaDeploySpec.json
        This example creates a JSON specification file for deploying VMware Aria Operations for Logs using data from the JSON specification file for Intelligent Logging and Analytics

        .EXAMPLE
        Export-vRLIJsonSpec -jsonFile .\ilaDeploySpec.json -outputPath .\myJsons\
        This example creates a JSON specification file in the folder provided for deploying VMware Aria Operations for Logs using data from the JSON specification file for Intelligent Logging and Analytics

        .EXAMPLE
        Export-vRLIJsonSpec -jsonFile .\ilaDeploySpec.json -customVersion 8.8.4
        This example creates a JSON specification file for deploying VMware Aria Operations for Logs using a custom version and data from the JSON specification file for Intelligent Logging and Analytics

        .EXAMPLE
        Export-vRLIJsonSpec -jsonFile .\ilaDeploySpec.json -useContentLibrary -contentLibrary Operations
        This example creates a JSON specification file for deploying VMware Aria Operations for Logs deploying the OVA from a vSphere Conent Library and data from the JSON specification file for Intelligent Logging and Analytics

        .PARAMETER jsonFile
        The JSON file for Intelligent Logging and Analytics.

        .PARAMETER outputPath
        The folder location where the VMware Aria Operations for Logs JSON file is created.

        .PARAMETER customVersion
        The custom version of VMware Aria Operations for Logs to deploy.

        .PARAMETER useContentLibrary
        Use a vSphere Content Library to deploy the VMware Aria Operations for Logs OVA.

        .PARAMETER contentLibrary
        The vSphere Content Library name to use to deploy the VMware Aria Operations for Logs OVA.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$outputPath,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                        $vcfVersion = ((Get-VCFManager).version -Split ('\.\d{1}\-\d{8}')) -split '\s+' -match '\S'
                        if ($PsBoundParameters.ContainsKey("outputPath")) {
                            $jsonSpecFileName = $outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "logsDeploySpec.json")
                        } else {
                            $jsonSpecFileName = (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "logsDeploySpec.json")
                        }
                        if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                if ($vrliLicense = Get-vRSLCMLockerLicense | Where-Object {$_.key -eq $jsonInput.licenseKey}) {
                                    if ($vrliCertificate = Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $jsonInput.certificateAlias}) {
                                        if ($vrliPassword = Get-vRSLCMLockerPassword -alias $jsonInput.adminPasswordAlias) {
                                            if ($vcfVersion -ge "4.5.0") {
                                                $vcCredentials = Get-vRSLCMLockerPassword | Where-Object {$_.userName -match (($jsonInput.vcenterFqdn).Split(".")[0] + "@vsphere.local")}
                                            } else {
                                                $vcCredentials = Get-vRSLCMLockerPassword -alias (($jsonInput.vcenterFqdn).Split(".")[0] + "-" + $jsonInput.vcenterDatacenter)
                                            }
                                            $datacenterName = Get-vRSLCMDatacenter | Where-Object {$_.dataCenterName -eq $jsonInput.datacenter}
                                            
                                            #### Generate the VMware Aria Operations for Logs Properties Section
                                            if (!$PsBoundParameters.ContainsKey("customVersion")) { 
                                                if ($vcfVersion -eq "4.3.0") { $vrliVersion = "8.4.0" }
                                                if ($vcfVersion -eq "4.3.1") { $vrliVersion = "8.4.1" }
                                                if ($vcfVersion -eq "4.4.0") { $vrliVersion = "8.6.2" }
                                                if ($vcfVersion -eq "4.4.1") { $vrliVersion = "8.6.2" }
                                                if ($vcfVersion -eq "4.5.0") { $vrliVersion = "8.8.2" }
                                                if ($vcfVersion -eq "4.5.1") { $vrliVersion = "8.14.0" }
                                                if ($vcfVersion -eq "4.5.2") { $vrliVersion = "8.14.0" }
                                                if ($vcfVersion -eq "5.0.0") { $vrliVersion = "8.14.0" }
                                                if ($vcfVersion -eq "5.1.0") { $vrliVersion = "8.14.0" }
                                            } else {
                                                $vrliVersion = $customVersion
                                            }
                                            
                                            $infrastructurePropertiesObject = @()
                                            $infrastructurePropertiesObject += [pscustomobject]@{
                                                'dataCenterVmid'        = $datacenterName.dataCenterVmid
                                                'regionName'            = "default"
                                                'zoneName'              = "default"
                                                'vCenterName'           = ($jsonInput.vcenterFqdn).Split(".")[0]
                                                'vCenterHost'           = $jsonInput.vcenterFqdn
                                                'vcUsername'            = $vcCredentials.userName
                                                'vcPassword'            = ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                'acceptEULA'            = "true"
                                                'enableTelemetry'       = "true"
                                                'defaultPassword'       = ("locker:password:" + $($vrliPassword.vmid) + ":" + $($vrliPassword.alias))
                                                'certificate'           = ("locker:certificate:" + $($vrliCertificate.vmid) + ":" + $($vrliCertificate.alias))
                                                'cluster'               = ($jsonInput.vcenterDatacenter + "#" + $jsonInput.vcenterCluster)
                                                'storage'               = $jsonInput.vcenterDatastore
                                                'diskMode'              = "thin"
                                                'network'               = $jsonInput.network
                                                'masterVidmEnabled'     = "false"
                                                'dns'                   = $jsonInput.dns
                                                'domain'                = $jsonInput.domain
                                                'gateway'               = $jsonInput.gateway
                                                'netmask'               = $jsonInput.netmask
                                                'searchpath'            = $jsonInput.searchPath
                                                'timeSyncMode'          = "ntp"
                                                'ntp'                   = $jsonInput.ntp
                                                'isDhcp'                = "false"
                                                'vcfProperties'         = '{"vcfEnabled":true,"sddcManagerDetails":[{"sddcManagerHostName":"' + $jsonInput.sddcManagerFqdn + '","sddcManagerName":"default","sddcManagerVmid":"default"}]}'
                                            }
                                            $infrastructureObject = @()
                                            $infrastructureObject += [pscustomobject]@{
                                                'properties'    = ($infrastructurePropertiesObject | Select-Object -Skip 0)
                                            }

                                            ### Generate the Properties Details
                                            if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                $contentLibraryItems = ((Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenterName.dataCenterVmid -vcenterName ($jsonInput.vcenterFqdn).Split(".")[0]).contentLibraries | Where-Object {$_.contentLibraryName -eq $contentLibrary}).contentLibraryItems
                                                if ($contentLibraryItems) {
                                                    $contentLibraryItemId = ($contentLibraryItems | Where-Object {$_.contentLibraryItemName -match "Log-Insight-$vrliVersion"}).contentLibraryItemId
                                                } else {
                                                    Write-Error "Unable to find vSphere Content Library ($contentLibrary) or Content Library Item in VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"
                                                    Break
                                                }
                                            }
                                            $productPropertiesObject = @()
                                            $productPropertiesObject += [pscustomobject]@{
                                                'certificate'                    = ("locker:certificate:" + $($vrliCertificate.vmid) + ":" + $($vrliCertificate.alias))
                                                'productPassword'                = ("locker:password:" + $($vrliPassword.vmid) + ":" + $($vrliPassword.alias))
                                                'adminEmail'                    = $jsonInput.adminEmail
                                                'fipsMode'                        = "false"
                                                'licenseRef'                    = ("locker:license:" + $($vrliLicense.vmid) + ":" + $($vrliLicense.alias))
                                                'nodeSize'                        = $jsonInput.nodeSize
                                                'configureClusterVIP'            = "false"
                                                'affinityRule'                    = $true
                                                'isUpgradeVmCompatibility'        = $true
                                                'vrliAlwaysUseEnglish'            = $false
                                                'masterVidmEnabled'                = $false
                                                'configureAffinitySeparateAll'    = "true"
                                                'contentLibraryItemId'          = $contentLibraryItemId
                                                'ntp'                           = $jsonInput.ntp
                                                'timeSyncMode'                  = "ntp"
                                            }

                                            #### Generate VMware Aria Operations for Logs Cluster Details
                                            $clusterVipProperties = @()
                                            $clusterVipProperties += [pscustomobject]@{
                                                'hostName'    = $jsonInput.clusterFqdn
                                                'ip'        = $jsonInput.clusterIp
                                            }
                                            $clusterVipsObject = @()
                                            $clusterVipsObject += [pscustomobject]@{
                                                'type'          = "vrli-cluster-1"
                                                'properties'    = ($clusterVipProperties | Select-Object -Skip 0)
                                            }
                                            $clusterObject = @()
                                            $clusterObject += [pscustomobject]@{
                                                'clusterVips'    = $clusterVipsObject
                                            }

                                            #### Generate VMware Aria Operations for Logs Node Details
                                            $masterProperties = @()
                                            $masterProperties += [pscustomobject]@{
                                                'vmName'        = $jsonInput.vmNameNodeA
                                                'hostName'      = $jsonInput.hostNameNodeA
                                                'ip'            = $jsonInput.ipNodeA
                                                'folderName'    = $jsonInput.vmFolder
                                            }
                                            $worker1Properties = @()
                                            $worker1Properties += [pscustomobject]@{
                                                'vmName'        = $jsonInput.vmNameNodeB
                                                'hostName'      = $jsonInput.hostNameNodeB
                                                'ip'            = $jsonInput.ipNodeB
                                                'folderName'    = $jsonInput.vmFolder
                                            }
                                            $worker2Properties = @()
                                            $worker2Properties += [pscustomobject]@{
                                                'vmName'        = $jsonInput.vmNameNodeC
                                                'hostName'      = $jsonInput.hostNameNodeC
                                                'ip'            = $jsonInput.ipNodeC
                                                'folderName'    = $jsonInput.vmFolder
                                            }
                                            $nodesObject = @()
                                            $nodesobject += [pscustomobject]@{
                                                'type'       = "vrli-master"
                                                'properties'    = ($masterProperties | Select-Object -Skip 0)
                                            }
                                            $nodesobject += [pscustomobject]@{
                                                'type'       = "vrli-worker"
                                                'properties'    = ($worker1Properties | Select-Object -Skip 0)
                                            }
                                            $nodesobject += [pscustomobject]@{
                                                'type'       = "vrli-worker"
                                                'properties'    = ($worker2Properties | Select-Object -Skip 0)
                                            }

                                            
                                            $productsObject = @()
                                            $productsObject += [pscustomobject]@{
                                                'id'         = "vrli"
                                                'version'    = $vrliVersion
                                                'properties'    = ($productPropertiesObject  | Select-Object -Skip 0)
                                                'clusterVIP'    = ($clusterObject  | Select-Object -Skip 0)
                                                'nodes'      = $nodesObject    
                                            }
                                            $vrliDeploymentObject = @()
                                            $vrliDeploymentObject += [pscustomobject]@{
                                                'environmentName' = $jsonInput.environemntName
                                                'infrastructure'  = ($infrastructureObject  | Select-Object -Skip 0)
                                                'products'        = $productsObject     
                                            }
                                            $vrliDeploymentObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonSpecFileName
                                            Write-Output "Creation of Deployment JSON Specification file for VMware Aria Operations for Logs: SUCCESSFUL"
                                        } else {
                                            Write-Error "Unable to find Admin Password with alias ($($jsonInput.adminPasswordAlias) in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find Certificate with alias ($($jsonInput.certificateAlias) in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find License key ($($jsonInput.licenseKey)) in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-vRLIJsonSpec

Function New-vRLIDeployment {
    <#
        .SYNOPSIS
        Deploy VMware Aria Operations for Logs Cluster via VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRLIDeployment cmdlet deploys VMware Aria Operations for Logs via VMware Aria Suite Lifecycle. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Suite Lifecycle has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment does not already exist in VMware Aria Suite Lifecycle
        - Requests a new deployment of VMware Aria Operations for Logs via VMware Aria Suite Lifecycle

        .EXAMPLE
        New-vRLIDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\ilaDeploySpec.json
        This example starts a deployment of VMware Aria Operations for Logs via VMware Aria Suite Lifecycle using data from the JSON Specification for Intelligent Logging and Analytics

        .EXAMPLE
        New-vRLIDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\ilaDeploySpec.json -customVersion 8.8.2
        This example starts a deployment of a custom version of VMware Aria Operations for Logs via VMware Aria Suite Lifecycle using data from the JSON Specification for Intelligent Logging and Analytics

        .EXAMPLE
        New-vRLIDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\ilaDeploySpec.json -useContentLibrary -contentLibrary Operations
        This example starts a deployment of VMware Aria Operations for Logs via VMware Aria Suite Lifecycle using a content library for the OVA deployment and using data from the JSON Specification for Intelligent Logging and Analytics

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER jsonFile
        The JSON (.json) file for Intelligent Logging and Analytics.

        .PARAMETER Monitor
        Monitor the deployment of VMware Aria Operations for Logs via VMware Aria Suite Lifecycle.

        .PARAMETER customVersion
        The custom version of VMware Aria Operations for Logs to deploy.

        .PARAMETER useContentLibrary
        Use a vSphere Content Library to deploy the VMware Aria Operations for Logs OVA.

        .PARAMETER contentLibrary
        The vSphere Content Library name to use to deploy the VMware Aria Operations for Logs OVA.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                        if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $commandSwitch = ""
                                if ($PsBoundParameters.ContainsKey("customVersion")) {
                                    $commandSwitch = $commandSwitch + " -customVersion $customVersion"
                                }
                                if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                    $commandSwitch = $commandSwitch + " -useContentLibrary -contentLibrary $contentLibrary"
                                }
                                $outputPath = ($outputPath = Split-Path $jsonFile -Parent) + "\"
                                Invoke-Expression "Export-vRLIJsonSpec -jsonFile $jsonFile -outputPath $outputPath $($commandSwitch) | Out-Null"
                                $json = (Get-Content -Raw ($outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "logsDeploySpec.json")))
                                $jsonSpec = $json | ConvertFrom-Json
                                if (!($environmentExists = (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $($jsonSpec.environmentName)}))) {
                                    if (Get-vRSLCMLockerPassword -alias $($jsonSpec.products.properties.productPassword.Split(":")[3])) {
                                        if (Get-vRSLCMLockerCertificate | Where-Object {$_.alias -Match $($jsonSpec.products.properties.certificate.Split(":")[3])}) {
                                            if (Get-vRSLCMLockerLicense | Where-Object {$_.alias -eq $($jsonSpec.products.properties.licenseRef.Split(":")[3])}) {
                                                $newRequest = Add-vRSLCMEnvironment -json $json
                                                if ($newRequest) {
                                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                                        Start-Sleep 10
                                                        Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                                    } else {
                                                        Write-Output "Deployment Request for VMware Aria Operations for Logs Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                                    }
                                                } else {
                                                    Write-Error "Request to deploy VMware Aria Operations for Logs failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Error "License with alias ($($jsonSpec.products.properties.licenseRef.Split(":")[3])) does not exist in the locker: PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Certificate with alias ($($jsonSpec.products.properties.certificate.Split(":")[3])) does not exist in the locker: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Password with alias ($($jsonSpec.products.properties.productPassword.Split(":")[3])) does not exist in the locker: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Environment with name ($($jsonSpec.environmentName)) already exists in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with a status of ($($environmentExists.environmentStatus)): SKIPPED"
                                }
                            }
                        }
                    } 
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-vRLIDeployment

Function Undo-vRLIDeployment {
    <#
        .SYNOPSIS
        Remove the VMware Aria Operations for Logs Environment from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-vRLIDeployment cmdlet removes VMware Aria Operations for Logs from VMware Aria Suite Lifecycle. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment exist in VMware Aria Suite Lifecycle
        - Requests a the deletion of VMware Aria Operations for Logs from VMware Aria Suite Lifecycle

        .EXAMPLE
        Undo-vRLIDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName sfo-intance-env
        This example starts a removal of VMware Aria Operations for Logs from VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER environmentName
        The VMware Aria Operations for Logs Environment Name.

        .PARAMETER monitor
        Monitor the VMware Aria Suite Lifecycle request.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName}) {
                                $newRequest = Remove-vRSLCMEnvironment -environmentId (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName}).environmentId
                                if ($newRequest) {
                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                        Start-Sleep 10
                                        $status = Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                        if (!(Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName})) {
                                            if ($status -match "COMPLETED") {
                                                Write-Output "Removal of VMware Aria Operations for Logs from Environment ($environmentName) VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removal of VMware Aria Operations for Logs from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Removal of VMware Aria Operations for Logs from Environment ($environmentName) VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Output "Removal request of VMware Aria Operations for Logs Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                    }
                                } else {
                                    Write-Error "Removal request of VMware Aria Operations for Logs failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Environment with name ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already removed: SKIPPED"
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIDeployment

Function Add-vRLISmtpConfiguration {
    <#
        .SYNOPSIS
        Configure SMTP settings in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLISmtpConfiguration cmdlet configures the SMTP sever settings in VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity is possible to the SMTP server
        - Configures SMTP server settings in VMware Aria Operations for Logs if not already configured

        .EXAMPLE
        Add-vRLISmtpConfiguration -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -smtpServer smtp.rainpole.io -port 25 -sender administrator@rainpole.io
        This example configures the SMTP server settings on VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER smtpServer
        The SMTP server FQDN or IP Address.

        .PARAMETER port
        The SMTP server port.

        .PARAMETER sender
        The sender email address.

        .PARAMETER smtpUser
        The SMTP server username.

        .PARAMETER smtpPass
        The SMTP server password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sender,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$smtpUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$smtpPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (Test-Connection -ComputerName $smtpServer -Quiet -Count 1) {
                                if (!(Get-vRLISmtpConfiguration | Where-Object {$_.server -eq $smtpServer})) {
                                    Set-vRLISmtpConfiguration -smtpServer $smtpServer -port $port -sender $sender -username $smtpUser -password $smtpPass | Out-Null
                                    Start-Sleep 2
                                    if (Get-vRLISmtpConfiguration | Where-Object {$_.server -eq $smtpServer}) {
                                        Write-Output "Configuring SMTP Server in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with SMTP server ($smtpServer): SUCCESSFUL"
                                    } else {
                                        Write-Error "Configuring SMTP Server in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with SMTP server ($smtpServer): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Configuring SMTP Server in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with SMTP server ($smtpServer), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to communicate with SMTP Server ($smtpServer), check details: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLISmtpConfiguration

Function Add-vRLIAuthenticationWSA {
    <#
        .SYNOPSIS
        Configure Workspace ONE Access as an authentication source in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAuthenticationWSA cmdlet configures Workspace ONE Access as an authentication source in VMware
        Aria Operations for Logs. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity is possible to Workspace ONE Access
        - Configures Workspace ONE Access as an authentication source in VMware Aria Operations for Logs if not already configured

        .EXAMPLE
        Add-vRLIAuthenticationWSA -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -wsaUser admin -wsaPass VMw@re1!
        This example configures Workspace ONE Access as an authentication source in VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER wsaFqdn
        The Workspace ONE Access FQDN or IP Address.

        .PARAMETER wsaUser
        The Workspace ONE Access administrator username.

        .PARAMETER wsaPass
        The Workspace ONE Access administrator password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (Test-WSAConnection -server $wsaFqdn) {
                                if (Test-WSAAuthentication -server $wsaFqdn -user $wsaUser -pass $wsaPass) {
                                    if ((Get-vRLIAuthenticationWSA).enabled -eq $false) {
                                        Set-vRLIAuthenticationWSA -hostname $wsaFqdn -port 443 -redirectUrl $vcfVrliDetails.fqdn -username $wsaUser -password $wsaPass
                                        Start-Sleep 2
                                        if ((Get-vRLIAuthenticationWSA).enabled -eq $true) {
                                            Write-Output "Configuring Workspace ONE Access Integration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with ($wsaFqdn): SUCCESSFUL"
                                        } else {
                                            Write-Error "Configuring Workspace ONE Access Integration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with ($wsaFqdn): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Configuring Workspace ONE Access Integration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with ($wsaFqdn), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to communicate with Workspace ONE Access Instance ($wsaFqdn), check details: POST_VALIDATION_FAILED"
                                
                                }
                            }
                        }
                    }
                }
            }
        } 
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLIAuthenticationWSA

Function Undo-vRLIAuthenticationWSA {
    <#
        .SYNOPSIS
        Disable Workspace ONE Access as an authentication source in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Undo-vRLIAuthenticationWSA cmdlet configures Workspace ONE Access as an authentication source in VMware
        Aria Operations for Logs. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Disables Workspace ONE Access as an authentication source in VMware Aria Operations for Logs if not already configured

        .EXAMPLE
        Undo-vRLIAuthenticationWSA -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example disables Workspace ONE Access as an authentication source in VMware Aria Operations for Logs.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if ((Get-vRLIAuthenticationWSA).enabled -eq $true) {
                                Remove-vRLIAuthenticationWSA | Out-Null
                                Start-Sleep 2
                                if ((Get-vRLIAuthenticationWSA).enabled -eq $false) {
                                    Write-Output "Disabling Workspace ONE Access Integration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                } else {
                                    Write-Error "Disabling Workspace ONE Access Integration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Disabling Workspace ONE Access Integration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), already disabled: SKIPPED"
                            }
                        }
                    }
                }
            }
        } 
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIAuthenticationWSA

Function Add-vRLIAuthenticationAD {
    <#
        .SYNOPSIS
        Configure Active Directory as an authentication source for VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAuthenticationAD cmdlet configures Active Diretory as an authentication source in VMware Aria
        Operations for Logs with an SSL connection. The cmdlet connects to SDDC Manager using the -server, -user,and
        -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity is possible to Active Directory
        - Configures Active Diretory as an authentication source in VMware Aria Operations for Logs

        .EXAMPLE
        Add-vRLIAuthenticationAD -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -domainBindUser svc-logs-ad -domainBindPass VMw@re1! -domainServers sfo-ad01.sfo.rainpole.io
        This example enables Active Directory as an authentication source in VMware Aria Operations for Logs.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$domainServers
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            foreach ($domainServer in $domainServers) {
                                if (Test-Connection -ComputerName ($domainServer) -Quiet -Count 1) {
                                    $serivceAccountCheck = Test-ADAuthentication -user $domainBindUser -pass $domainBindPass -server $domain -domain $domain -ErrorAction SilentlyContinue
                                    if ($serivceAccountCheck -match "AD Authentication Successful") {
                                        if ((Get-vRLIAuthenticationAD).enableAD -eq $false) {
                                            Set-vRLIAuthenticationAD -domain $domain -domainServers $domainServers -domainBindUser $domainBindUser -domainBindPass $domainBindPass -connectionType CUSTOM -port 636 -requireSsl:$true | Out-Null
                                            Start-Sleep 2
                                            if ((Get-vRLIAuthenticationAD).enableAD -eq $true) {
                                                Write-Output "Configuring Active Directory Authentication in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with for Domain ($domain): SUCCESSFUL"
                                            } else {
                                                Write-Error "Configuring Active Directory Authentication in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with for Domain ($domain): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Configuring Active Directory Authentication in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with for Domain ($domain), already exists: SKIPPED"
                                        }
                                    } else {
                                        Write-Error "Unable to authentucate to Active Directory with user ($domainBindUser): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to communicate with Active Directory Domain Controller ($domainServer), check details: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }
            }
        } 
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLIAuthenticationAD

Function Undo-vRLIAuthenticationAD {
    <#
        .SYNOPSIS
        Disable Active Directory as an authentication source for VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAuthenticationAD cmdlet disables Active Diretory as an authentication source in VMware Aria
        Operations for Logs. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Disables Active Diretory as an authentication source in VMware Aria Operations for Logs

        .EXAMPLE
        Undo-vRLIAuthenticationAD -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io
        This example enables Active Directory as an authentication source in VMware Aria Operations for Logs.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if ((Get-vRLIAuthenticationAD).enableAD -eq $true) {
                                Remove-vRLIAuthenticationAD | Out-Null
                                Start-Sleep 2
                                if (!((Get-vRLIAuthenticationAD).enableAD -eq $true)) {
                                        Write-Output "Disabling Active Directory Authentication in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                } else {
                                    Write-Error "Disabling Active Directory Authentication in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Disabling Active Directory Authentication in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), already disabled: SKIPPED"
                            }
                        }
                    }
                }
            }
        } 
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIAuthenticationAD

Function Install-vRLIPhotonAgent {
    <#
        .SYNOPSIS
        Install VMware Aria Operations for Logs Photon Agent in a Virtual Machine.

        .DESCRIPTION
        The Install-vRLIPhotonAgent cmdlet installs and configures the VMware Aria Operations for Logs Photon Agent on
        a virtual machine. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the Virtual Machine exists in the vCenter Server inventory
        - Downloads and Installs the Photon Agent on the Virtual Machne
        - Configures the liagent.ini file to communicate with VMware Aria Operations for Logs

        .EXAMPLE
        Install-vRLIPhotonAgent -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vmName sfo-wsa01 -vmRootPass VMw@re1!
        This example installs and configures the VMware Aria Operations for Logs Agent on the virtual machine named 'sfo-wsa01'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vmName
        The Virtual Machine name.

        .PARAMETER vmRootPass
        The Virtual Machine root password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmRootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (($vcfVcenterDetails = Get-VcenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                                if (Test-VsphereConnection -server $vcfVcenterDetails.fqdn) {
                                    if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        if (Get-VM -Name $vmName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue) {
                                            $output = Invoke-VMScript -VM $vmName -ScriptText "systemctl status liagentd" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn
                                            if ($output.ScriptOutput.Contains("/lib/systemd/system/liagentd.service; enabled")) {
                                                Write-Warning "Installing and Configuring VMware Aria Operations for Logs Agent Installed and Configured on ($vmName), already exists: SKIPPED"
                                            } else {
                                                Invoke-VMScript -VM $vmName -ScriptText "rm /tmp/liagent.rpm && rm /tmp/installAgent.sh && /tmp/configureAgent.sh" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn | Out-Null
                                                $installAgent = @(
                                                    "curl -k -o /tmp/liagent.rpm https://$($vcfVrliDetails.fqdn)/api/v1/agent/packages/types/rpm; rpm -Uvh /tmp/liagent.rpm",
                                                    "systemctl enable liagentd",
                                                    "systemctl status liagentd"
                                                )
                                                Foreach ($line in $installAgent) {
                                                    Invoke-VMScript -VM $vmName -ScriptText "echo ""$line"">>/tmp/installAgent.sh" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn | Out-Null
                                                }
                                                $output = Invoke-VMScript -VM $vmName -ScriptText "chmod 777 /tmp/installAgent.sh && /tmp/installAgent.sh" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn
                                                if ($output.ScriptOutput.Contains("/lib/systemd/system/liagentd.service; enabled")) {
                                                    $configureAgent = @(
                                                        "sed -i 's/;hostname=LOGINSIGHT/hostname=$($vcfVrliDetails.fqdn)/' /var/lib/loginsight-agent/liagent.ini",
                                                        "sed -i 's/;hostname=OPERATIONS_FOR_LOGS/hostname=$($vcfVrliDetails.fqdn)/' /var/lib/loginsight-agent/liagent.ini",
                                                        "sed -i 's/;proto=cfapi/proto=cfapi/' /var/lib/loginsight-agent/liagent.ini",
                                                        "sed -i 's/;port=9543/port=9000/' /var/lib/loginsight-agent/liagent.ini",
                                                        "sed -i 's/;ssl=yes/ssl=no/' /var/lib/loginsight-agent/liagent.ini",
                                                        "systemctl restart liagentd",
                                                        "systemctl status liagentd"
                                                    )
                                                    Foreach ($line in $configureAgent) {
                                                        Invoke-VMScript -VM $vmName -ScriptText "echo ""$line"">>/tmp/configureAgent.sh" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn | Out-Null
                                                    }
                                                    $output = Invoke-VMScript -VM $vmName -ScriptText "chmod 777 /tmp/configureAgent.sh && /tmp/configureAgent.sh" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn
                                                    if ($output.ScriptOutput.Contains("active (running)")) {
                                                        Write-Output "Installing and Configuring VMware Aria Operations for Logs Agent Installed and Configured on ($vmName): SUCCESSFUL"
                                                    } else {
                                                        Write-Error "Installing and Configuring VMware Aria Operations for Logs Agent Installed and Configured on ($vmName): POST_VALIDATION_FAILED"
                                                    }
                                                } else {
                                                    Write-Error "Enabling VMware Aria Operations for Logs Agent Installed and Configured on ($vmName): POST_VALIDATION_FAILED"
                                                }
                                            }
                                        } else {
                                            Write-Error "Virtual Machine ($vmName), not Found in vCenter Server ($($vcfVcenterDetails.fqdn)) Inventory, check details and try again: PRE_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-vRLIPhotonAgent

Function Undo-vRLIPhotonAgent {
    <#
        .SYNOPSIS
        Removes the VMware Aria Operations for Logs Photon Agent from a Virtual Machine.

        .DESCRIPTION
        The Undo-vRLIPhotonAgent cmdlet removes the VMware Aria Operations for Logs Photon Agent from a virtual
        machine. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the Virtual Machine exists in the vCenter Server inventory
        - Removes the Photon Agent from the Virtual Machne

        .EXAMPLE
        Undo-vRLIPhotonAgent -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vmName sfo-wsa01 -vmRootPass VMw@re1!
        This example removes the VMware Aria Operations for Logs Agent from the virtual machine named 'sfo-wsa01'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vmName
        The Virtual Machine name.

        .PARAMETER vmRootPass
        The Virtual Machine root password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmRootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (($vcfVcenterDetails = Get-VcenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                            if (Test-VsphereConnection -server $vcfVcenterDetails.fqdn) {
                                if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                    if (Get-VM -Name $vmName -Server $vcfVcenterDetails.fqdn -ErrorAction SilentlyContinue) {
                                        $output = Invoke-VMScript -VM $vmName -ScriptText "systemctl status liagentd" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn
                                        if ($output.ScriptOutput.Contains("/lib/systemd/system/liagentd.service; enabled")) {
                                            Invoke-VMScript -VM $vmName -ScriptText "curl -k -o /tmp/liagent.rpm https://$($vcfVrliDetails.fqdn)/api/v1/agent/packages/types/rpm; package=`$(rpm -q /tmp/liagent.rpm); rpm -e `$package; systemctl daemon-reload" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn | Out-Null
                                            $output = Invoke-VMScript -VM $vmName -ScriptText "systemctl status liagentd" -GuestUser root -GuestPassword $vmRootPass -Server $vcfVcenterDetails.fqdn
                                            if ($output.ScriptOutput.Contains("liagentd.service could not be found")) {
                                                Write-Output "Removing VMware Aria Operations for Logs Agent from ($vmName): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removing VMware Aria Operations for Logs Agent from ($vmName): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Removing VMware Aria Operations for Logs Agent from ($vmName), already performed: SKIPPED"
                                        }
                                    } else {
                                        Write-Error "Virtual Machine ($vmName), not Found in vCenter Server ($($vcfVcenterDetails.fqdn)) Inventory, check details and try again: PRE_VALIDATION_FAILED"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIPhotonAgent

Function Add-vRLIAgentGroup {
    <#
        .SYNOPSIS
        Creates an agent group in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAgentGroup cmdlet creates a new agent group in VMware Aria Operations for Logs. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Creates an agent group in the VMware Aria Operations for Logs if not already configured

        .EXAMPLE
        Add-vRLIAgentGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -agentGroupType wsa -agentGroupName "Workspace ONE Access - Appliance Agent Group" -criteria "xint-wsa01a.rainpole.io","xint-wsa01b.rainpole.io","xint-wsa01c.rainpole.io"
        This example creates an agent group for Workspace ONE Access in VMware Aria Operations for Logs and assigns the Cluster Virtual Machines

        .EXAMPLE
        Add-vRLIAgentGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -agentGroupType photon -agentGroupName "Photon OS - Appliance Agent Group" -criteria "sfo-vcf01.sfo.rainpole.io","xint-vrslcm01.rainpole.io","xint-wsa01a.rainpole.io","xint-wsa01b.rainpole.io","xint-wsa01c.rainpole.io"
        This example creates an agent group for Photon OS in VMare Aria Operations for Logs and assigns the SDDC Manager, VMware Aria Suite Lifecycle and Workspace ONE Access Cluster Virtual Machines.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER agentGroupName
        The Agent Group Name.

        .PARAMETER agentGroupType
        The Agent Group Type (wsa or photon).

        .PARAMETER criteria
        The Agent Group Criteria.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$agentGroupName,
        [Parameter (Mandatory = $true)] [ValidateSet("wsa","photon")] [ValidateNotNullOrEmpty()] [String]$agentGroupType,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$criteria
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (!(Get-vRLIAgentGroup | Select-Object name | Where-Object {$_.name -eq $agentGroupName})) {
                                New-vRLIAgentGroup -agentGroupType $agentGroupType -criteria $criteria -agentGroupName $agentGroupName | Out-Null
                                Start-Sleep 2
                                if (Get-vRLIAgentGroup | Select-Object name | Where-Object {$_.name -eq $agentGroupName}) {
                                    Write-Output "Creating Agent Group in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for ($agentGroupName): SUCCESSFUL"
                                } else {
                                    Write-Error "Creating Agent Group in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for ($agentGroupName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Creating Agent Group in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for ($agentGroupName), already performed: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLIAgentGroup

Function Undo-vRLIAgentGroup {
    <#
        .SYNOPSIS
        Deletes an agent group in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Undo-vRLIAgentGroup cmdlet deletes an agent group from VMware Aria Operations for Logs. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Deletes an agent group from the VMware Aria Operations for Logs if not already configured

        .EXAMPLE
        Undo-vRLIAgentGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -agentGroupName "Workspace ONE Access (IAM) - Appliance Agent Group"
        This example deletes an agent group for Workspace ONE Access in VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER agentGroupName
        The Agent Group Name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$agentGroupName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (Get-vRLIAgentGroup | Select-Object name | Where-Object {$_.name -eq $agentGroupName}) {
                                Remove-vRLIAgentGroup -groupName $agentGroupName | Out-Null
                                if (!(Get-vRLIAgentGroup | Select-Object name | Where-Object {$_.name -eq $agentGroupName})) {
                                    Write-Output "Deleting Agent Group in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for ($agentGroupName): SUCCESSFUL"
                                } else {
                                    Write-Error "Deleting Agent Group in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for ($agentGroupName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Deleting Agent Group in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for ($agentGroupName), does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIAgentGroup

Function Register-vRLIWorkloadDomain {
    <#
        .SYNOPSIS
        Connect a Workload Domain to VMware Aria Operations for Logs.

        .DESCRIPTION
        The Register-vRLIWorkloadDomain cmdlet connects a Workload Domain to VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Obtains the Workload Domain details from the SDDC Manager inventory
        - Connects the Workload Domain with VMware Aria Operations for Logs if not already configured

        .EXAMPLE
        Register-vRLIWorkloadDomain -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -status ENABLED
        This example ENABLES the Workload Domain in VMware Aria Operations for Logs

        .EXAMPLE
        Register-vRLIWorkloadDomain -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -status DISABLED
        This example DISABLES the Workload Domain in VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER status
        The status of the Workload Domain in VMware Aria Operations for Logs "ENABLED" "DISABLED".
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateSet("ENABLED", "DISABLED")] [String]$status
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                                if ((Get-VCFvRLIConnection | Where-Object {$_.domainId -eq (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id}).status -ne $status) { 
                                    Set-VCFvRLIConnection -domainId (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id -status $status | Out-Null
                                    Do {
                                        $configStatus = (Get-VCFvRLIConnection | Where-Object {$_.domainId -eq (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id}).status
                                    } Until ($configStatus -ne "IN_PROGRESS")
                                    if ((Get-VCFvRLIConnection | Where-Object {$_.domainId -eq (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id}).status -eq $status) { 
                                        Write-Output "Workload Domain Intergration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for Workload Domain ($domain): SUCCESSFUL"
                                    } else {
                                        Write-Error "Workload Domain Intergration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Workload Domain Intergration in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for Workload Domain ($domain), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Register-vRLIWorkloadDomain

Function Set-vRLISyslogEdgeCluster {
    <#
        .SYNOPSIS
        Configure Syslog settings on NSX Edge Cluster Nodes.

        .DESCRIPTION
        The Set-vRLISyslogEdgeCluster cmdlet configures Syslog settings on NSX Edge Cluster The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Gathers the NSX Edge Node details from NSX Manager cluster
        - Configures the Syslog settings on the NSX Edge Node if not already configured

        .EXAMPLE
        Set-vRLISyslogEdgeCluster -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -exportname SFO-VRLI
        This example configures the Syslog settings for each NSX Edge node to sent logs to VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER exportName
        The Syslog Exporter name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$exportName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass
                if ($nsxtManagerDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain -listNodes) {
                    if (Test-NSXTConnection -server $nsxtManagerDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $nsxtManagerDetails.fqdn -user $nsxtManagerDetails.adminUser -pass $nsxtManagerDetails.AdminPass) {
                            [Array]$edgeNodeIds = (Get-NsxtEdgeCluster).members.transport_node_id
                            foreach ($nodeId in $edgeNodeIds) {
                                if (!(Get-NsxtSyslogExporter -transport -id $nodeId | Where-Object {$_.exporter_name -eq $exportName})) {
                                    if (!(Get-NsxtSyslogExporter -transport -id $nodeId | Where-Object {$_.server -eq $vcfVrliDetails.fqdn})) {
                                        Set-NsxtSyslogExporter -transport -id $nodeId -exporterName $exportName -logLevel INFO -port 514 -protocol TCP -server $vcfVrliDetails.fqdn | Out-Null
                                        if (Get-NsxtSyslogExporter -transport -id $nodeId | Where-Object {$_.exporter_name -eq $exportName}) {
                                            Write-Output "Configuring Syslog Exporter ($exportName) on Edge Node ($nodeId): SUCCESSFUL"
                                        } else {
                                            Write-Error "Configuring Syslog Exporter ($exportName) on Edge Node ($nodeId): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Configuring Syslog Server ($($vcfVrliDetails.fqdn)) on Edge Node ($nodeId), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Warning "Configuring Syslog Exporter ($exportName) on Edge Node ($nodeId), already exists: SKIPPED"
                                }
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vRLISyslogEdgeCluster

Function Undo-vRLISyslogEdgeCluster {
    <#
        .SYNOPSIS
        Removes the Syslog settings on NSX Edge Cluster Nodes.

        .DESCRIPTION
        The Undo-vRLISyslogEdgeCluster cmdlet removes the Syslog settings on NSX Edge Cluster. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to NSX Manager cluster
        - Gathers the NSX Edge Node details from NSX Manager cluster
        - Removes the Syslog settings on the NSX Edge Node

        .EXAMPLE
        Undo-vRLISyslogEdgeCluster -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -exportname SFO-VRLI
        This example removes the Syslog settings for each NSX Edge node.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER exportName
        The Syslog Exporter name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$exportName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($nsxtManagerDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain -listNodes) {
                    if (Test-NSXTConnection -server $nsxtManagerDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $nsxtManagerDetails.fqdn -user $nsxtManagerDetails.adminUser -pass $nsxtManagerDetails.AdminPass) {
                            [Array]$edgeNodeIds = (Get-NsxtEdgeCluster).members.transport_node_id
                            Foreach ($nodeId in $edgeNodeIds) {
                                if (Get-NsxtSyslogExporter -transport -id $nodeId | Where-Object {$_.exporter_name -eq $exportName}) { 
                                    Remove-NsxtSyslogExporter -transport -id $nodeId -exporterName $exportName | Out-Null
                                    if (!(Get-NsxtSyslogExporter -transport -id $nodeId | Where-Object {$_.exporter_name -eq $exportName})) {
                                        Write-Output "Removing Syslog Exporter ($exportName) on Edge Node ($nodeId): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing Syslog Exporter ($exportName) on Edge Node ($nodeId): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing Syslog Exporter ($exportName) on Edge Node ($nodeId), already removed: SKIPPED"
                                }
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLISyslogEdgeCluster

Function Add-vRLILogArchive {
    <#
        .SYNOPSIS
        Configure log archiving in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLILogArchive cmdlet configure log archiving in VMware Aria Operations for Logs. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Configure an email address to send notifications to in VMware Aria Operations for Logs
        - Configure the log retention threshold in VMware Aria Operations for Logs
        - Configure log archive location in VMware Aria Operations for Logs

        .EXAMPLE
        Add-vRLILogArchive -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -emailAddress administrator@rainpole.io -retentionNotificationDays 1 -retentionInterval weeks -retentionPeriodDays 7 -archiveLocation "nfs://172.27.11.4/sfo-m01-vrli01-400GB"
        This example configures the log archive and retention period in VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER emailAddress
        The email address to send notifications to.

        .PARAMETER retentionNotificationDays
        The number of days to send notifications.

        .PARAMETER retentionInterval
        The interval to send notifications "minutes","hours","days","weeks","months".

        .PARAMETER retentionPeriodDays
        The number of days to retain logs.

        .PARAMETER archiveLocation
        The archive location to store logs.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$emailAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$retentionNotificationDays,
        [Parameter (Mandatory = $true)] [ValidateSet("minutes","hours","days","weeks","months")] [ValidateNotNullOrEmpty()] [String]$retentionInterval,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$retentionPeriodDays,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$archiveLocation
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            Set-vRLIEmailNotification -emailAddress $emailAddress | Out-Null
                            Set-vRLIRetentionThreshold -enable true -interval $retentionNotificationDays -intervalUnit $retentionInterval | Out-Null
                            $partitionId = (Get-vRLIIndexPartition).id
                            Set-vRLILogArchive -id $partitionId -enable true -retentionPeriod $retentionPeriodDays -archiveEnable true -archiveLocation $archiveLocation
                            Write-Output "Configuring Email Notifications, Retention Period and Archive Location in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLILogArchive

Function Add-vRLIAuthenticationGroup {
    <#
        .SYNOPSIS
        Adds a group from the authentication provider in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAuthenticationGroup cmdlet assigns access to a group based on the authentication provider.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that integration with the authentication provider has been enabled
        - Validates that the group has not already been assigned access to VMware Aria Operations for Logs
        - Adds the group to the access control assigning the role provided in VMware Aria Operations for Logs

        .EXAMPLE
        Add-vRLIAuthenticationGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -group gg-vrli-admins -role 'Super Admin' -authProvider vidm
        This example adds the group gg-vrli-admins assigned from Workspace ONE Access with Super Admin role in VMware Aria Operations for Logs

        .EXAMPLE
        Add-vRLIAuthenticationGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -group gg-vrli-admins -role 'Super Admin' -authProvider ad
        This example adds the group gg-vrli-admins assigned from Active Directory with Super Admin role in VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The domain name.

        .PARAMETER group
        The group name.

        .PARAMETER role
        The role to assign to the group "Super Admin","User","Dashboard User","View Only Admin".
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$group,
        [ValidateSet("Super Admin","User","Dashboard User","View Only Admin")] [ValidateNotNullOrEmpty()] [String]$role,
        [Parameter (Mandatory = $true)] [ValidateSet("vidm","ad")] [ValidateNotNullOrEmpty()] [String]$authProvider
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if ($authProvider -eq "vidm") {
                                if ((Get-vRLIAuthenticationWSA).enabled -eq "True") {
                                    if (!(Get-vRLIGroup -authProvider vidm | Where-Object {$_.name -eq $group + "@" + $domain})) {
                                        Add-vRLIGroup -authProvider vidm -domain $domain -group $group -role $role | Out-Null
                                        if (Get-vRLIGroup -authProvider vidm | Where-Object {$_.name -eq $group + "@" + $domain}) {
                                            Write-Output "Adding Group to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Group to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Adding Group to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Workspace ONE Integration on VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), not enabled: PRE_VALIDATION_FAILED"
                                }
                            } elseif ($authProvider -eq "ad") { 
                                if ((Get-vRLIAuthenticationAD).enableAD -eq $true) {
                                    if (!(Get-vRLIGroup -authProvider ad | Where-Object {$_.name -eq $group})) {
                                        Add-vRLIGroup -authProvider ad -domain $domain -group $group -role $role | Out-Null
                                        if (Get-vRLIGroup -authProvider ad | Where-Object {$_.name -eq $group}) {
                                            Write-Output "Adding Group to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Group to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Adding Group to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Active Directory Integration on VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), not enabled: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLIAuthenticationGroup

Function Undo-vRLIAuthenticationGroup {
    <#
        .SYNOPSIS
        Remove a group from the authentication provider in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Undo-vRLIAuthenticationGroup cmdlet removes access to a group based on the authentication provider.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that the group has not already been removed from VMware Aria Operations for Logs
        - Removes access assigned from VMware Aria Operations for Logs

        .EXAMPLE
        Undo-vRLIAuthenticationGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -group gg-vrli-admins -authProvider vidm
        This example removes the group gg-vrli-admins assigned via Workspace ONE Access from its assigned role in VMware Aria Operations for Logs

        .EXAMPLE
        Undo-vRLIAuthenticationGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -group gg-vrli-admins -authProvider ad
        This example removes the group gg-vrli-admins assigned via Active Directory from its assigned role in VMware Aria Operations for Logs.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$group,
        [Parameter (Mandatory = $true)] [ValidateSet("vidm","ad")] [ValidateNotNullOrEmpty()] [String]$authProvider
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (Get-vRLIGroup -authProvider $authProvider | Where-Object {$_.name -eq $group + "@" + $domain}) {
                                Remove-vRLIGroup -authProvider $authProvider -domain $domain -group $group | Out-Null
                                if (!(Get-vRLIGroup -authProvider $authProvider | Where-Object {$_.name -eq $group + "@" + $domain})) {
                                    Write-Output "Removing Group from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing Group from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing Group from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), named ($group), already removed: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIAuthenticationGroup

Function Add-vRLIAlertDatacenter {
    <#
        .SYNOPSIS
        Adds datacenter based alerts in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAlertsDatacenter cmdlet adds datacenter based alerts to VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Datacenter object provided is valid in the vCenter Server inventory
        - Creates the alert in VMware Aria Operations for Logs for the Datacenter object if not already configured
        - Integrates with VMware Aria Operations if the -vropsIntegration switch is provided

        .EXAMPLE
        Add-vRLIAlertDatacenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomainName sfo-m01 -datacenterName sfo-m01-dc01 -email administrator@rainpole.io -alertTemplate ".\SampleNotifications\aria-operations-logs-alerts-datacenter-vcf.json" -vropsIntegration
        This example adds the alerts provided in the JSON file.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomainName
        The name of the workload domain to run against.

        .PARAMETER datacenterName
        The Datacenter name.

        .PARAMETER email
        The email address to send notifications to.

        .PARAMETER alertTemplate
        The JSON file containing the alerts to be added.

        .PARAMETER vropsIntegration
        Enables integration with VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomainName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$email,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alertTemplate,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$vropsIntegration
    )

    $adapter = "VMWARE" # Defines the VMware Aria Operations Adapter type
    $resource = "Datacenter" # Defines the VMware Aria Operations Resource type associated with the Adapter

    Try {
        if (Test-Path -Path $alertTemplate) {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                        if ($PsBoundParameters.ContainsKey("vropsIntegration")) {
                            if (!($vcfVropsDetails = Get-vROPSServerDetail -fqdn $server -username $user -password $pass)) {
                                Break
                            } else {
                                if (!(Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn)) { Break }
                                if (!(Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass)) { Break }
                            }
                        }
                        if (($vcfVcenterDetails = Get-VcenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomainName)) {
                            if (Test-VsphereConnection -server $vcfVcenterDetails.fqdn) {
                                if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                                        if (Get-Datacenter $datacenterName -ErrorAction Ignore ) {
                                            if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) { 
                                                $templateAlerts = (Get-Content -path $alertTemplate -Raw)
                                                $templateAlerts = $templateAlerts -replace '!!datacenterName!!',$datacenterName
                                                $templateAlerts = $templateAlerts -replace '!!email!!',$email
                                                [Array]$allAlerts = $templateAlerts | ConvertFrom-Json
                                                Foreach ($alert in $allAlerts) {
                                                    $json = $alert | ConvertTo-Json
                                                    if ($PsBoundParameters.ContainsKey("vropsIntegration")) {
                                                        $entityObjectId =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $datacenterName | Where-Object {$_.identifierType.name -eq "VMEntityObjectID"}).value
                                                        $entityVcid =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $datacenterName | Where-Object {$_.identifierType.name -eq "VMEntityVCID"}).value
                                                        $vcopsResourceKindKey = '"vcopsResourceKindKey": "' + 'resourceName='+$datacenterName+'&adapterKindKey='+$adapter+'&resourceKindKey='+$resource+'&identifiers=VMEntityName::'+$datacenterName+'$$$VMEntityObjectID::'+$entityObjectId+'$$$VMEntityVCID::'+$entityVcid + '"'
                                                        $json = $json -replace '"vcopsEnabled": false','"vcopsEnabled": true'
                                                        $json = $json -replace '"vcopsResourceKindKey": ""',$vcopsResourceKindKey
                                                    }
                                                    if (!((Get-vRLIAlert | Select-Object name ) | Where-Object {$_.name -eq $alert.name})) {
                                                        Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass | Out-Null
                                                        New-vRLIAlert -json $json | Out-Null
                                                    }
                                                }
                                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                                Write-Output "Adding Datacenter Alerts in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) using template Alert JSON ($alertTemplate) for Workload Domain ($sddcDomainName): SUCCESSFUL"
                                            }
                                        } else {
                                            Write-Error "Unable to find Datacenter ($datacenterName) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }                       
                }
            }
        } else {
            Write-Error "Unable to find template Alert JSON ($alertTemplate): PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLIAlertDatacenter

Function Add-vRLIAlertVirtualMachine {
    <#
        .SYNOPSIS
        Adds virtual machine based alerts in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLIAlertVirtualMachine cmdlet adds virtual machine based alerts to VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Virtual Machine object provided is valid in the vCenter Server inventory
        - Creates the alert in VMware Aria Operations for Logs for the Virtual Machine object if not already configured
        - Integrates with VMware Aria Operations if the -vropsIntegration switch is provided

        .EXAMPLE
        Add-vRLIAlertVirtualMachine -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomainName sfo-m01 -vmName xint-vrslcm01 -email administrator@rainpole.io -alertTemplate ".\SampleNotifications\aria-operations-logs-alerts-vm-asl.json" -vropsIntegration
        This example adds the alerts provided in the JSON file for the VMware Aria Suite Lifecycle Virtual Machine.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to SDDC Manager.

        .PARAMETER pass
        The password used to connect to SDDC Manager.

        .PARAMETER sddcDomainName
        The name of the SDDC Domain.

        .PARAMETER vmName
        The name of the Virtual Machine.

        .PARAMETER email
        The email address to send notifications to.

        .PARAMETER alertTemplate
        The path to the JSON file containing the alerts to be added.

        .PARAMETER vropsIntegration
        Enables integration with VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomainName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$email,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alertTemplate,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$vropsIntegration
    )

    $adapter = "VMWARE" # Defines the VMware Aria Operations Adapter type
    $resource = "VirtualMachine" # Defines the VMware Aria Operations Resource type associated with the Adapter

    Try {
        if (Test-Path -Path $alertTemplate) {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                        if ($PsBoundParameters.ContainsKey("vropsIntegration")) {
                            if (!($vcfVropsDetails = Get-vROPSServerDetail -fqdn $server -username $user -password $pass)) {
                                Break
                            } else {
                                if (!(Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn)) { Break }
                                if (!(Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass)) { Break }
                            }
                        }
                        if (($vcfVcenterDetails = Get-VcenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomainName)) {
                            if (Test-VsphereConnection -server $vcfVcenterDetails.fqdn) {
                                if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                                        if (Get-VM $vmName -ErrorAction Ignore ) {
                                            if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) { 
                                                $templateAlerts = (Get-Content -path $alertTemplate -Raw)
                                                $templateAlerts = $templateAlerts -replace '!!vmName!!',$vmName
                                                $templateAlerts = $templateAlerts -replace '!!email!!',$email
                                                [Array]$allAlerts = $templateAlerts | ConvertFrom-Json
                                                Foreach ($alert in $allAlerts) {
                                                    $json = $alert | ConvertTo-Json
                                                    if ($PsBoundParameters.ContainsKey("vropsIntegration")) {
                                                        $VMEntityInstanceUUID =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $vmName | Where-Object {$_.identifierType.name -eq "VMEntityInstanceUUID"}).value
                                                        $VMEntityObjectID =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $vmName | Where-Object {$_.identifierType.name -eq "VMEntityObjectID"}).value
                                                        $VMEntityVCID =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $vmName | Where-Object {$_.identifierType.name -eq "VMEntityVCID"}).value
                                                        $VMServiceMonitoringEnabled =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $vmName | Where-Object {$_.identifierType.name -eq "VMServiceMonitoringEnabled"}).value
                                                        $isPingEnabled =(Get-vROPSResourceDetail -adapter $adapter -resource $resource -objectname $vmName | Where-Object {$_.identifierType.name -eq "isPingEnabled"}).value
                                                        $vcopsResourceKindKey = '"vcopsResourceKindKey": "' + 'resourceName='+ $vmName +'&adapterKindKey='+ $adapter+ '&resourceKindKey='+ $resource +'&identifiers=VMEntityInstanceUUID::'+ $VMEntityInstanceUUID  +'$$$VMEntityName::'+ $vmName + '$$$VMEntityObjectID::'+ $VMEntityObjectID +'$$$VMEntityVCID::'+ $VMEntityVCID +'$$$VMServiceMonitoringEnabled::'+ $VMServiceMonitoringEnabled +'$$$isPingEnabled::'+ $isPingEnabled +'"'
                                                        $json = $json -replace '"vcopsEnabled": false','"vcopsEnabled": true'
                                                        $json = $json -replace '"vcopsResourceKindKey": ""',$vcopsResourceKindKey
                                                    }
                                                    if (!((Get-vRLIAlert | Select-Object name ) | Where-Object {$_.name -eq $alert.name})) {
                                                        Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass | Out-Null
                                                        New-vRLIAlert -json $json | Out-Null
                                                    }
                                                }
                                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                                Write-Output "Adding Virtual Machine Alerts in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) using template Alert JSON ($alertTemplate) for Workload Domain ($sddcDomainName): SUCCESSFUL"
                                            }
                                        } else {
                                            Write-Error "Unable to find Virtual Machine ($vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }                         
                }
            }
        } else {
            Write-Error "Unable to find template Alert JSON ($alertTemplate): PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLIAlertVirtualMachine

Function Undo-vRLIAlert {
    <#
        .SYNOPSIS
        Removes alerts from VMware Aria Operations for Logs.

        .DESCRIPTION
        The Undo-vRLIAlert cmdlet removes datacenter based alerts from VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Deletes all alerts with the name provided in the title

        .EXAMPLE
        Undo-vRLIAlert -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -name sfo-m01-dc01
        This example removes all alerts that contain the name 'sfo-m01-dc01'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER name
        The name of the alert to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if ($allAlerts = Get-vRLIAlert | Where-Object {$_.name -match $name} | Select-Object name, id) {
                                Foreach ($alert in $allAlerts) {
                                    Remove-vRLIAlert -alertId $alert.id | Out-Null
                                }
                                Write-Output "Removing Alerts in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) with name ($name): SUCCESSFUL"
                            } else {
                                Write-Warning "Removing Alerts in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)) for name ($name), none exist: SKIPPED"
                            }
                        }
                    }
                }                         
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLIAlert

Function Enable-vRLIAlert {
    <#
        .SYNOPSIS
        Enables alerts in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Enable-vRLIAlert cmdlet enables alerts in VMware Aria Operations for Logs. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Enables the alert in VMware Aria Operations for Logs

        .EXAMPLE
        Enable-vRLIAlert -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -email administrator@rainpole.io -alertDefinition ".\SampleNotifications\aria-operations-logs-alerts-vcf.json"
        This example enables the alerts provided in the JSON file and configures an email address.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER email
        The email address to send notifications to.

        .PARAMETER alertDefinition
        The alert definition file to use.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$email,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$alertDefinition
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("alertDefinition")) {
            $alertDefinition = Get-ExternalFileName -title "Select the alert file (.json)" -fileType "json" -location ((Get-InstalledModule -Name PowerValidatedSolutions).InstalledLocation + "\SampleNotifications\")
        } else {
            if (!(Test-Path -Path $alertDefinition)) {
                Write-Error  "Alert Template '$alertDefinition' File Not Found"
                Break
            }
        }

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) { 
                            $definedAlerts = (Get-Content -path $alertDefinition -Raw)
                            $configureAlerts =  $definedAlerts | ConvertFrom-Json
                            [Array]$allAlerts = Get-vRLIAlert
                            foreach ($alert in $allAlerts) {
                                foreach ($configureAlert in $configureAlerts) {
                                    if ($alert.name -eq $configureAlert.name) {
                                        Set-vRLIAlert -id $alert.id -enabled true | Out-Null
                                        Update-vRLIAlert -id $alert.id -email $email | Out-Null
                                    }
                                }
                            }
                            Write-Output "Enabling VMware Aria Operations for Logs Alerts Defined in ($alertDefinition): SUCCESSFUL"
                        }
                    }
                }                         
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Enable-vRLIAlert

Function Disable-vRLIAlert {
    <#
        .SYNOPSIS
        Disables alerts in VMware Aria Operations for Logs.

        .DESCRIPTION
        The Disable-vRLIAlert cmdlet enables alerts in VMware Aria Operations for Logs. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Enables the alert in VMware Aria Operations for Logs

        .EXAMPLE
        Disable-vRLIAlert -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alertDefinition ".\SampleNotifications\aria-operations-logs-alerts-vcf.json"
        This example disables the alerts provided in the JSON file.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER alertDefinition
        The alert definition file to use.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$alertDefinition
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("alertDefinition")) {
            $alertDefinition = Get-ExternalFileName -title "Select the alert file (.json)" -fileType "json" -location ((Get-InstalledModule -Name PowerValidatedSolutions).InstalledLocation + "\SampleNotifications\")
        } else {
            if (!(Test-Path -Path $alertDefinition)) {
                Write-Error  "Alert Template '$alertDefinition' File Not Found"
                Break
            }
        }

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) { 
                            $definedAlerts = (Get-Content -path $alertDefinition -Raw)
                            $configureAlerts =  $definedAlerts | ConvertFrom-Json
                            [Array]$allAlerts = Get-vRLIAlert
                            foreach ($alert in $allAlerts) {
                                foreach ($configureAlert in $configureAlerts) {
                                    if ($alert.name -eq $configureAlert.name) {
                                        Set-vRLIAlert -id $alert.id -enabled false | Out-Null
                                    }
                                }
                            }
                            Write-Output "Disabling VMware Aria Operations for Logs Alerts Defined in ($alertDefinition): SUCCESSFUL"
                        }
                    }
                }                         
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Disable-vRLIAlert

Function Add-vRLILogForwarder {
    <#
        .SYNOPSIS
        Adds a log forwarder destination to VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-vRLILogForwarder cmdlet adds log forwarder destination to VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Adds a log forwarder destination to VMware Aria Operations for Logs

        .EXAMPLE
        Add-vRLILogForwarder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -name "SFO to LAX" -fqdn lax-vrli01.lax.rainpole.io -protocol SYSLOG -port 514 -transport TCP -acceptCert false -sslEnabled false -testConnection false
        This example adds a log forwarder to VMware Aria Operations for Logs using syslog over TCP 514.

        .EXAMPLE
        Add-vRLILogForwarder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -name "SFO to LAX" -fqdn lax-vrli01.lax.rainpole.io -protocol CFAPI -port 9543 -acceptCert true -sslEnabled true -testConnection true
        This example adds a log forwarder destination to VMware Aria Operations for Logs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER name
        The name of the log forwarder destination.

        .PARAMETER fqdn
        The fully qualified domain name of the log forwarder destination.

        .PARAMETER protocol
        The protocol to use for the log forwarder destination. "CFAPI", "SYSLOG", "RAW".

        .PARAMETER port
        The port to use for the log forwarder destination.

        .PARAMETER transport
        The transport to use for the log forwarder destination. "TCP", "UDP".

        .PARAMETER acceptCert
        Accepts the certificate for the log forwarder destination. "true", "false".

        .PARAMETER sslEnabled
        Enables SSL for the log forwarder destination. "true", "false".

        .PARAMETER testConnection
        Tests the connection to the log forwarder destination. "true", "false".
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateSet("CFAPI", "SYSLOG", "RAW")] [String]$protocol,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $false)] [ValidateSet("TCP", "UDP")] [String]$transport,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$acceptCert,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$sslEnabled,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$testConnection
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (! (Get-vRlILogForwarder | Where-Object {$_.host -eq $fqdn})) {
                                if ($protocol -eq 'SYSLOG' -and (-not $PsBoundParameters.ContainsKey('transport'))) {
                                    Throw 'You must enter a transport for SYSLOG.'
                                } elseif ($protocol -eq 'SYSLOG' -and ($PsBoundParameters.ContainsKey('transport'))) {
                                    Set-vRLILogForwarder -name $name -server $fqdn -protocol $protocol -port $port -transport $transport -acceptCert $acceptCert -sslEnabled $sslEnabled -testConnection $testConnection | Out-Null
                                    if (Get-vRlILogForwarder | Where-Object {$_.host -eq $fqdn}) {
                                        Write-Output "Adding log forwarder ($fqdn) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Warning "Adding log forwarder ($fqdn) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Set-vRLILogForwarder -name $name -server $fqdn -protocol $protocol -port $port -acceptCert $acceptCert -sslEnabled $sslEnabled -testConnection $testConnection | Out-Null
                                    if (Get-vRlILogForwarder | Where-Object {$_.host -eq $fqdn}) {
                                        Write-Output "Adding log forwarder ($fqdn) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Warning "Adding log forwarder ($fqdn) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }          
                                }
                            } else {
                                Write-Warning "Adding log forwarder ($fqdn) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), already exist: SKIPPED"
                            }
                        }
                    }
                }                         
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRLILogForwarder

Function Undo-vRLILogForwarder {
    <#
        .SYNOPSIS
        Removes a log forwarder destination to VMware Aria Operations for Logs.

        .DESCRIPTION
        The Undo-vRLILogForwarder cmdlet removes log forwarder destination to VMware Aria Operations for Logs.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Removes a log forwarder destination from VMware Aria Operations for Logs

        .EXAMPLE
        Undo-vRLILogForwarder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -fqdn lax-vrli01.lax.rainpole.io -protocol SYSLOG -port 514
        This example removes a log forwarder to VMware Aria Operations for Logs using syslog over TCP 514.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER name
        The name of the log forwarder to remove.

        .PARAMETER fqdn
        The FQDN of the log forwarder to remove.

        .PARAMETER protocol
        The protocol of the log forwarder to remove. 'CFAPI", "SYSLOG", "RAW".

        .PARAMETER port
        The port of the log forwarder to remove.

        .PARAMETER transport
        The transport of the log forwarder to remove. 'TCP', 'UDP'.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateSet("CFAPI", "SYSLOG", "RAW")] [String]$protocol,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $false)] [ValidateSet("TCP", "UDP")] [String]$transport
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {                   
                            if ($protocol -eq 'SYSLOG' -and (-not $PsBoundParameters.ContainsKey('transport'))) {
                                Throw 'You must enter a transport for SYSLOG.'
                            } elseif ($protocol -eq 'SYSLOG' -and ($PsBoundParameters.ContainsKey('transport'))) {
                                if ($response = Get-vRlILogForwarder | Where-Object {$_.name -eq $name -and $_.host -eq $fqdn -and $_.protocol -eq $protocol -and $_.port -eq $port -and $_.transportProtocol -eq $transport}) {
                                    Remove-vRLILogForwarder -id $response.id | Out-Null
                                    if (Get-vRlILogForwarder | Where-Object { $_.name -eq $name -and $_.host -eq $fqdn -and $_.protocol -eq $protocol -and $_.port -eq $port -and $_.transportProtocol -eq $transport}) {
                                        Write-Error "Removing log forwarder ($fqdn) from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                    } else {
                                        Write-Output "Removing log forwarder ($fqdn) from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                    }
                                } else {
                                    Write-Warning "Removing log forwarder ($fqdn) from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), configuration does not exist."
                                }
                            } else {
                                if ($response = Get-vRlILogForwarder | Where-Object {$_.name -eq $name -and $_.host -eq $fqdn -and $_.protocol -eq $protocol -and $_.port -eq $port}) {
                                    Remove-vRLILogForwarder -id $response.id | Out-Null
                                    if (Get-vRlILogForwarder | Where-Object {$_.name -eq $name -and $_.host -eq $fqdn -and $_.protocol -eq $protocol -and $_.port -eq $port}) {
                                        Write-Error "Removing log forwarder ($fqdn) from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                    } else {
                                        Write-Output "Removing log forwarder ($fqdn) from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                    }
                                } else {
                                    Write-Warning "Removing log forwarder ($fqdn) from VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), configuration does not exist."
                                }        
                            }
                        }
                    }
                }                         
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRLILogForwarder

Function Add-NsxtNodeProfileSyslogExporter {
    <#
        .SYNOPSIS
        Sets a syslog exporter on an NSX node profile to VMware Aria Operations for Logs.

        .DESCRIPTION
        The Add-NsxtNodeProfileSyslogExporter cmdlet adds a syslog exporter for VMware Aria Operations for Logs to an NSX node
        profile for configuration of syslog on the NSX components included in the node profile.
        The cmdlet connects to SDDC Manager using the -server, -user, -password, and -domain values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Validates that VMware Aria Operations for Logs has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Adds a syslog exporter on the default (All NSX Nodes) or specified node profile for NSX

        .EXAMPLE
        Add-NsxtNodeProfileSyslogExporter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01
        This example adds a syslog exporter to VMware Aria Operations for Logs for the default (All NSX Nodes) node profile.

        .EXAMPLE
        Add-NsxtNodeProfileSyslogExporter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -id "********-****-****-****-************"
        This example adds a syslog exporter to VMware Aria Operations for Logs for a specific node profile with the -id parameter.

        .PARAMETER id
        The id of the NSX node profile to add the syslog exporter to. If not specified, the default (All NSX Nodes) node profile is used.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager.

        .PARAMETER user
        The user name to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER domain
        The domain name of the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if (!($PsBoundParameters.ContainsKey("id"))) {
            $id = "00000000-0000-0000-0000-000000000001" # Default: (All NSX Nodes)
        }
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                            if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                                if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                                    if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                                        if ($profileExists = Get-NsxtNodeProfile -id $id -ErrorAction SilentlyContinue) {
                                            if (!((Get-NsxtNodeProfile -id $id).syslog.exporters | Where-Object {$_.server -eq $vcfVrliDetails.fqdn -and $_.port -eq 514 -and $_.protocol -eq "TCP" -and $_.max_log_level -eq "INFO"})) {
                                                Set-NsxtNodeProfileSyslogExporter -id $id -server $vcfVrliDetails.fqdn -port 514 -protocol "TCP" -logLevel "INFO" | Out-Null
                                                    if ((Get-NsxtNodeProfile -id $id).syslog.exporters | Where-Object {$_.server -eq $vcfVrliDetails.fqdn -and $_.port -eq 514 -and $_.protocol -eq "TCP" -and $_.max_log_level -eq "INFO"}) {
                                                        Write-Output "Adding Syslog Exporter ($($vcfVrliDetails.fqdn)) to NSX Node Profile ($($profileExists.display_name)) on NSX Manager ($($vcfNsxDetails.fqdn)): SUCCESSFUL"
                                                    } else {
                                                        Write-Error "Adding Syslog Exporter ($($vcfVrliDetails.fqdn)) to NSX Node Profile ($($profileExists.display_name)) in NSX Manager ($($vcfNsxDetails.fqdn)): POST_VALIDATION_FAILED"
                                                    }     
                                            } else {
                                                Write-Warning "Adding Syslog Exporter ($($vcfVrliDetails.fqdn)) to NSX Node Profile ($($profileExists.display_name)) in NSX Manager ($($vcfNsxDetails.fqdn)), already exist: SKIPPED"
                                            }
                                        } else {
                                            Write-Error "The NSX node profile ($id) does not exist in NSX Manager ($($vcfNsxDetails.fqdn)): PRE_VALIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } 
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NsxtNodeProfileSyslogExporter

Function Undo-NsxtNodeProfileSyslogExporter {
    <#
        .SYNOPSIS
        Removes all syslog exporters on an NSX node profile.

        .DESCRIPTION
        The Undo-NsxtNodeProfileSyslogExporter cmdlet removes a syslog exporter for VMware Aria Operations for Logs from
        an NSX node profile for configuration of syslog on the NSX components included in the node profile.
        The cmdlet connects to SDDC Manager using the -server, -user, -password, and -domain values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes all syslog exporters on the default (All NSX Nodes) or specified node profile for NSX

        .EXAMPLE
        Undo-NsxtNodeProfileSyslogExporter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01
        This example removes all syslog exporters from the default (All NSX Nodes) node profile.

        .EXAMPLE
        Undo-NsxtNodeProfileSyslogExporter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -id "********-****-****-****-************"
        This example removes all syslog exporters from a specific node profile with the -id parameter.

        .PARAMETER id
        The NSX node profile ID to remove the syslog exporter from. If not specified, the default (All NSX Nodes) node profile is used.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if (!($PsBoundParameters.ContainsKey("id"))) {
            $id = "00000000-0000-0000-0000-000000000001"
        }
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                    if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                        if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                            if ($profileExists = Get-NsxtNodeProfile -id $id -ErrorAction SilentlyContinue) {
                                if (!(Get-NsxtNodeProfile -id $id | Where-Object {$null -eq $_.syslog})) {
                                    Remove-NsxtNodeProfileSyslogExporter -id $id | Out-Null
                                    if (Get-NsxtNodeProfile -id $id | Where-Object {$null -eq $_.syslog}) {
                                        Write-Output "Removing all syslog exporters from the NSX node profile ($($profileExists.display_name)) on NSX Manager ($($vcfNsxDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing all syslog exporters from the NSX node profile ($id) in NSX Manager ($($vcfNsxDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }     
                                } else {
                                    Write-Warning "Removing all syslog exporters from the NSX node profile ($($profileExists.display_name)) in NSX Manager ($($vcfNsxDetails.fqdn)), already removed: SKIPPED"
                                }
                            } else {
                                Write-Error "The NSX node profile ($id) does not exist in NSX Manager ($($vcfNsxDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NsxtNodeProfileSyslogExporter

Function Get-vROpsLogForwardingConfig {
    <#
        .SYNOPSIS
        Gets the VMware Aria Operations log forwarding configuration.

        .DESCRIPTION
        The Get-vROpsLogForwardingConfig cmdlet gets the VMware Aria Operations logging forwarding configuration.
        The cmdlet connects to SDDC Manager using the -server, -user, -password, and -domain values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Gets the VMware Aria Operations logging forwarding configuration

        .EXAMPLE
        Get-vROpsLogForwardingConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example returns the log forwarding configuration on VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($vcfVropsDetails = Get-vROpsServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop) {
                                if (Test-vROpsConnection -server $vcfVropsDetails.loadBalancerFqdn) {   
                                    if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                                        if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                                            if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                                                $response = Get-vROpsLogForwarding
                                                $response
                                                if ($response.enabled -eq $false) {
                                                    Write-Warning "VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) logging configuration to VMware Aria Operations for Logs status: Not enabled."
                                                } elseif ($response.enabled -eq $true -and $response.host -ne $vcfVrliDetails.fqdn) {
                                                    Write-Warning "VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) logging configuration to VMware Aria Operations for Logs status: Not configured with $($vcfVrliDetails.fqdn)."                    
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vROpsLogForwardingConfig

Function Get-vRAvRLIConfig {
    <#
        .SYNOPSIS
        Returns the VMware Aria Operations for Logs logging configuration (CFAPI) on VMware Aria Automation.

        .DESCRIPTION
        The Get-vRAvRLIConfig cmdlet returns the VMware Aria Operations for Logs logging configuration for VMware Aria
        Automation. The cmdlet connects to SDDC Manager using the -server, -user, and -password values and connects to
        the first VMware Aria Automation appliance using the -rootPass value.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that network connectivity is possible to the first VMware Aria Automation appliance
        - Returns the VMware Aria Operations for Logs configuration in VMware Aria Automation

        .EXAMPLE
        Get-vRAvRLIConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -rootPass VMw@re1!
        This example returns the VMware Aria Operations for Logs logging configuration on VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER rootPass
        The root password to connect to the first VMware Aria Automation appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($vraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop) {
                                if (Test-vRAConnection -server $vRADetails.node1IpAddress) {   
                                    $vmName = $vraDetails.fqdn | Select-Object -First 1
                                    $vmName = $vmName.Split(".")[0]
                                    if ((Get-VM -Name $vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                        $scriptCommand = "vracli vrli"
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
                                        if (($output.ScriptOutput).Contains('No vRLI integration configured')) {
                                            Write-Output "VMware Aria Automation integration with VMware Aria Operations for Logs status 'Not Configured'"
                                        } elseif (($output.ScriptOutput).Contains('agentId')) {
                                            $output.ScriptOutput | ConvertFrom-JSON
                                        } else {
                                            Write-Error "Returning the VMware Aria Automation integration with VMware Aria Operations for Logs: POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to locate a virtual machine named ($vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"                                        
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vRAvRLIConfig

Function Set-vRAvRLIConfig {
    <#
        .SYNOPSIS
        Sets the VMware Aria Operations for Logs logging configuration (CFAPI) on VMware Aria Automation.

        .DESCRIPTION
        The Set-vRAvRLIConfig cmdlet sets the VMware Aria Operations for Logs logging configuration for VMware Aria
        Automation. The cmdlet connects to SDDC Manager using the -server, -user, and -password values and connects
        to the first VMware Aria Automation appliance using the -rootPass value.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that network connectivity and authentication is possible to VMware Aria Operations for Logs
        - Validates that network connectivity is possible to the first VMware Aria Automation appliance
        - Sets the VMware Aria Operations for Logs configuration on VMware Aria Automation

        .EXAMPLE
        Set-vRAvRLIConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -rootPass VMw@re1! -protocol HTTPS
        This example sets the VMware Aria Operations for Logs logging configuration on VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER rootPass
        The root password to connect to the first VMware Aria Automation appliance.

        .PARAMETER protocol
        The protocol to use for the VMware Aria Operations for Logs logging configuration. The acceptable values for this parameter are: "HTTPS", "HTTP"

        .Parameter port
        The port to use for the VMware Aria Operations for Logs logging configuration. The default value for this parameter is 9543.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass,
        [Parameter (Mandatory = $true)] [ValidateSet("HTTPS", "HTTP")] [String]$protocol,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$port
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($vraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop) {
                                if (Test-vRAConnection -server $vRADetails.node1IpAddress) {
                                    if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                                        if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                                            if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                                                $vmName = $vraDetails.fqdn | Select-Object -First 1
                                                $vmName = $vmName.Split('.')[0]
                                                if ((Get-VM -Name $vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {

                                                    # Set the uri format and default ports
                                                    if ($protocol -eq "HTTPS") {
                                                        $uriProtocol = $protocol.ToLower()
                                                        $uriPort = 9543 # CFAPI SSL Default
                                                    } elseif ($protocol -eq "HTTP") {
                                                        $uriProtocol = $protocol.ToLower()
                                                        $uriPort = 9000 # CFAPI Non-SSL Default
                                                    }

                                                    # Set the port if provided
                                                    if ($PsBoundParameters.ContainsKey("port")) {
                                                        $uriPort = $port
                                                    }

                                                    # Set the uri to the VMware Aria Operations for Logs cluster FQDN
                                                    $uriHost = $vcfVrliDetails.fqdn

                                                    # Run commands based on the selected protocol
                                                    if ($protocol -eq "HTTPS") {
                                                        $scriptCommand = "vracli vrli set " + $uriProtocol + "://" + $uriHost + ":" + $uriPort + " --force" # Must use --force to accept certificate.
                                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
                                                    } else {
                                                        $scriptCommand = 'vracli vrli set ' + $uriProtocol + '://' + $uriHost + ':' + $uriPort
                                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
                                                    }

                                                    $status = Get-vRAvRLIConfig -server $server -user $user -pass $pass -rootPass $rootPass      
                                                    if (($status).Contains("`"host`": `"$uriHost`"") -and ($status).Contains("`"port`": $uriPort") -and ($status).Contains("`"scheme`": `"$uriProtocol`"")) {
                                                        Write-Output 'Setting the VMware Aria Automation integration with VMware Aria Operations for Logs: SUCCESSFUL'
                                                    } elseif (($status).Contains('No vRLI integration configured')) {
                                                        Write-Warning 'VMware Aria Automation integration with VMware Aria Operations for Logs configuration not set: SKIPPED'
                                                    } else {
                                                        Write-Error 'Setting the VMware Aria Automation integration with VMware Aria Operations for Logs: POST_VALIDATION_FAILED'
                                                    }
                                                } else {
                                                    Write-Error "Unable to locate a virtual machine named ($vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"                                        
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vRAvRLIConfig

Function Remove-vRAvRLIConfig {
    <#
        .SYNOPSIS
        Removes the VMware Aria Operations for Logs logging configuration (CFAPI) on VMware Aria Automation.

        .DESCRIPTION
        The Remove-vRAvRLIConfig cmdlet removes the VMware Aria Operations for Logs logging configuration for VMware
        Aria Automation. The cmdlet connects to SDDC Manager using the -server, -user, and -password values and
        connects to the first VMware Aria Automation appliance using the -rootPass value.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that network connectivity is possible to the first VMware Aria Automation appliance
        - Unsets the VMware Aria Operations for Logs configuration in VMware Aria Automation

        .EXAMPLE
        Remove-vRAvRLIConfig -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -rootPass VMw@re1!
        This example removes the VMware Aria Operations for Logs logging configuration on VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager.

        .PARAMETER user
        The user name to authenticate with SDDC Manager.

        .PARAMETER pass
        The password to authenticate with SDDC Manager.

        .PARAMETER rootPass
        The root password to authenticate with the first VMware Aria Automation appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if ($vraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass -ErrorAction Stop) {
                                if (Test-vRAConnection -server $vRADetails.node1IpAddress) {   
                                    $vmName = $vraDetails.fqdn | Select-Object -First 1
                                    $vmName = $vmName.Split(".")[0]
                                    if ((Get-VM -Name $vmName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue )) {
                                        $scriptCommand = "vracli vrli unset"
                                        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
                                        if (($output.ScriptOutput).Contains('Clearing vRLI integration configuration')) {
                                            Write-Output "Clearing the VMware Aria Automation integration with VMware Aria Operations for Logs: SUCCESSFUL"
                                        } elseif (($output.ScriptOutput).Contains('No vRLI integration configured')) {
                                            Write-Warning "VMware Aria Automation integration with VMware Aria Operations for Logs not set: SKIPPED"
                                        } else {
                                            Write-Warning "Clearing the VMware Aria Automation integration with VMware Aria Operations for Logs: POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to locate a virtual machine named ($vmName) in vCenter Server ($($vcfVcenterDetails.fqdn)) inventory: PRE_VALIDATION_FAILED"                                        
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Remove-vRAvRLIConfig

Function Enable-vRLIContentPack {
    <#
        .SYNOPSIS
        Enables the VMware Aria Operations for Logs content pack from the marketplace.

        .DESCRIPTION
        The Enable-vRLIContentPack cmdlet installs a designated VMware Aria Operations for Logs content pack from the
        online Content Pack Marketplace hosted on GitHub.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that network connectivity is possible to VMware Aria Operations for Logs
        - Installs the VMware Aria Operations for Logs content pack selected from the marketplace

        .EXAMPLE
        Enable-vRLIContentPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -token <your_base64_github_token> -contentPack VRO
        This examples installs the VMware Aria Automation Orchestrator content pack from the marketplace.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager.

        .PARAMETER user
        The user name to authenticate with SDDC Manager.

        .PARAMETER pass
        The password to authenticate with SDDC Manager.

        .PARAMETER token.

        .PARAMETER contentPack
        The content pack to install from the marketplace. 'VSPHERE','VSAN','NSX','WSA','VRSLCM','VROPS','VRNI','VRA','VRO','SRM','LINUX','LINUX-SYSTEMD'
        #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$token,
        [Parameter (Mandatory = $true)] [ValidateSet('VSPHERE','VSAN','NSX','WSA','VRSLCM','VROPS','VRNI','VRA','VRO','SRM','LINUX','LINUX-SYSTEMD')] [String]$contentPack
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            # Define the supported content pack namespaces
                            if ($contentPack -eq 'VSPHERE') {$contentPackNamespace = 'com.vmware.vsphere'}
                            if ($contentPack -eq 'VSAN') {$contentPackNamespace = 'com.vmware.vsan'}
                            if ($contentPack -eq 'NSX') {$contentPackNamespace = 'com.vmware.nsxt'}
                            if ($contentPack -eq 'WSA') {$contentPackNamespace = 'com.vmware.vidm'}
                            if ($contentPack -eq 'VRSLCM') {$contentPackNamespace = 'com.vmware.vrslcm801'}
                            if ($contentPack -eq 'VROPS') {$contentPackNamespace = 'com.vmware.vrops67'}
                            if ($contentPack -eq 'VRNI') {$contentPackNamespace = 'om.vmware.vrni'}
                            if ($contentPack -eq 'VRA') {$contentPackNamespace = 'com.vmware.vra.83'}
                            if ($contentPack -eq 'VRO') {$contentPackNamespace = 'com.vmware.vro.83'}
                            if ($contentPack -eq 'SRM') {$contentPackNamespace = 'com.vmware.srm81'}                            
                            if ($contentPack -eq 'LINUX') {$contentPackNamespace = 'com.linux'}
                            if ($contentPack -eq 'LINUX-SYSTEMD') {$contentPackNamespace = 'com.linux.systemd'}

                            $index = Get-vRLIMarketplaceMetadata -index -token $token
                            $contentPackFile = ($index | Where-Object { $_.namespace -eq $contentPackNamespace }).filename
                            $contentPackName = ($index| Where-Object { $_.namespace -eq $contentPackNamespace }).name
                            $contentPackVersion = ($index | Where-Object { $_.namespace -eq $contentPackNamespace }).contentVersion

                            if ($response = Get-vRLIMarketplaceMetadata -token $token) {
                                $uri = ($response | Where-Object { $_.name -eq $contentPackFile }).url
                                $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $ghHeaders
                                $json = $response | ConvertTo-Json -Depth 100 -Compress
                            } else {
                                Write-Warning "Retrieving content pack ($contentPackFile) metadata from the marketplace: PRE_VALIDATION_FAILED"
                            }

                            if (Get-vRLIContentPack | Where-Object { $_.name -eq $contentPackName }) {
                                Write-Warning "Installing content pack ($contentPackName v$contentPackVersion) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), already exists: SKIPPED"
                            } else {
                                if ($json) {
                                    Install-vRLIContentPack -json $json | Out-Null
                                    if ($contentPackStatus = (Get-vRLIContentPack | Where-Object { $_.name -eq $contentPackName })) {
                                        Write-Output "Installing content pack ($contentPackName v$contentPackVersion) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Installing content pack ($contentPackName v$contentPackVersion) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }   
                                } else {
                                    Write-Error "Installing content pack ($contentPackName v$contentPackVersion) to VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): PRE_VALIDATION_FAILED"
                                }
                            }       
                        }          
                    }         
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Enable-vRLIContentPack

Function Uninstall-vRLIContentPack {
    <#
        .SYNOPSIS
        Uninstalls the VMware Aria Operations for Logs content pack.

        .DESCRIPTION
        The Uninstall-vRLIContentPack cmdlet removes a designated VMware Aria Operations for Logs content pack.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that network connectivity is possible to VMware Aria Operations for Logs
        - Removes the VMware Aria Operations for Logs content pack

        .EXAMPLE
        Uninstall-vRLIContentPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -contentPack WSA
        This examples removes the Workspace ONE Access content pack from VMware Aria Operations for Logs

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager.

        .PARAMETER user
        The user name to authenticate with SDDC Manager.

        .PARAMETER pass
        The password to authenticate with SDDC Manager.

        .PARAMETER contentPack
        The content pack to remove. 'VSPHERE','VSAN','NSX','WSA','VRSLCM','VROPS','VRNI','VRA','VRO','SRM','LINUX','LINUX-SYSTEMD'
        #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateSet('VSPHERE','VSAN','NSX','WSA','VRSLCM','VROPS','VRNI','VRA','VRO','SRM','LINUX','LINUX-SYSTEMD')] [String]$contentPack
    )

    Try {
        if ($contentPack -eq 'VSPHERE') {$contentPackNamespace = 'com.vmware.vsphere'}
        if ($contentPack -eq 'VSAN') {$contentPackNamespace = 'com.vmware.vsan'}
        if ($contentPack -eq 'NSX') {$contentPackNamespace = 'com.vmware.nsxt'}
        if ($contentPack -eq 'WSA') {$contentPackNamespace = 'com.vmware.vidm'}
        if ($contentPack -eq 'VRSLCM') {$contentPackNamespace = 'com.vmware.vrslcm801'}
        if ($contentPack -eq 'VROPS') {$contentPackNamespace = 'com.vmware.vrops67'}
        if ($contentPack -eq 'VRNI') {$contentPackNamespace = 'om.vmware.vrni'}
        if ($contentPack -eq 'VRA') {$contentPackNamespace = 'com.vmware.vra.83'}
        if ($contentPack -eq 'VRO') {$contentPackNamespace = 'com.vmware.vro.83'}
        if ($contentPack -eq 'SRM') {$contentPackNamespace = 'com.vmware.srm81'}                            
        if ($contentPack -eq 'LINUX') {$contentPackNamespace = 'com.linux'}
        if ($contentPack -eq 'LINUX-SYSTEMD') {$contentPackNamespace = 'com.linux.systemd'}

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            if (Get-vRLIContentPack | Where-Object { $_.namespace -match $contentPackNamespace }) {
                                Remove-vRLIContentPack -namespace $contentPackNamespace | Out-Null
                                if (!(Get-vRLIContentPack | Where-Object { $_.name -eq $contentPack })) {
                                    Write-Output "Disabling content pack ($contentPack) in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                } else {
                                    Write-Error "Disabling content pack ($contentPack) in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Disabling content pack ($contentPack) in VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), does not exist: SKIPPED"
                            }       
                        }          
                    }         
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Uninstall-vRLIContentPack
Function Update-vRLIContentPack {
    <#
        .SYNOPSIS
        Updates the VMware Aria Operations for Logs content pack from the marketplace.

        .DESCRIPTION
        The Update-vRLIContentPack cmdlet updates a designated VMware Aria Operations for Logs content pack from the
        online Content Pack Marketplace hosted on GitHub.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that network connectivity is possible to VMware Aria Operations for Logs
        - Updates the VMware Aria Operations for Logs content pack selected from the marketplace

        .EXAMPLE
        Update-vRLIContentPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -contentPack NSX
        This example updates the VMware Aria Operations for Logs content pack for NSX to the latest version from the marketplace.

        .PARAMETER Server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager.

        .PARAMETER User
        The user name to authenticate with SDDC Manager.

        .PARAMETER Pass
        The password to authenticate with SDDC Manager.

        .PARAMETER ContentPack
        The content pack to update. The supported content packs are: VSPHERE','VSAN','NSX','WSA','VRSLCM','VROPS','VRNI','VRA','VRO','SRM','LINUX','LINUX-SYSTEMD'
        #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateSet('VSPHERE','VSAN','NSX','WSA','VRSLCM','VROPS','VRNI','VRA','VRO','SRM','LINUX','LINUX-SYSTEMD')] [String]$contentPack
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrliDetails = Get-vRLIServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRLIConnection -server $vcfVrliDetails.fqdn) {
                        if (Test-vRLIAuthentication -server $vcfVrliDetails.fqdn -user $vcfVrliDetails.adminUser -pass $vcfVrliDetails.adminPass) {
                            # Define the supported content pack namespaces
                            if ($contentPack -eq 'VSPHERE') {$contentPackNamespace = 'com.vmware.vsphere'}
                            if ($contentPack -eq 'VSAN') {$contentPackNamespace = 'com.vmware.vsan'}
                            if ($contentPack -eq 'NSX') {$contentPackNamespace = 'com.vmware.nsxt'}
                            if ($contentPack -eq 'WSA') {$contentPackNamespace = 'com.vmware.vidm'}
                            if ($contentPack -eq 'VRSLCM') {$contentPackNamespace = 'com.vmware.vrslcm801'}
                            if ($contentPack -eq 'VROPS') {$contentPackNamespace = 'com.vmware.vrops67'}
                            if ($contentPack -eq 'VRNI') {$contentPackNamespace = 'om.vmware.vrni'}
                            if ($contentPack -eq 'VRA') {$contentPackNamespace = 'com.vmware.vra.83'}
                            if ($contentPack -eq 'VRO') {$contentPackNamespace = 'com.vmware.vro.83'}
                            if ($contentPack -eq 'SRM') {$contentPackNamespace = 'com.vmware.srm81'}                            
                            if ($contentPack -eq 'LINUX') {$contentPackNamespace = 'com.linux'}
                            if ($contentPack -eq 'LINUX-SYSTEMD') {$contentPackNamespace = 'com.linux.systemd'}

                            $index = Get-vRLIMarketplaceMetadata -index -token $token
                            $contentPackFile = ($index | Where-Object { $_.namespace -eq $contentPackNamespace }).filename
                            $contentPackName = ($index | Where-Object { $_.namespace -eq $contentPackNamespace }).name
                            $contentPackVersion = ($index | Where-Object { $_.namespace -eq $contentPackNamespace }).contentVersion

                            if ($status = Get-vRLIContentPack | Where-Object { $_.name -eq $contentPackName }) {
                                if ($response = Get-vRLIMarketplaceMetadata -token $token) {
                                    $uri = ($response | Where-Object { $_.name -eq $contentPackFile }).url
                                    $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $ghHeaders
                                    $json = $response | ConvertTo-Json -Depth 100 -Compress
                                    if ($status.contentVersion -lt $contentPackVersion) {
                                        Install-vRLIContentPack -update -json $json | Out-Null
                                        if (Get-vRLIContentPack | Where-Object {$_.name -eq $contentPackName -and $_.contentVersion -eq $contentPackVersion}) {
                                            Write-Output "Updating the content pack ($contentPackName) to version v$contentPackVersion on VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): SUCCESSFUL"
                                        } else {
                                            Write-Error "Updating the content pack ($contentPackName) to version v$contentPackVersion on VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }   
                                    } else {
                                        Write-Warning "Updating the content pack ($contentPackName) to version v$contentPackVersion on VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), no update needed: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Retrieving content pack ($contentPackFile) metadata from the marketplace: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Updating content pack ($contentPackName) to version v$contentPackVersion on VMware Aria Operations for Logs ($($vcfVrliDetails.fqdn)), not installed: PRE_VALIDATION_FAILED"
                            }   
                        }          
                    }         
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vRLIContentPack

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region I N T E L L I G E N T O P E R A T I O N S M A N A G E M E N T F U N C T I O N S ###########

Function Export-IomJsonSpec {
    <#
        .SYNOPSIS
        Create JSON specification for Intelligent Operations Management.

        .DESCRIPTION
        The Export-IomJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation workbook
        to deploy the Intelligent Operations Management for VMware Cloud Foundation validated solution:
        - Validates that the Planning and Preparation is available
        - Generates the JSON specification file using the Planning and Preparation workbook

        .EXAMPLE
        Export-IomJsonSpec -workbook .\pnp-workbook.xlsx -jsonFile .\iomDeploySpec.json
        This example creates a JSON specification Intelligent Operations Management using the Planning and Preparation Workbook.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER jsonFile
        The path to the JSON specification file to be created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        }
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Generation of Intelligent Operations Management (.json) Specification File"
        if (Test-Path -Path $workbook) {
            $pnpWorkbook = Open-ExcelPackage -Path $Workbook
            $jsonObject = @()
            $jsonObject += [pscustomobject]@{
                'sddcManagerFqdn'                   = $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value
                'sddcManagerUser'                   = $pnpWorkbook.Workbook.Names["sso_default_admin"].Value
                'sddcManagerPass'                   = $pnpWorkbook.Workbook.Names["administrator_vsphere_local_password"].Value
                'mgmtSddcDomainName'                = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value
                'contentLibraryName'                = $pnpWorkbook.Workbook.Names["vrslcm_xreg_content_library"].Value
                'licenseAlias'                      =  $pnpWorkbook.Workbook.Names["vrops_license_alias"].Value
                'licenseKey'                        = if ($pnpWorkbook.Workbook.Names["vrs_license"].Value) { $pnpWorkbook.Workbook.Names["vrs_license"].Value } else { $pnpWorkbook.Workbook.Names["vrops_license"].Value }
                'certificateAlias'                  = $pnpWorkbook.Workbook.Names["xreg_vrops_virtual_hostname"].Value
                'rootPasswordAlias'                 = $pnpWorkbook.Workbook.Names["xreg_vrops_root_password_alias"].Value
                'rootPassword'                      = $pnpWorkbook.Workbook.Names["xreg_vrops_root_password"].Value
                'rootUserName'                      = "root"
                'xintPasswordAlias'                 = $pnpWorkbook.Workbook.Names["vrslcm_xreg_env_password_alias"].Value
                'xintPassword'                      = $pnpWorkbook.Workbook.Names["vrslcm_xreg_env_password"].Value
                'xintUserName'                      = $pnpWorkbook.Workbook.Names["vrslcm_xreg_admin_username"].Value
                'environmentName'                   = $pnpWorkbook.Workbook.Names["vrslcm_xreg_env"].Value
                'datacenter'                        = $pnpWorkbook.Workbook.Names["vrslcm_xreg_dc"].Value
                'vcenterFqdn'                       = $pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value
                'vcenterDatacenter'                 = $pnpWorkbook.Workbook.Names["mgmt_datacenter"].Value
                'vcenterCluster'                    = $pnpWorkbook.Workbook.Names["mgmt_cluster"].Value
                'vcenterDatastore'                  = $pnpWorkbook.Workbook.Names["mgmt_vsan_datastore"].Value
                'network'                           = $pnpWorkbook.Workbook.Names["xreg_seg01_name"].Value
                'gateway'                            = $pnpWorkbook.Workbook.Names["xreg_seg01_gateway_ip"].Value
                'netmask'                            = $pnpWorkbook.Workbook.Names["xreg_seg01_mask"].Value
                'domain'                            = $pnpWorkbook.Workbook.Names["region_ad_parent_fqdn"].Value
                'searchpath'                        = $pnpWorkbook.Workbook.Names["region_ad_parent_fqdn"].Value
                'dns'                               = ($pnpWorkbook.Workbook.Names["region_dns1_ip"].Value + "," + $pnpWorkbook.Workbook.Names["region_dns2_ip"].Value)
                'ntp'                                = $pnpWorkbook.Workbook.Names["xregion_ntp1_server"].Value
                'deployOption'                      = $pnpWorkbook.Workbook.Names["xreg_vrops_appliance_size"].Value.ToLower()
                'clusterFqdn'                       = $pnpWorkbook.Workbook.Names["xreg_vrops_virtual_fqdn"].Value
                'clusterIp'                         = $pnpWorkbook.Workbook.Names["xreg_vrops_virtual_ip"].Value
                'vmNameNodeA'                       = $pnpWorkbook.Workbook.Names["xreg_vrops_nodea_hostname"].Value
                'hostNameNodeA'                     = $pnpWorkbook.Workbook.Names["xreg_vrops_nodea_fqdn"].Value
                'ipNodeA'                           = $pnpWorkbook.Workbook.Names["xreg_vrops_nodea_ip"].Value
                'vmNameNodeB'                       = $pnpWorkbook.Workbook.Names["xreg_vrops_nodeb_hostname"].Value
                'hostNameNodeB'                     = $pnpWorkbook.Workbook.Names["xreg_vrops_nodeb_fqdn"].Value
                'ipNodeB'                           = $pnpWorkbook.Workbook.Names["xreg_vrops_nodeb_ip"].Value
                'vmNameNodeC'                       = $pnpWorkbook.Workbook.Names["xreg_vrops_nodec_hostname"].Value
                'hostNameNodeC'                     = $pnpWorkbook.Workbook.Names["xreg_vrops_nodec_fqdn"].Value
                'ipNodeC'                           = $pnpWorkbook.Workbook.Names["xreg_vrops_nodec_ip"].Value
                'networkProxies'                    = $pnpWorkbook.Workbook.Names["reg_seg01_name"].Value
                'gatewayProxies'                    = $pnpWorkbook.Workbook.Names["reg_seg01_gateway_ip"].Value
                'netmaskProxies'                    = $pnpWorkbook.Workbook.Names["reg_seg01_mask_overlay_backed"].Value
                'domainProxies'                        = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'searchpathProxies'                    = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'vmNameProxyA'                        = $pnpWorkbook.Workbook.Names["region_vropsca_hostname"].Value
                'hostNameProxyA'                    = $pnpWorkbook.Workbook.Names["region_vropsca_fqdn"].Value
                'ipProxyA'                            = $pnpWorkbook.Workbook.Names["region_vropsca_ip"].Value
                'vmNameProxyB'                        = $pnpWorkbook.Workbook.Names["region_vropscb_hostname"].Value
                'hostNameProxyB'                    = $pnpWorkbook.Workbook.Names["region_vropscb_fqdn"].Value
                'ipProxyB'                            = $pnpWorkbook.Workbook.Names["region_vropscb_ip"].Value
                'vmFolderOperations'                = $pnpWorkbook.Workbook.Names["xreg_vrops_vm_folder"].Value
                'vmFolderProxies'                   = $pnpWorkbook.Workbook.Names["region_vrops_collector_vm_folder"].Value
                'vmListOperations'                  = $pnpWorkbook.Workbook.Names["xreg_vrops_nodea_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodeb_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodec_hostname"].Value
                'vmListProxies'                     = $pnpWorkbook.Workbook.Names["region_vropsca_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["region_vropscb_hostname"].Value
                'vmListAll'                         = $pnpWorkbook.Workbook.Names["xreg_vrops_nodea_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodeb_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodec_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["region_vropsca_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["region_vropscb_hostname"].Value
                'antiAffinityRuleNameOperations'    = $pnpWorkbook.Workbook.Names["xreg_vrops_anti_affinity_rule_name"].Value
                'antiAffinityRuleNameProxies'       = $pnpWorkbook.Workbook.Names["xreg_vropsrc_anti_affinity_rule_name"].Value
                'drsGroupNameOperations'            = $pnpWorkbook.Workbook.Names["xreg_vrops_vm_group_name"].Value
                'drsGroupNameIdentity'              = $pnpWorkbook.Workbook.Names["xreg_wsa_vm_group_name"].Value
                'drsGroupNameProxies'               = $pnpWorkbook.Workbook.Names["region_vropsrc_vm_group_name"].Value
                'drsGroupNameAz'                    = $pnpWorkbook.Workbook.Names["mgmt_az1_vm_group_name"].Value
                'vmToVmRuleNameWsa'                 = $pnpWorkbook.Workbook.Names["xreg_wsa_vrops_vm_to_vm_rule_name"].Value
                'vmToVmRuleNameOperations'          = $pnpWorkbook.Workbook.Names["xreg_vrops_vm_to_vm_rule_name"].Value
                'vmToVmRuleNameProxies'             = $pnpWorkbook.Workbook.Names["xreg_vrops_vm_to_vm_rule_name"].Value
                'stretchedCluster'                  = $pnpWorkbook.Workbook.Names["mgmt_stretched_cluster_chosen"].Value
                'currency'                          = $pnpWorkbook.Workbook.Names["xreg_vrops_currency"].Value
                'wsaFqdn'                           = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_fqdn"].Value
                'wsaUser'                           = $pnpWorkbook.Workbook.Names["local_admin_username"].Value
                'wsaPass'                           = $pnpWorkbook.Workbook.Names["local_admin_password"].Value
                'domainFqdn'                        = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
                'domainBindUser'                    = $pnpWorkbook.Workbook.Names["child_svc_vsphere_ad_user"].Value
                'domainBindPass'                    = $pnpWorkbook.Workbook.Names["child_svc_vsphere_ad_password"].Value
                'serviceAccountOperationsVcf'       = $pnpWorkbook.Workbook.Names["iom_vcf_svc_user"].Value
                'vsphereRoleNameOperations'         = $pnpWorkbook.Workbook.Names["iom_vsphere_role"].Value
                'wsaBindUser'                       = $pnpWorkbook.Workbook.Names["child_svc_wsa_ad_user"].Value
                'wsaBindPass'                       = $pnpWorkbook.Workbook.Names["child_svc_wsa_ad_password"].Value
                'baseDnGroup'                       = $pnpWorkbook.Workbook.Names["child_ad_groups_ou"].Value
                'adGroups'                          = "$($pnpWorkbook.Workbook.Names["group_gg_vrops_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrops_content_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrops_read_only"].Value)"
                'smtpServer'                        = $pnpWorkbook.Workbook.Names["smtp_server"].Value
                'smtpPort'                          = $pnpWorkbook.Workbook.Names["smtp_server_port"].Value -as [Int]
                'smtpAuthUser'                      = $pnpWorkbook.Workbook.Names["smtp_sender_username"].Value
                'smtpAuthPass'                      = $pnpWorkbook.Workbook.Names["smtp_sender_password"].Value
                'senderAddress'                     = $pnpWorkbook.Workbook.Names["xreg_vrops_smtp_sender_email_address"].Value
                'operationsAdminGroup'              = $pnpWorkbook.Workbook.Names["group_gg_vrops_admins"].Value
                'operationsContentAdminGroup'       = $pnpWorkbook.Workbook.Names["group_gg_vrops_content_admins"].Value
                'operationsReadOnlyGroup'           = $pnpWorkbook.Workbook.Names["group_gg_vrops_read_only"].Value
                'iomVcfServiceAccount'              = $pnpWorkbook.Workbook.Names["iom_vcf_svc_user"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
                'iomVcfServiceAccountPassword'      = $pnpWorkbook.Workbook.Names["iom_vcf_svc_password"].Value
                'iomVsphereServiceAccount'          = $pnpWorkbook.Workbook.Names["iom_vsphere_svc_user"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
                'iomVsphereServiceAccountPassword'  = $pnpWorkbook.Workbook.Names["iom_vsphere_svc_password"].Value
                'collectorGroupName'                = $pnpWorkbook.Workbook.Names["region_vrops_collector_group_name"].Value
                'defaultCollectorGroup'             = $pnpWorkbook.Workbook.Names["xreg_vrops_default_collector_group"].Value
                'ipListOperations'                  = $pnpWorkbook.Workbook.Names["xreg_vrops_virtual_ip"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodea_ip"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodeb_ip"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vrops_nodec_ip"].Value
                'ipListProxies'                     = $pnpWorkbook.Workbook.Names["region_vropsca_ip"].Value + "," + $pnpWorkbook.Workbook.Names["region_vropscb_ip"].Value
                'ipListIdentity'                    = $pnpWorkbook.Workbook.Names["xreg_wsa_virtual_ip"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_ip"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_ip"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_ip"].Value
                'pingAdapterNameProxies'            = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value + "-operations-proxies"
                'pingAdapterNameOperations'         = $pnpWorkbook.Workbook.Names["xreg_vrops_virtual_hostname"].Value + "-cluster"
                'pingAdapterNameIdentity'           = $pnpWorkbook.Workbook.Names["xreg_wsa_virtual_hostname"].Value + "-cluster"
            }
            Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
            $jsonObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonFile
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            Foreach ($jsonValue in $jsonInput.psobject.properties) {
                if ($jsonValue.value -eq "Value Missing" -or $null -eq $jsonValue.value ) {
                    $issueWithJson = $true
                }
            }
            if ($issueWithJson) {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Creation of JSON Specification file for Intelligent Operations Management, missing data: POST_VALIDATION_FAILED"
            } else { 
                Show-PowerValidatedSolutionsOutput -message "Creation of JSON Specification file for Intelligent Operations Management: SUCCESSFUL"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-IomJsonSpec

Function Invoke-IomDeployment {
    <#
        .SYNOPSIS
        End-to-end Deployment of Intelligent Operations and Management.

        .DESCRIPTION
        The Invoke-IomDeployment cmdlet is a single function to implement the configuration of the Intelligent
        Operations and Management for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-IomDeployment -jsonFile .\iomDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\"
        This example configures Intelligent Operations and Management for VMware Cloud Foundation using the JSON spec supplied

        .PARAMETER jsonFile
        The fully qualified path to the JSON specification file (.json).

        .PARAMETER certificates
        The fully qualified path to the certificates directory.

        .PARAMETER binaries
        The fully qualified path to the binaries directory.

        .PARAMETER useContentLibrary
        Use a vSphere Content Library to store the binaries.

        .PARAMETER nested
        Deploy Intelligent Operations and Management for VMware Cloud Foundation in a nested configuration.
    #>
  

    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificates,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$binaries,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$nested
    )

    $solutionName           = "Intelligent Operations Management for VMware Cloud Foundation"
    $operationsProductName  = "VMware Aria Operations"
    $lcmProductName         = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Deployment of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            $operationsPem = $certificates + $jsonInput.certificateAlias + ".2.chain.pem"
            if (Test-Path -Path $operationsPem) {
                if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn ) {
                    if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                        if (Get-VCFWSA) {
                            if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                                if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                    $allWorkloadDomains         = Get-VCFWorkloadDomain
                                    $failureDetected            = $false
                                    $pvsModulePath              = (Get-InstalledModule -Name PowerValidatedSolutions).InstalledLocation
                                    $operationsVsphereTemplate  = $pvsModulePath + "\vSphereRoles\" + "aria-operations-vsphere-integration.role"
                                    $operationsNotifications    = $pvsModulePath + "\SampleNotifications\" + "aria-operations-notifications-vcf.csv"

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Creating a vSphere Content Library for Operational Management"
                                        $StatusMsg = Add-ContentLibrary -Server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ContentLibraryName $jsonInput.contentLibraryName -published -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                            $opsProxyOvaPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match "Operations-Cloud-Proxy"}).name
                                            if ((([regex]::Match(((Split-Path $opsProxyOvaPath -leaf)), "(?<=-)\d+\.\d+\.\d+").Value) -notin (Get-vRSLCMProductVersion -productId vrops))) {
                                                Show-PowerValidatedSolutionsOutput -type ERROR -message "$operationsProductName Cloud Proxy OVA ($binaryFile) does not match a supported version: PRE_VALIDATION_FAILED"; $failureDetected = $true
                                            } elseif (($opsProxyOvaPath -match "Operations-Cloud-Proxy")) {
                                                Show-PowerValidatedSolutionsOutput -message "Importing $operationsProductName Cloud Proxy OVA into vSphere Content Library"
                                                $StatusMsg = Import-ContentLibraryItem -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibrary $jsonInput.contentLibraryName -file $opsProxyOvaPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            } else {
                                                Show-PowerValidatedSolutionsOutput -type ERROR -message "$operationsProductName Cloud Proxy OVA ($automationOvaPath) File Not Found: PRE_VALIDATION_FAILED"
                                            }
                                            $opsOvaPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match "Operations-Manager-Appliance"}).name
                                            if ((([regex]::Match(((Split-Path $opsOvaPath -leaf)), "(?<=-)\d+\.\d+\.\d+").Value) -notin (Get-vRSLCMProductVersion -productId vrops))) {
                                                Show-PowerValidatedSolutionsOutput -type ERROR -message "$operationsProductName OVA ($binaryFile) does not match a supported version: PRE_VALIDATION_FAILED"; $failureDetected = $true
                                            } elseif (($opsOvaPath -match "Operations-Manager-Appliance")) {
                                                Show-PowerValidatedSolutionsOutput -message "Importing $operationsProductName OVA into vSphere Content Library"
                                                $StatusMsg = Import-ContentLibraryItem -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibrary $jsonInput.contentLibraryName -file $opsOvaPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            } else {
                                                Show-PowerValidatedSolutionsOutput -type ERROR -message "$operationsProductName OVA ($automationOvaPath) File Not Found: PRE_VALIDATION_FAILED"
                                            }
                                        }
                                        $allDatacenters = Get-vRSLCMDatacenter
                                        foreach ($datacenter in $allDatacenters) {
                                            Sync-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid -vcenterName (Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid).vcenterName | Out-Null
                                        }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Assigning SDDC Manager Role to a Service Account"
                                        $StatusMsg = Add-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUser -domainBindPass $jsonInput.domainBindPass -principal $jsonInput.serviceAccountOperationsVcf -role ADMIN -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Defining a Custom Role in vSphere"
                                        foreach ($sddcDomain in $allWorkloadDomains) {
                                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                                $StatusMsg = Add-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -roleName $jsonInput.vsphereRoleNameOperations -template $operationsVsphereTemplate -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring Service Account Permissions for vSphere Integration"
                                        foreach ($sddcDomain in $allWorkloadDomains) {
                                            if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                                $StatusMsg = Add-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUser -domainBindPass $jsonInput.domainBindPass -principal $jsonInput.serviceAccountOperationsVcf -role $jsonInput.vsphereRoleNameOperations -propagate true -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Creating Virtual Machine and Template Folders for $operationsProductName Appliances"
                                        $StatusMsg = Add-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -folderName $jsonInput.vmFolderOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = Add-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -folderName $jsonInput.vmFolderProxies -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Preparing the NSX to $operationsProductName Integration"
                                        foreach ($sddcDomain in $allWorkloadDomains) {
                                            Show-PowerValidatedSolutionsOutput -message "Preparing the NSX to $operationsProductName Integration for Workload Domain ($($sddcDomain.name))"
                                            $StatusMsg = Add-NsxtPrincipalIdentity -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -principalId ("svc-iom-" + $(($sddcDomain.nsxtCluster.vipFqdn).Split('.')[-0])) -role enterprise_admin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Adding $operationsProductName License to $lcmProductName"
                                        $StatusMsg = New-vRSLCMLockerLicense -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.licenseAlias -license $jsonInput.licenseKey -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Importing the Certificate for $operationsProductName to $lcmProductName"
                                        $StatusMsg = Import-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -certChainPath $operationsPem -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Adding the $operationsProductName Passwords to $lcmProductName"
                                        $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.rootPasswordAlias -password $jsonInput.rootPassword -userName $jsonInput.rootUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.xintPasswordAlias -password $jsonInput.xintPassword -userName $jsonInput.xintUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Deploying $operationsProductName Using $lcmProductName"
                                        if ($PsBoundParameters.ContainsKey("nested")) {
                                            $StatusMsg = New-vROPSDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -nested -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        } elseif ($PsBoundParameters.ContainsKey("nested") -and $PsBoundParameters.ContainsKey("useContentLibrary")) {
                                            $StatusMsg = New-vROPSDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -nested -useContentLibrary -contentLibrary $contentLibrary -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg    
                                        } elseif ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                            $StatusMsg = New-vROPSDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -useContentLibrary -contentLibrary $contentLibrary -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        } else {
                                            $StatusMsg = New-vROPSDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        }
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -Type INFO -Message "$StatusMsg" } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -Type WARNING -Message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                        if ( $StatusMsg -match "FAILED" -or $WarnMsg -match "FAILED" ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message "Deployment of $operationsProductName FAILED"; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Activating Data Persistence on VMware Cloud Proxy Appliances for the $operationsProductName Virtual Machines"
                                        Show-PowerValidatedSolutionsOutput -type NOTE -message "CURRENTLY NO AUTOMATION"
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Moving the $operationsProductName Appliances to the Dedicated Folders"
                                        $StatusMsg = Move-VMtoFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -vmList $jsonInput.vmListOperations -folder $jsonInput.vmFolderOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg -match "SUCCESSFUL") { Show-PowerValidatedSolutionsOutput -message "Relocating $operationsProductName Cluster Appliances to Dedicated Folder: SUCCESSFUL" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -Type WARNING -Message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg }
                                        $StatusMsg = Move-VMtoFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -vmList $jsonInput.vmListProxies -folder $jsonInput.vmFolderProxies -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg -match "SUCCESSFUL") { Show-PowerValidatedSolutionsOutput -message "Relocating $operationsProductName Collector Appliances to Dedicated Folder: SUCCESSFUL" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -Type WARNING -Message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring vSphere DRS Anti-Affinity Rules for the $operationsProductName Appliances"
                                        $StatusMsg = Add-AntiAffinityRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.antiAffinityRuleNameOperations -antiAffinityVMs $jsonInput.vmListOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = Add-AntiAffinityRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.antiAffinityRuleNameProxies -antiAffinityVMs $jsonInput.vmListProxies -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Creating a VM Group and Define the Startup Order of the $operationsProductName Analytics Appliances"
                                        $StatusMsg = Add-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameOperations -drsGroupVMs $jsonInput.vmListOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = Add-VmStartupRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.vmToVmRuleNameWsa -vmGroup $jsonInput.drsGroupNameOperations -dependOnVmGroup $jsonInput.drsGroupNameIdentity -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Creating a VM Group and Define the Startup Order of the $operationsProductName Cloud Proxy Appliances"
                                        $StatusMsg = Add-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameProxies -drsGroupVMs $jsonInput.vmListProxies -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg }
                                        $StatusMsg = Add-VmStartupRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.vmToVmRuleNameOperations -vmGroup $jsonInput.drsGroupNameProxies -dependOnVmGroup $jsonInput.drsGroupNameOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg }
                                    }

                                    if (!$failureDetected) {
                                        if ($stretchedCluster -eq "Include") {
                                            Show-PowerValidatedSolutionsOutput -message "Adding the $operationsProductName Appliances to the First Availability Zone VM Group"
                                            $StatusMsg = Add-VmGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -name $groupName -vmList $vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Synchronizing the Active Directory Groups for $operationsProductName in Workspace ONE Access"
                                        $StatusMsg = Add-WorkspaceOneDirectoryGroup -server $jsonInput.wsaFqdn -user $jsonInput.wsaUser -pass $jsonInput.wsaPass -domain $jsonInput.domainFqdn -bindUser $jsonInput.wsaBindUser -bindPass $jsonInput.wsaBindPass -baseDnGroup $jsonInput.baseDnGroup -adGroups $jsonInput.adGroups -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Grouping the VMware Cloud Proxy Appliances"
                                        $StatusMsg = Add-vROPSGroupRemoteCollectors -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -collectorGroupName $jsonInput.collectorGroupName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring User Access in $operationsProductName"
                                        $StatusMsg = Import-vROPSUserGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -groupName $jsonInput.operationsAdminGroup -role Administrator -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = Import-vROPSUserGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -groupName $jsonInput.operationsContentAdminGroup -role ContentAdmin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = Import-vROPSUserGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -groupName $jsonInput.operationsReadOnlyGroup -role ReadOnly -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring Email Alert Plug-in Settings for $operationsProductName"
                                        $StatusMsg = Add-vROPSAlertPluginEmail -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -pluginName "Email-Alert-Plugin" -smtpServer $jsonInput.smtpServer -smtpPort $jsonInput.smtpPort -senderAddress $jsonInput.senderAddress -secureConnection true -protocol TLS -authentication false -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Setting the Currency for Cost Calculation in $operationsProductName"
                                        $StatusMsg = Add-vROPSCurrency -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -currency $jsonInput.currency -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Removing Existing vCenter Server Adapter in $operationsProductName"
                                        $StatusMsg = Remove-OperationsDefaultAdapter -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "Removing Default vCenter Server/vSAN Adapter and Credentials from VMware Aria Operations: SUCCESSFUL" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Activating the VMware Cloud Foundation Integration"
                                        $StatusMsg = Register-vROPSManagementPack -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -state enable -packType VCF -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring Credentials for SDDC Components in $operationsProductName"
                                        $StatusMsg = Add-vROPSVcfCredential -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -serviceUser $jsonInput.iomVcfServiceAccount -servicePassword $jsonInput.iomVcfServiceAccountPassword -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        foreach ($sddcDomain in $allWorkloadDomains) {
                                            $StatusMsg = Add-vROPSVcenterCredential -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -serviceUser $jsonInput.iomVsphereServiceAccount -servicePassword $jsonInput.iomVsphereServiceAccountPassword -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $nsxCertKey = $certificates + $sddcDomain.nsxtCluster.vipFqdn.Split('.')[0] + ".key"
                                            $nsxCert = $certificates + $sddcDomain.nsxtCluster.vipFqdn.Split('.')[0] + ".cer"
                                            if (Test-Path -Path $nsxCertKey,$nsxCert) {
                                                $StatusMsg = Add-vROPSNsxCredential -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -certificate -certificateData $nsxCert -certificateKey $nsxCertKey -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Configuring the VMware Cloud Foundation Integration"
                                        Show-PowerValidatedSolutionsOutput -type NOTE -message "CURRENTLY NO AUTOMATION"
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Activating the VMware Infrastructure Health Integration in $operationsProductName"
                                        $StatusMsg = Register-vROPSManagementPack -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -state enable -packType VMwareInfrastructureHealth -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Activating the Ping Integration in $operationsProductName"
                                        $StatusMsg = Register-vROPSManagementPack -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -state enable -packType Ping -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Adding Ping Adapters for the $operationsProductName Nodes"
                                        $StatusMsg = Add-vROPSAdapterPing -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -addressList $jsonInput.ipListOperations -adapterName $jsonInput.pingAdapterNameOperations -collectorGroupName $jsonInput.defaultCollectorGroup -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        $StatusMsg = Add-vROPSAdapterPing -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -addressList $jsonInput.ipListProxies -adapterName $jsonInput.pingAdapterNameProxies -collectorGroupName $jsonInput.collectorGroupName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Adding Ping Adapters for the Clustered Workspace ONE Access"
                                        $StatusMsg = Add-vROPSAdapterPing -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -addressList $jsonInput.ipListIdentity -adapterName $jsonInput.pingAdapterNameIdentity -collectorGroupName $jsonInput.defaultCollectorGroup -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }

                                    if (!$failureDetected) {
                                        Show-PowerValidatedSolutionsOutput -message "Creating Notifications in $operationsProductName for VMware Cloud Foundation Issues"
                                        $StatusMsg = Import-vROPSNotification -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -csvPath $operationsNotifications -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }
                            }
                        } else {
                            Show-PowerValidatedSolutionsOutput -type ERROR -Message "Unable to find Workspace ONE Access in ($($jsonInput.sddcManagerFqdn)): PRE_VALIDATION_FAILED"
                        }
                    }
                }
            } else {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Certificate File (.pem) for $logsProductName ($operationsForLogsPem): File Not Found"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $solutionName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-IomDeployment

Function Invoke-UndoIomDeployment {
    <#
        .SYNOPSIS
        End-to-end removal of Intelligent Operations and Management.

        .DESCRIPTION
        The Invoke-UndoIomDeployment cmdlet is a single function to remove the configuration of the Intelligent
        Operations and Management for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-UndoIomDeployment -jsonFile .\iomDeploySpec.json
        This example removes the configuration of Intelligent Operations and Management for VMware Cloud Foundation using the JSON spec supplied.

        .PARAMETER jsonFile
        The JSON specification file for the Intelligent Operations and Management for VMware Cloud Foundation validated solution.
    #>
  

    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    $solutionName           = "Intelligent Operations Management for VMware Cloud Foundation"
    $operationsProductName  = "VMware Aria Operations"
    $lcmProductName         = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Removal of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn ) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domainType "MANAGEMENT")) {
                        if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $allWorkloadDomains = Get-VCFWorkloadDomain                                

                                Show-PowerValidatedSolutionsOutput -message "Removing the Active Directory Groups for $operationsProductName in Workspace ONE Access"
                                $StatusMsg = Undo-WorkspaceOneDirectoryGroup -server $jsonInput.wsaFqdn -user $jsonInput.wsaUser -pass $jsonInput.wsaPass -domain $jsonInput.domainFqdn -bindUser $jsonInput.wsaBindUser -bindPass $jsonInput.wsaBindPass -baseDnGroup $jsonInput.baseDnGroup -adGroups $jsonInput.adGroups -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing a VM Group and Startup Order of the $operationsProductName Cloud Proxy Appliances"
                                    $StatusMsg = Undo-VmStartupRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.vmToVmRuleNameOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameProxies -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing a VM Group and Startup Order of the $operationsProductName Analytics Appliances"
                                    $StatusMsg = Undo-VmStartupRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.vmToVmRuleNameWsa -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing vSphere DRS Anti-Affinity Rules for the $operationsProductName Appliances"
                                    $StatusMsg = Undo-AntiAffinityRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.antiAffinityRuleNameOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-AntiAffinityRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.antiAffinityRuleNameProxies -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                            foreach ($vm in ($jsonInput.vmListAll -Split ',')) {
                                                if (Get-VM -name $vm -ErrorAction SilentlyContinue ) {
                                                    Get-VM -name $vm | Stop-VM -RunAsync -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                    Do {$powerState = (Get-VM -name $vm | Select-Object PowerState).PowerState } Until ($powerState -eq "PoweredOff")
                                                    Get-VM -name $vm | Remove-VM -DeletePermanently -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                }
                                            }
                                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                            Show-PowerValidatedSolutionsOutput -message "Deleting $operationsProductName from $lcmProductName"
                                            $StatusMsg = Undo-vROPSDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -environmentName $jsonInput.environmentName -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing the $operationsProductName Passwords to $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.rootPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.xintPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing $operationsProductName Certificate to $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing $operationsProductName License to $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerLicense -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.licenseAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing the NSX to $operationsProductName Integration"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        Show-PowerValidatedSolutionsOutput -message "Removing the NSX to $operationsProductName Integration for Workload Domain ($($sddcDomain.name))"
                                        $StatusMsg = Undo-NsxtPrincipalIdentity -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -principalId ("svc-iom-" + $(($sddcDomain.nsxtCluster.vipFqdn).Split('.')[-0])) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Virtual Machine and Template Folders for the $operationsProductName Appliances"
                                    $StatusMsg = Undo-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -foldername $jsonInput.vmFolderOperations  -folderType VM -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -foldername $jsonInput.vmFolderProxies -folderType VM -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Service Account Permissions for vSphere Integration"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                            $StatusMsg = Undo-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -domain $jsonInput.domainFqdn -principal $jsonInput.serviceAccountOperationsVcf -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }
                                
                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing a Custom Role in vSphere"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        if ($sddcDomain.type -eq "MANAGEMENT" -or ($sddcDomain.type -eq "VI" -and $sddcDomain.ssoName -ne "vsphere.local")) {
                                            $StatusMsg = Undo-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $sddcDomain.name -roleName $jsonInput.vsphereRoleNameOperations -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing SDDC Manager Role to a Service Account"
                                    $StatusMsg = Undo-SddcManagerRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -principal $jsonInput.serviceAccountOperationsVcf -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for Intelligent Logging and Analytics ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-UndoIomDeployment

Function Export-vROPsJsonSpec {
    <#
        .SYNOPSIS
        Create VMware Aria Operations Deployment JSON specification.

        .DESCRIPTION
        The Export-vRLIJsonSpec cmdlet creates the JSON specification file using the Intelligent Operations Management
        JSON specification file generated from the Planning and Preparation workbook to deploy VMware Aria Operations
        using VMware Aria Suite Lifecycle. The cmdlet connects to SDDC Manager using the -server, -user, and
        -password values.
        - Validates that the JSON specification file for Intelligent Operations Management
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Suite Lifecycle has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the License, Certificate and Password have been created in VMware Aria Suite Lifecycle locker
        - Generates the deployment JSON specification file using the JSON specification file for Intelligent Operations
        Management for use with VMware Aria Suite Lifecycle named '<management_domain_name>-operationsDeploySpec.json.json'

        .EXAMPLE
        Export-vROPsJsonSpec -jsonFile .\ilaDeploySpec.json
        This example creates a JSON specification file for deploying VMware Aria Operations using data from the JSON specification file for Intelligent Operations Management

        .EXAMPLE
        Export-vROPsJsonSpec -jsonFile .\ilaDeploySpec.json -nested
        This example creates a reduce footprint JSON specification file for deploying VMware Aria Operations using data from the JSON specification file for Intelligent Operations Management

        .EXAMPLE
        Export-vROPsJsonSpec -jsonFile .\ilaDeploySpec.json -customVersion 8.10.0
        This example creates a JSON specification file for deploying VMware Aria Operations using a custom version and data from the JSON specification file for Intelligent Operations Management

        .EXAMPLE
        Export-vROPsJsonSpec -jsonFile .\ilaDeploySpec.json -useContentLibrary -contentLibrary Operations
        This example creates a JSON specification file for deploying VMware Aria Operations using data from the JSON specification file for Intelligent Operations Management and deplpying OVAs from a vSphere Content Library.

        .PARAMETER jsonFile
        The JSON file for Intelligent Operations Management.

        .PARAMETER outputPath
        The folder location where the VMware Aria Operations JSON file is created.

        .PARAMETER nested
        Specifies to use the reduced footprint JSON specification file for deploying VMware Aria Operations.

        .PARAMETER customVersion
        The custom version to use for deploying VMware Aria Operations.

        .PARAMETER useContentLibrary
        Specifies to use a vSphere Content Library for deploying VMware Aria Operations.

        .PARAMETER contentLibrary
        The vSphere Content Library to use for deploying VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$outputPath,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$nested,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {

        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                        $vcfVersion = ((Get-VCFManager).version -Split ('\.\d{1}\-\d{8}')) -split '\s+' -match '\S'
                        if ($PsBoundParameters.ContainsKey("outputPath")) {
                            $jsonSpecFileName = $outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "operationsDeploySpec.json")
                        } else {
                            $jsonSpecFileName = (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "operationsDeploySpec.json")
                        }
                        if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                if ($vropsLicense = Get-vRSLCMLockerLicense | Where-Object {$_.key -eq $jsonInput.licenseKey}) {
                                    if ($vropsCertificate = Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $jsonInput.certificateAlias}) {
                                        if ($defaultPassword = Get-vRSLCMLockerPassword -alias $jsonInput.xintPasswordAlias) {
                                            if ($vropsPassword = Get-vRSLCMLockerPassword -alias $jsonInput.rootPasswordAlias) {
                                                if ($vcfVersion -ge "4.5.0") {
                                                    $vcCredentials = Get-vRSLCMLockerPassword | Where-Object {$_.userName -match (($jsonInput.vcenterFqdn).Split(".")[0] + "@vsphere.local")}
                                                } else {
                                                    $vcCredentials = Get-vRSLCMLockerPassword -alias (($jsonInput.vcenterFqdn).Split(".")[0] + "-" + $jsonInput.vcenterDatacenter)
                                                }
                                                if ($datacenterName = Get-vRSLCMDatacenter | Where-Object {$_.dataCenterName -eq $jsonInput.datacenter}) {
                                                    $vcfVersion = ((Get-VCFManager).version -Split ('\.\d{1}\-\d{8}')) -split '\s+' -match '\S'
                                                    $xintEnvironment = Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $jsonInput.environmentName}
                                                    
                                                    if (!$PsBoundParameters.ContainsKey("customVersion")) {
                                                        if ($vcfVersion -eq "4.3.0") { $vropsVersion = "8.4.0"}
                                                        if ($vcfVersion -eq "4.3.1") { $vropsVersion = "8.5.0"}
                                                        if ($vcfVersion -eq "4.4.0") { $vropsVersion = "8.6.2"}
                                                        if ($vcfVersion -eq "4.4.1") { $vropsVersion = "8.6.2"}
                                                        if ($vcfVersion -eq "4.5.0") { $vropsVersion = "8.6.3"}
                                                        if ($vcfVersion -eq "4.5.1") { $vropsVersion = "8.14.0"}
                                                        if ($vcfVersion -eq "4.5.2") { $vropsVersion = "8.14.0"}
                                                        if ($vcfVersion -eq "5.0.0") { $vropsVersion = "8.14.0"}
                                                        if ($vcfVersion -eq "5.1.0") { $vropsVersion = "8.14.0"}
                                                    } else {
                                                        $vropsVersion = $customVersion
                                                    }
                                                    

                                                    $infrastructurePropertiesObject = @()
                                                    $infrastructurePropertiesObject += [pscustomobject]@{
                                                        'dataCenterVmid'    = $datacenterName.dataCenterVmid
                                                        'regionName'        = "default"
                                                        'zoneName'          = "default"
                                                        'vCenterName'       = ($jsonInput.vcenterFqdn).Split(".")[0]
                                                        'vCenterHost'       = $jsonInput.vcenterFqdn
                                                        'vcUsername'        = $vcCredentials.userName
                                                        'vcPassword'        = ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                        'acceptEULA'        = "true"
                                                        'enableTelemetry'   = "true"
                                                        'defaultPassword'   = ("locker:password:" + $($defaultPassword.vmid) + ":" + $($defaultPassword.alias))
                                                        'certificate'       = ("locker:certificate:" + $($vropsCertificate.vmid) + ":" + $($vropsCertificate.alias))
                                                        'cluster'           = ($jsonInput.vcenterDatacenter + "#" + $jsonInput.vcenterCluster)
                                                        'storage'           = $jsonInput.vcenterDatastore
                                                        'diskMode'          = "thin"
                                                        'network'           = $jsonInput.network
                                                        'masterVidmEnabled' = "false"
                                                        'dns'               = $jsonInput.dns
                                                        'domain'            = $jsonInput.domain
                                                        'gateway'           = $jsonInput.gateway
                                                        'netmask'           = $jsonInput.netmask
                                                        'searchpath'        = $jsonInput.searchPath
                                                        'timeSyncMode'      = "ntp"
                                                        'ntp'               = $jsonInput.ntp
                                                        'isDhcp'            = "false"
                                                        'vcfProperties'     = '{"vcfEnabled":true,"sddcManagerDetails":[{"sddcManagerHostName":"' + $jsonInput.sddcManagerFqdn + '","sddcManagerName":"default","sddcManagerVmid":"default"}]}'
                                                    }
                                                    $infrastructureObject = @()
                                                    $infrastructureObject += [pscustomobject]@{
                                                        'properties'    = ($infrastructurePropertiesObject | Select-Object -Skip 0)
                                                    }

                                                    ### Generate the Properties Details
                                                    if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                        $contentLibraryItems = ((Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenterName.dataCenterVmid -vcenterName ($jsonInput.vcenterFqdn).Split(".")[0]).contentLibraries | Where-Object { $_.contentLibraryName -eq $contentLibrary }).contentLibraryItems
                                                        if ($contentLibraryItems) {
                                                            $contentLibraryItemId = ($contentLibraryItems | Where-Object { $_.contentLibraryItemName -match "Operations-Manager-Appliance-$vropsVersion" }).contentLibraryItemId
                                                            $contentLibraryProxyItemId = ($contentLibraryItems | Where-Object { $_.contentLibraryItemName -match "Operations-Cloud-Proxy-$vropsVersion" }).contentLibraryItemId
                                                        } else {
                                                            Write-Error "Unable to find vSphere Content Library ($contentLibrary) or Content Library Item in VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"
                                                            Break
                                                        }
                                                    }
                                                    $productPropertiesObject = @()
                                                    $productPropertiesObject += [pscustomobject]@{
                                                        'certificate'                  = ("locker:certificate:" + $($vropsCertificate.vmid) + ":" + $($vropsCertificate.alias))
                                                        'productPassword'              = ("locker:password:" + $($vropsPassword.vmid) + ":" + $($vropsPassword.alias))
                                                        'licenseRef'                   = ("locker:license:" + $($vropsLicense.vmid) + ":" + $($vropsLicense.alias))
                                                        'disableTls'                   = "TLSv1,TLSv1.1"
                                                        'fipsMode'                     = "false"
                                                        'timeSyncMode'                 = "ntp"
                                                        'masterVidmEnabled'            = $true
                                                        'ntp'                          = $jsonInput.ntp
                                                        'affinityRule'                 = $false
                                                        'configureAffinitySeparateAll' = "true"
                                                        'contentLibraryItemId'         = $contentLibraryItemId
                                                        'contentLibraryItemId:proxy'   = $contentLibraryProxyItemId
                                                        'deployOption'                 = $jsonInput.deployOption
                                                        'isCaEnabled'                  = "false"
                                                    }

                                                    #### Generate VMware Aria Operations Cluster Details
                                                    $clusterVipProperties = @()
                                                    $clusterVipProperties += [pscustomobject]@{
                                                        'controllerType' = "NSX_T"
                                                        'hostName'       = $jsonInput.clusterFqdn
                                                    }
                                                    $clusterVipsObject = @()
                                                    $clusterVipsObject += [pscustomobject]@{
                                                        'type'          = "vrops-cluster"
                                                        'properties'    = ($clusterVipProperties | Select-Object -Skip 0)
                                                    }
                                                    $clusterObject = @()
                                                    $clusterObject += [pscustomobject]@{
                                                        'clusterVips'    = $clusterVipsObject
                                                    }

                                                    #### Generate VMware Aria Operations Node Details
                                                    $masterProperties = New-Object -TypeName psobject
                                                    $masterProperties | Add-Member -notepropertyname 'vmName' -notepropertyvalue $jsonInput.vmNameNodeA
                                                    $masterProperties | Add-Member -notepropertyname 'hostName' -notepropertyvalue $jsonInput.hostNameNodeA
                                                    $masterProperties | Add-Member -notepropertyname 'ip' -notepropertyvalue $jsonInput.ipNodeA
                                                    $masterProperties | Add-Member -notepropertyname 'gateway' -notepropertyvalue $jsonInput.gateway
                                                    $masterProperties | Add-Member -notepropertyname 'domain' -notepropertyvalue $jsonInput.domain
                                                    $masterProperties | Add-Member -notepropertyname 'searchpath' -notepropertyvalue $jsonInput.searchPath
                                                    $masterProperties | Add-Member -notepropertyname 'dns' -notepropertyvalue $jsonInput.dns
                                                    $masterProperties | Add-Member -notepropertyname 'netmask' -notepropertyvalue $jsonInput.netmask
                                                    $masterProperties | Add-Member -notepropertyname 'timeZone' -notepropertyvalue "UTC"
                                                    $masterProperties | Add-Member -notepropertyname 'vCenterHost' -notepropertyvalue $jsonInput.vcenterFqdn
                                                    $masterProperties | Add-Member -notepropertyname 'cluster' -notepropertyvalue ($jsonInput.vcenterDatacenter + "#" + $jsonInput.vcenterCluster)
                                                    $masterProperties | Add-Member -notepropertyname 'network' -notepropertyvalue $jsonInput.network
                                                    $masterProperties | Add-Member -notepropertyname 'storage' -notepropertyvalue $jsonInput.vcenterDatastore
                                                    $masterProperties | Add-Member -notepropertyname 'diskMode' -notepropertyvalue "thin"
                                                    $masterProperties | Add-Member -notepropertyname 'vCenterName' -notepropertyvalue ($jsonInput.vcenterFqdn).Split(".")[0]
                                                    $masterProperties | Add-Member -notepropertyname 'vcUsername' -notepropertyvalue $vcCredentials.userName
                                                    $masterProperties | Add-Member -notepropertyname 'vcPassword' -notepropertyvalue ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                    $masterProperties | Add-Member -notepropertyname 'ntp' -notepropertyvalue $jsonInput.ntp
                                                    if ($vcfVersion -eq "4.4.0") {
                                                        $masterProperties | Add-Member -notepropertyname 'extendedStorage' -notepropertyvalue $jsonInput.vcenterDatastore
                                                    }
                                                    $replicaProperties = @()
                                                    $replicaProperties += [pscustomobject]@{
                                                        'vmName'   = $jsonInput.vmNameNodeB
                                                        'hostName' = $jsonInput.hostNameNodeB
                                                        'ip'       = $jsonInput.ipNodeB
                                                    }
                                                    $dataProperties = @()
                                                    $dataProperties += [pscustomobject]@{
                                                        'vmName'   = $jsonInput.vmNameNodeC
                                                        'hostName' = $jsonInput.hostNameNodeC
                                                        'ip'       = $jsonInput.ipNodeC
                                                    }
                                                    if ($vcfVersion -ge "4.5.1") {
                                                        $deployOption = "smallcp"
                                                        $type = "cloudproxy"
                                                    } else {
                                                        $deployOption = "smallrc"
                                                        $type = "remotecollector"
                                                    }
                                                    $remoteCollector1Properties = @()
                                                    $remoteCollector1Properties += [pscustomobject]@{
                                                        'vmName'        = $jsonInput.vmNameProxyA
                                                        'hostName'        = $jsonInput.hostNameProxyA
                                                        'ip'            = $jsonInput.ipProxyA
                                                        'deployOption'  = $deployOption
                                                        'gateway'       = $jsonInput.gatewayProxies
                                                        'domain'        = $jsonInput.domainProxies
                                                        'searchpath'    = $jsonInput.domainProxies
                                                        'dns'           = $jsonInput.dns
                                                        'netmask'       = $jsonInput.netmaskProxies
                                                        'timeZone'      = "UTC"
                                                        'vCenterHost'   = $jsonInput.vcenterFqdn
                                                        'cluster'       = ($jsonInput.vcenterDatacenter + "#" + $jsonInput.vcenterCluster)
                                                        'network'       = $jsonInput.networkProxies
                                                        'storage'       = $jsonInput.vcenterDatastore
                                                        'diskMode'      = "thin"
                                                        'vCenterName'   = ($jsonInput.vcenterFqdn).Split(".")[0]
                                                        'vcUsername'    = $vcCredentials.userName
                                                        'vcPassword'    = ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                        'ntp'           = $jsonInput.ntp
                                                    }
                                                    $remoteCollector2Properties = @()
                                                    $remoteCollector2Properties += [pscustomobject]@{
                                                        'vmName'        = $jsonInput.vmNameProxyB
                                                        'hostName'        = $jsonInput.hostNameProxyB
                                                        'ip'            = $jsonInput.ipProxyB
                                                        'deployOption'  = $deployOption
                                                        'gateway'       = $jsonInput.gatewayProxies
                                                        'domain'        = $jsonInput.domainProxies
                                                        'searchpath'    = $jsonInput.searchPathProxies
                                                        'dns'           = $jsonInput.dns
                                                        'netmask'       = $jsonInput.netmaskProxies
                                                        'timeZone'      = "UTC"
                                                        'vCenterHost'   = $jsonInput.vcenterFqdn
                                                        'cluster'       = ($jsonInput.vcenterDatacenter + "#" + $jsonInput.vcenterCluster)
                                                        'network'       = $jsonInput.networkProxies
                                                        'storage'       = $jsonInput.vcenterDatastore
                                                        'diskMode'      = "thin"
                                                        'vCenterName'   = ($jsonInput.vcenterFqdn).Split(".")[0]
                                                        'vcUsername'    = $vcCredentials.userName
                                                        'vcPassword'    = ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                        'ntp'           = $jsonInput.ntp
                                                    }
                                                    $nodesObject = @()
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'       = "master"
                                                        'properties'    = ($masterProperties | Select-Object -Skip 0)
                                                    }
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'       = "replica"
                                                        'properties'    = ($replicaProperties | Select-Object -Skip 0)
                                                    }
                                                    if (!$PsBoundParameters.ContainsKey("nested")) {
                                                        $nodesobject += [pscustomobject]@{
                                                            'type'       = "data"
                                                            'properties'    = ($dataProperties | Select-Object -Skip 0)
                                                        }
                                                    }

                                                    $nodesobject += [pscustomobject]@{
                                                        'type'       = $type
                                                        'properties'    = ($remoteCollector1Properties | Select-Object -Skip 0)
                                                    }
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'       = $type
                                                        'properties'    = ($remoteCollector2Properties | Select-Object -Skip 0)
                                                    }

                                                    #### Generate the VMware Aria Operations Properties Section
                                                    $productsObject = @()
                                                    $productsObject += [pscustomobject]@{
                                                        'id'         = "vrops"
                                                        'version'    = $vropsVersion
                                                        'properties' = ($productPropertiesObject  | Select-Object -Skip 0)
                                                        'clusterVIP' = ($clusterObject  | Select-Object -Skip 0)
                                                        'nodes'      = $nodesObject    
                                                    }
                                                    if (!($xintEnvironment)) { 
                                                        $vropsDeploymentObject = @()
                                                        $vropsDeploymentObject += [pscustomobject]@{
                                                            'environmentName' = $jsonInput.environmentName
                                                            'infrastructure'  = ($infrastructureObject  | Select-Object -Skip 0)
                                                            'products'        = $productsObject     
                                                        }
                                                    } else {
                                                        $vropsDeploymentObject = @()
                                                        $vropsDeploymentObject += [pscustomobject]@{
                                                            'environmentId'   = $xintEnvironment.environmentId
                                                            'environmentName' = $jsonInput.environmentName
                                                            'infrastructure'  = ($infrastructureObject  | Select-Object -Skip 0)
                                                            'products'        = $productsObject     
                                                        }
                                                    }

                                                    $vropsDeploymentObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonSpecFileName 
                                                    Write-Output "Creation of Deployment JSON Specification file for VMware Aria Operations: SUCCESSFUL"                            
                                                } else {
                                                    Write-Error "Datacenter Provided in the JSON Specification ($($jsonInput.datacenter)) does not exist: PRE_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Error "Root Password with alias ($($jsonInput.rootPasswordAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Admin Password with alias ($($jsonInput.xintPasswordAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Certificate with alias ($($jsonInput.certificateAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "License with alias ($($jsonInput.licenseKey)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }    
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-vROPsJsonSpec

Function New-vROPSDeployment {
    <#
        .SYNOPSIS
        Deploy Aria Operations to VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vROPSDeployment cmdlet deploys VMware Aria Operations via VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Suite Lifecycle has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment does not already exist in VMware Aria Suite Lifecycle
        - Requests a new deployment of VMware Aria Operations via VMware Aria Suite Lifecycle

        .EXAMPLE
        New-vROPSDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\iomDeploySpec.json
        This example starts a deployment of VMware Aria Operations via VMware Aria Suite Lifecycle using using data from the JSON Specification for Intelligent Operations Management

        .EXAMPLE
        New-vROPSDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\iomDeploySpec.jsono -nested
        This example starts a reduce footprint deployment of VMware Aria Operations via VMware Aria Suite Lifecycle using data from the JSON Specification for Intelligent Operations Management

        .EXAMPLE
        New-vROPSDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\iomDeploySpec.json -customVersion 8.10.0
        This example starts a deployment using a custom version of VMware Aria Operations via VMware Aria Suite Lifecycle using data from the JSON Specification for Intelligent Operations Management

        .EXAMPLE
        New-vROPSDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\iomDeploySpec.json -useContentLibrary -contentLibrary Operations
        This example starts a deployment of VMware Aria Operations via VMware Aria Suite Lifecycle using data from the JSON Specification for Intelligent Operations Management and a vSphere Content Library for OVA installs.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER jsonFile
        The JSON (.json) file for Intelligent Operations Management.

        .PARAMETER monitor
        Specifies to monitor the deployment request in VMware Aria Suite Lifecycle.

        .PARAMETER nested
        Specifies to use the reduced footprint JSON specification file for deploying VMware Aria Operations.

        .PARAMETER customVersion
        The custom version to use for deploying VMware Aria Operations.

        .PARAMETER useContentLibrary
        Specifies to use a vSphere Content Library for deploying VMware Aria Operations.

        .PARAMETER contentLibrary
        The vSphere Content Library to use for deploying VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$nested,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                        if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $commandSwitch = ""
                                if ($PsBoundParameters.ContainsKey("customVersion")) {
                                    $commandSwitch = $commandSwitch + " -customVersion $customVersion"
                                }
                                if ($PsBoundParameters.ContainsKey("nested")) {
                                    $commandSwitch = $commandSwitch + " -nested"
                                }
                                if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                    $commandSwitch = $commandSwitch + " -useContentLibrary -contentLibrary $contentLibrary"
                                }
                                $outputPath = ($outputPath = Split-Path $jsonFile -Parent) + "\"
                                Invoke-Expression "Export-vROPSJsonSpec -jsonFile $jsonFile -outputPath $outputPath $($commandSwitch) | Out-Null"
                                $json = (Get-Content -Raw ($outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "operationsDeploySpec.json")))
                                $jsonSpec = $json | ConvertFrom-Json
                                if (!(((Get-vRSLCMLoadbalancer -type NSX_T) | Where-Object {$_.loadBalancerDetails -match $jsonInput.clusterFqdn}))) {
                                    New-vRSLCMLoadbalancer -type NSX_T -loadBalancerIp $jsonInput.clusterIp -loadBalancerFqdn $jsonInput.clusterFqdn | Out-Null
                                }
                                if (!((Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $jsonSpec.environmentName}).products.id -contains $jsonSpec.products.id)) {
                                    if (Get-vRSLCMLockerPassword -alias $($jsonSpec.products.properties.productPassword.Split(":")[3])) {
                                        if (Get-vRSLCMLockerCertificate | Where-Object {$_.alias -Match $($jsonSpec.products.properties.certificate.Split(":")[3])}) {
                                            if (Get-vRSLCMLockerLicense | Where-Object {$_.alias -eq $($jsonSpec.products.properties.licenseRef.Split(":")[3])}) {
                                                if ($jsonSpec.environmentId) {
                                                    $newRequest = Add-vRSLCMEnvironment -json $json -environmentId $jsonSpec.environmentId -addProduct -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
                                                } else {
                                                    $newRequest = Add-vRSLCMEnvironment -json $json -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
                                                }
                                                if ($newRequest) {
                                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                                        Start-Sleep 10
                                                        Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                                    } else {
                                                        Write-Output "Deployment Request for VMware Aria Operations Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                                    }
                                                } else {
                                                    Write-Error "Request to deploy VMware Aria Operations failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Error "License in VMware Aria Suite Lifecycle ($($vrvcfVrslcmDetailsslcm.fqdn)) Locker with alias ($($jsonSpec.products.properties.licenseRef.Split(":")[3])), does not exist: PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Certificate in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.certificate.Split(":")[3])), does not exist: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Password in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.productPassword.Split(":")[3])), does not exist: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "VMware Aria Operations in environment ($($jsonSpec.environmentName)) on VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already exists: SKIPPED"
                                }
                            }
                        }
                    } 
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-vROPSDeployment

Function Undo-vROPSDeployment {
    <#
        .SYNOPSIS
        Remove the VMware Aria Operations from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-vROPSDeployment cmdlet removes VMware Aria Operations from VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment exist in VMware Aria Suite Lifecycle
        - Requests a the deletion of VMware Aria Operations from VMware Aria Suite Lifecycle

        .EXAMPLE
        Undo-vROPSDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName xint-env
        This example starts a removal of VMware Aria Operations from VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER environmentName
        The VMware Aria Operations Environment Name.

        .PARAMETER monitor
        Monitor the VMware Aria Suite Lifecycle request.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName -and $_.products.id -eq 'vrops'}) {
                                $newRequest = Remove-vRSLCMEnvironment -environmentId (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName}).environmentId -productId vrops
                                if ($newRequest) {
                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                        Start-Sleep 10
                                        $status = Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                        if (!(Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName -and $_.products.id -eq 'vrops'})) {
                                            if ($status -match "COMPLETED") {
                                                Write-Output "Removal of VMware Aria Operations from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removal of VMware Aria Operations from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Removal of VMware Aria Operations from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Output "Removal request of VMware Aria Operations Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                    }
                                } else {
                                    Write-Error "Removal request of VMware Aria Operations failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Environment with name ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already removed: SKIPPED"
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vROPSDeployment

Function Import-vROPSUserAccount {
    <#
        .SYNOPSIS
        Import a user from Workspace ONE Access and assign access in VMware Aria Operations.

        .DESCRIPTION
        The Import-vROPSUserAccount cmdlet imports a user from Workspace ONE Access and assigns access in VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that Workspace ONE Access has been configured as an authentication source
        - Validates the user account provided can be found in VMware Aria Operations
        - Validated the role exists within VMware Aria Operations
        - Imports the user and assigns the VMware Aria Operations role

        .EXAMPLE
        Import-vROPSUserAccount -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -userName nigel.mccloud -role Administrator
        This example imports a user into VMware Aria Operations and assigns the role.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The domain of the user to import.

        .PARAMETER userName
        The username of the user to import.

        .PARAMETER role
        The role to assign to the user.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (!(Get-vROPSUserAccount -username $userName)) {
                                if (Get-vROPSAuthSource | Where-Object {$_.name -eq "vIDMAuthSource"}) {
                                    if ($userAccount = Search-vROPSUserAccount -sourceId (Get-vROPSAuthSource | Where-Object {$_.name -eq "vIDMAuthSource"}).id -domain $domain -userName ($userName + '@' + $domain)) {
                                        if (Get-vROPSAuthRole -name $role -ErrorAction SilentlyContinue) {
                                            Add-vROPSUserAccount -sourceId (Get-vROPSAuthSource | Where-Object {$_.name -eq "vIDMAuthSource"}).id -userName $userAccount.name -lastName $userAccount.lastName -firstName $userAccount.firstName -distinguishedName $domain -role $role | Out-Null
                                            if (Get-vROPSUserAccount -username $userName) {
                                                Write-Output "Importing user account into VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($userName + '@' + $domain)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Importing user account into VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($userName + '@' + $domain)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Unable to locate role in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($role): PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to locate user account in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($userName): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to locate Authentication Source in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) type (vIDMAuthSource): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Importing user account into VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($userName + '@' + $domain)), already performed: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Import-vROPSUserAccount

Function Import-vROPSUserGroup {
    <#
        .SYNOPSIS
        Import a Group from Workspace ONE Access and assign access in VMware Aria Operations.

        .DESCRIPTION
        The Import-vROPSUserGroup cmdlet imports a Group from Workspace ONE Access and assigns access in VMware Aria
        Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that Workspace ONE Access has been configured as an authentication source
        - Validates the user group provided can be found in VMware Aria Operations
        - Validated the role exists within VMware Aria Operations
        - Imports the group and assigns the VMware Aria Operations role

        .EXAMPLE
        Import-vROPSUserGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -groupName gg-vrops-admins -role Administrator
        This example imports a group into VMware Aria Operations and assigns the role.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The domain of the group to import.

        .PARAMETER groupName
        The group name of the group to import.

        .PARAMETER role
        The role to assign to the group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (!(Get-vROPSUserGroup -name ($groupName + '@' + $domain))) {
                                if (Get-vROPSAuthSource | Where-Object {$_.name -eq "vIDMAuthSource"}) {
                                    if (Search-vROPSUserGroup -sourceId (Get-vROPSAuthSource | Where-Object {$_.name -eq "vIDMAuthSource"}).id -domain $domain -groupName ($groupName + '@' + $domain)) {
                                        if (Get-vROPSAuthRole -name $role -ErrorAction SilentlyContinue) {
                                            Add-vROPSUserGroup -sourceId (Get-vROPSAuthSource | Where-Object {$_.name -eq "vIDMAuthSource"}).id -userGroup ($groupName + '@' + $domain) -role $role | Out-Null
                                            if (Get-vROPSUserGroup -name ($groupName + '@' + $domain)) {
                                                Write-Output "Importing User Group into VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($groupName + '@' + $domain)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Importing User Group into VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($groupName + '@' + $domain)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Unable to locate Role in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($role): PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to locate User Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($groupName): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to locate Authentication Source in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) type (vIDMAuthSource): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Importing User Group into VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($groupName + '@' + $domain)), already performed: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Import-vROPSUserGroup

Function Register-vROPSWorkloadDomain {
    <#
        .SYNOPSIS
        Connect a Workload Domain to VMware Aria Operations.

        .DESCRIPTION
        The Register-vROPSWorkloadDomain cmdlet connects a Workload Domain to VMware Aria Operations. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates if the Workload Domain is already connected to VMware Aria Operations
        - Enables/Disables connecting the Workload Domain to VMware Aria Operations

        .EXAMPLE
        Register-vROPSWorkloadDomain -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -status ENABLED
        This example ENABLES the Workload Domain in VMware Aria Operations

        .EXAMPLE
        Register-vROPSWorkloadDomain -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -status DISABLED
        This example DISABLES the Workload Domain in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The Workload Domain to connect to VMware Aria Operations.

        .PARAMETER status
        The status of the Workload Domain in VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateSet("ENABLED", "DISABLED")] [String]$status
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                        if ((Get-VCFvROPSConnection | Where-Object {$_.domainId -eq (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id}).status -ne $status) { 
                            Set-VCFvROPSConnection -domainId (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id -status $status | Out-Null
                            Start-Sleep 10
                            Do {
                                $configStatus = (Get-VCFvROPSConnection | Where-Object {$_.domainId -eq (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id}).status
                            } Until ($configStatus -ne "IN_PROGRESS")
                            if ((Get-VCFvROPSConnection | Where-Object {$_.domainId -eq (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).id}).status -eq $status) { 
                                Write-Output "Enabling Workload Domain Intergation with VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) for domain ($domain): SUCCESSFUL"
                            } else {
                                Write-Error "Enabling Workload Domain Intergation with VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) for domain ($domain): POST_VALIDATION_FAILED"
                            }
                        } else {
                            Write-Warning "Enabling Workload Domain Intergation with VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) for domain ($domain), already enabled: SKIPPED"
                        }
                    } else {
                        Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Register-vROPSWorkloadDomain

Function Add-vROPSGroupRemoteCollectors {
    <#
        .SYNOPSIS
        Creates a Collector group and assigns nodes in VMwre Aria Operations.

        .DESCRIPTION
        The Add-vROPSGroupRemoteCollectors cmdlet creates a collector group in VMware Aria Operations and
        assigns the remote collector nodes. The cmdlet connects to SDDC Manager using the -server, -user, and
        -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to Aria Operations
        - Gathers the collector node details
        - Creates a new collector group in VMware Aria Operations
        - Assigns the deployed collectors to the collector group in VMware Aria Operations

        .EXAMPLE
        Add-vROPSGroupRemoteCollectors -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -collectorGroupName "sfo-remote-collectors"
        This example creates a Collector group called 'sfo-remote-collectors' and assigns the Remove Collector Nodes in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER collectorGroupName
        The name of the Collector Group to create in VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (!(Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName})) {
                                $collectors = (Get-vROPSCollector | Where-Object {$_.type -eq "REMOTE" -or $_.type -eq "CLOUD_PROXY"} | Select-Object id).id
                                $collectorIds = $collectors -join ","
                                Add-vROPSCollectorGroup -name $collectorGroupName -collectorIds $collectorIds
                                if (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}) {
                                    Write-Output "Creating Collector Group in ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName): SUCCESSFUL"
                                } else {
                                    Write-Error "Creating Collector Group in ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Creating Collector Group in ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSGroupRemoteCollectors

Function Update-vROPSAdapterVcenter {
    <#
        .SYNOPSIS
        Updates the assigned collector group for vCenter Adapter.

        .DESCRIPTION
        The Update-vROPSAdapterVcenter cmdlet updates the assigned collector group for all vCenter Adapters in
        VMware Aria Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the collector group exits in VMware Aria Operations
        - Gathers the unique ID of the collector group
        - Gathers the vCenter Adapter details from VMware Aria Operations
        - Updates the assigned collector group for the vCenter Adapter in VMware Aria Operations

        .EXAMPLE
        Update-vROPSAdapterVcenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -collectorGroupName "sfo-remote-collectors"
        This example updates all vCenter Adapters to use the collector group named 'sfo-remote-collectors'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER collectorGroupName
        The name of the Collector Group to assign to the vCenter Adapter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if ($collectorGroupId = (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id) {
                                $adapters = Get-vROPSAdapter | Where-Object {$_.resourceKey.adapterKindKey -eq "VMWARE"}
                                Foreach ($adapter in $adapters) {
                                    $vcurl = ((Get-vROPSAdapter -id $adapter.id).resourceKey.resourceIdentifiers | Where-Object {$_.identifierType.name -eq "VCURL"}).value
                                    $json = '{
                                    "resourceKey" : {
                                    "name" : "'
+ $($adapter.resourceKey.name) +'",
                                    "adapterKindKey" : "VMWARE",
                                    "resourceKindKey" : "VMwareAdapter Instance",
                                    "resourceIdentifiers" : [ {
                                        "identifierType" : {
                                        "name" : "AUTODISCOVERY",
                                        "dataType" : "STRING",
                                        "isPartOfUniqueness" : true
                                        },
                                        "value" : "true"
                                    }, {
                                        "identifierType" : {
                                        "name" : "PROCESSCHANGEEVENTS",
                                        "dataType" : "STRING",
                                        "isPartOfUniqueness" : true
                                        },
                                        "value" : "true"
                                    }, {
                                        "identifierType" : {
                                        "name" : "VCURL",
                                        "dataType" : "STRING",
                                        "isPartOfUniqueness" : true
                                        },
                                        "value" : "'
+ $vcurl +'"
                                    } ]
                                    },
                                    "description" : "'
+ $($adapter.description) +'",
                                    "id" : "'
+ $($adapter.id) +'",
                                    "collectorGroupId": "'
+ $($collectorGroupId) +'"
                                    }'


                                    $json | Out-File .\updateAdapter.json
                                    if (!($($adapter.collectorGroupId) -eq $collectorGroupId)) {
                                        Set-vROPSAdapter -json .\updateAdapter.json | Out-Null
                                        Write-Output "Assiging vCenter Adapter ($($adapter.resourceKey.name)) to Collector Group ($collectorGroupName): SUCCESSFUL"
                                    } else {
                                        Write-Warning "Assiging vCenter Adapter ($($adapter.resourceKey.name)) to Collector Group ($collectorGroupName), already assigned: SKIPPED"
                                    }
                                    Remove-Item .\updateAdapter.json -Force -Confirm:$false
                                }
                            } else {
                                Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vROPSAdapterVcenter

Function Update-vROPSAdapterCollecterGroup {
    <#
        .SYNOPSIS
        Updates the assigned Collector Group for the specified Adapter type.

        .DESCRIPTION
        The Update-vROPSAdapterCollecterGroup cmdlet updates the assigned Collector group for all Adapters in
        VMware Aria Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates the collector Group exits in VMware Aria Operations
        - Gathers the unique ID of the collector group
        - Gathers the given Adapter details from VMware Aria Operations
        - Updates the assigned Collector group for the Adapter in VMware Aria Operations
        
        .EXAMPLE
        Update-vROPSAdapterCollecterGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -collectorGroupName "sfo-remote-collectors" -adaptertype "LogInsightAdapter"
        This example updates VMware Aria Operations for LogsAdapter to use the collector group named 'sfo-remote-collectors'
        
        .EXAMPLE
        Update-vROPSAdapterCollecterGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -collectorGroupName "sfo-remote-collectors" -adaptertype "VMWARE"
        This example updates all vCenter Adapters to use the collector group named 'sfo-remote-collectors'
        
        .EXAMPLE
        Update-vROPSAdapterCollecterGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -collectorGroupName "sfo-remote-collectors" -adaptertype "IdentityManagerAdapter" -adaptername "sfo-wsa01"
        This example updates Identity Manager Adapter with name "sfo-wsa01" to use the collector group named 'sfo-remote-collectors'

        .EXAMPLE
        Update-vROPSAdapterCollecterGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -adaptertype "IdentityManagerAdapter" -adaptername "vRSLCM_VCF_Workspace ONE Access Adapter"
        This example updates Identity Manager Adapter with name "vRSLCM_VCF_Workspace ONE Access Adapter" to use the default Collector group named "Default collector group".

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER collectorGroupName
        The name of the Collector Group to assign to the Adapter.

        .PARAMETER adapterType
        The type of Adapter to update.

        .PARAMETER adapterName
        The name of the Adapter to update.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName="Default collector group",
        [Parameter (Mandatory = $true)] [ValidateSet("VMWARE","LogInsightAdapter","IdentityManagerAdapter","NSXTAdapter","PingAdapter","CASAdapter")] [String]$adapterType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$adapterName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if ($collectorGroupId = (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id) {
                                $adapters = Get-vROPSAdapter | Where-Object {$_.resourceKey.adapterKindKey -eq $adapterType}
                                if ($adapterName) {
                                    if ($adapters | Where-Object {$_.resourceKey.name -eq $adapterName}) {
                                        $adapters = $adapters | Where-Object {$_.resourceKey.name -eq $adapterName}
                                    } else {
                                        Write-Error "Adapter with name $adapterName not found"
                                        Break
                                    }
                                }
                                Foreach ($adapter in $adapters) {
                                    $json =  $adapter
                                    if (!($($json.collectorGroupId) -eq $collectorGroupId)) {
                                        $json.collectorGroupId=$collectorGroupId
                                        #Remove collectorId as the request body can accept a collectorId or a collectorGroupId, but not both.
                                        $json.PSObject.Properties.Remove('collectorId')
                                        $json  | ConvertTo-Json -Depth 4 | Out-File .\updateAdapter.json                                                
                                        Set-vROPSAdapter -json .\updateAdapter.json | Out-Null
                                        Write-Output "Assigning Collector Group ($collectorGroupName) to instance ($($adapter.resourceKey.name)): SUCCESSFUL"
                                        Remove-Item .\updateAdapter.json -Force -Confirm:$false
                                    } else {
                                        Write-Warning "Assigning Collector Group ($collectorGroupName) to instance ($($adapter.resourceKey.name)) already assigned: SKIPPED"
                                    }
                                }
                            } else {
                                Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vROPSAdapterCollecterGroup

Function Remove-OperationsDefaultAdapter {
    <#
        .SYNOPSIS
        Removes the default vCenter Server and vSAN Adapters from VMware Aria Operations.

        .DESCRIPTION
        The Remove-OperationsDefaultAdapter cmdlet removes the default vCenter Server and vSAN adapters and associated
        credentials from VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Deletes the adapters and credentials from VMware Aria Operations

        .EXAMPLE
        Remove-OperationsDefaultAdapter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example deletes the default adapter and credentials from VMware Aria Operations

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if ($vcenterAdapter = (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -match "VCF_VC"})) {
                                Undo-vROPSAdapter -server $server -user $user -pass $pass -adapterName $vcenterAdapter.resourceKey.name -adapterType VMWARE
                                $vcenterCredential = (Get-vROPSCredential -credentialId $vcenterAdapter.credentialInstanceId).name
                                Undo-vROPSCredential -server $server -user $user -pass $pass -credentialName $vcenterCredential -credentialType VMWARE
                                $alreadyRemoved = $false
                            } else {
                                $alreadyRemoved = $true
                            }
                            if ($vsanAdapter = (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -match "VCF_vSAN"})) {
                                Undo-vROPSAdapter -server $server -user $user -pass $pass -adapterName $vsanAdapter.resourceKey.name -adapterType VirtualAndPhysicalSANAdapter
                                $vsanCredential = (Get-vROPSCredential -credentialId $vsanAdapter.credentialInstanceId).name
                                Undo-vROPSCredential -server $server -user $user -pass $pass -credentialName $vsanCredential -credentialType VirtualAndPhysicalSANAdapter
                                $alreadyRemoved = $false
                            } else {
                                $alreadyRemoved = $true
                            }
                            if ($alreadyRemoved) {
                                Write-Warning "Removing Default vCenter Server/vSAN Adapter and Credentials from VMware Aria Operations, does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Remove-OperationsDefaultAdapter

Function Add-vROPSCurrency {
    <#
        .SYNOPSIS
        Configures the currency in VMware Aria Operations.

        .DESCRIPTION
        The Add-vROPSCurrency cmdlet configures the currency in VMware Aria Operations. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates if a currency value has been configured
        - Configures the currency value based on the value provided

        .EXAMPLE
        Add-vROPSCurrency -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -currency USD
        This example configures the currency to USD in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER currency
        The currency to configure in VMware Aria Operations.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$currency
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (-not (($currentCurrency = Get-vROPSCurrency | Select-Object code)).code) {
                                Set-vROPSCurrency -currency $currency | Out-Null
                                if (((Get-vROPSCurrency | Select-Object code)).code -eq $currency) {
                                    Write-Output "Configuring currency in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) to ($currency): SUCCESSFUL"
                                } else {
                                    Write-Error "Configuring currency in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) to ($currency): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Configuring currency in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) to ($currency), ($($currentCurrency.code)) already set: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSCurrency

Function Enable-vROPSManagementPack {
    <#
        .SYNOPSIS
        Install a Management Pack in VMware Aria Operations.

        .DESCRIPTION
        The Enable-vROPSManagementPack cmdlet uploads and installs a management pack in VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates the path to the Management Pack (.pak) file
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates the Management Pack does not exist in VMware Aria Operations
        - Uploads the Management Pack file to VMware Aria Operations
        - Installs the Management Pack to VMware Aria Operations

        .EXAMPLE
        Enable-vROPSManagementPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -packType "SDDC Health" -pakfile .\management.pak
        This example installs the SDDC Health Management Pack in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER packType
        The Management Pack type to install.

        .PARAMETER pakFile
        The path to the Management Pack (.pak) file to install.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateSet("SDDC Health","SrmAdapter","VrAdapter")] [ValidateNotNullOrEmpty()] [String]$packType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pakFile
    )

    if (!$pakFile) {
        $pakFile = Get-ExternalFileName -title "Select the Management Pack file (.pak)" -fileType "pak" -location "default"
    } else {
        if (!(Test-Path -Path $pakFile)) {
            Write-Error "Management Pack file (pak) '$pakFile' File Not Found"
            Break
        }
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (!(Get-vROPSSolution | Where-Object {$_.id -eq $packType})) {
                                $uploadPak = Import-vROPSManagementPack -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass -pak $pakFile
                                if ($uploadPak) {
                                    $pakId = ($uploadPak | ConvertFrom-JSon).pak_id
                                    $installPak = Install-vROPSManagementPack -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass -pakId $pakId
                                    Do {
                                        $status = Get-vROPSManagementPackStatus -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass -pakId $pakId
                                    } Until ( $status.cluster_pak_install_status -ne "CANDIDATE" )
                                    if ($status.cluster_pak_install_status -eq "COMPLETED") {
                                        Write-Output "Installing '$pakFile' Management Pack to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Installing '$pakFile' Management Pack to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Uploading '$pakFile' Management Pack to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Installing '$pakFile' Management Pack to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Enable-vROPSManagementPack

Function Register-vROPSManagementPack {
    <#
        .SYNOPSIS
        Enable / Disable a Management Pack.

        .DESCRIPTION
        The Register-vROPSManagementPack cmdlet activates or deactivates a management pack in VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates if the Management Pack is activated or deactivated in VMware Aria Operations
        - Activates or deactivates the Management Pack

        .EXAMPLE
        Register-vROPSManagementPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -state enable -packType Ping
        This example activates the Ping management pack in VMware Aria Operations

        .EXAMPLE
        Register-vROPSManagementPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -state disable -packType Ping
        This example deactivates the Ping management pack in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER state
        The state of the Management Pack to activate or deactivate.

        .PARAMETER packType
        The Management Pack type to activate or deactivate.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateSet("enable","disable")] [ValidateNotNullOrEmpty()] [String]$state,
        [Parameter (Mandatory = $true)] [ValidateSet("Ping","PCI","ISO","FISMA","HIPAA","CIS","DISA","VCF","VMwareInfrastructureHealth")] [ValidateNotNullOrEmpty()] [String]$packType
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            # Connect to VMware Aria Operations and extract the Management Pack Details
                            $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $($vcfVropsDetails.adminUser), $($vcfVropsDetails.adminPass)))) # Create Basic Authentication Encoded Credentials
                            $vropsBasicHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
                            $vropsBasicHeaders.Add("Authorization", "Basic $base64AuthInfo")
                            $vropsBasicHeaders.Add("Content-Type", "application/json")
                            $uri = ((Get-vROPSManagementPack -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass | Where-Object {$_.links -match $packType}).links | Where-Object {$_.rel -eq "pak_information"}).href
                            $adapterDetails = Invoke-RestMethod -Method GET -Uri $uri -Headers $vropsBasicHeaders
                            $uri = ((Get-vROPSManagementPack -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass | Where-Object {$_.links -match $packType}).links | Where-Object {$_.rel -eq "pak_cluster_status"}).href
                            if ($state -eq "enable") {
                                if (!(Get-vROPSSolution | Where-Object {$_.id -match $packType})) {
                                    Set-vROPSManagementPack -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass -pakId ((($adapterDetails.pak_id) -Split ("-"))[0]) -version $adapterDetails.version -status enable | Out-Null
                                    Do {
                                        $status = Invoke-RestMethod -Method GET -Uri $uri -Headers $vropsBasicHeaders
                                    } Until ( $status.cluster_pak_install_status -ne "CANDIDATE" )
                                    if ($status.cluster_pak_install_status -eq "COMPLETED") {
                                        Write-Output "Activating ($packType) Management Pack on VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Activating ($packType) Management Pack on VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Activating ($packType) Management Pack on VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), already exists: SKIPPED"
                                }
                            } elseif ($state -eq "disable") {
                                if (Get-vROPSSolution | Where-Object {$_.id -match $packType}) {
                                    Set-vROPSManagementPack -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass -pakId ((($adapterDetails.pak_id) -Split ("-"))[0]) -version $adapterDetails.version -status disable | Out-Null
                                    Do {
                                        $status = Get-vROPSManagementPackActivity -server $vcfVropsDetails.loadBalancerFqdn -username $vcfVropsDetails.adminUser -password $vcfVropsDetails.adminPass
                                    } Until ( $($status.current_pak_activity.pak_id) -ne $adapterDetails.pak_id )
                                    if (!(Get-vROPSSolution | Where-Object {$_.id -match $packType})) {
                                        Write-Output "Deactivating ($packType) Management Pack on VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Deactivating ($packType) Management Pack on VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Deactivating ($packType) Management Pack on VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), already exists: SKIPPED"
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Register-vROPSManagementPack

Function Add-vROPSAdapterNsxt {
    <#
        .SYNOPSIS
        Adds an NSX Adapter to VMware Aria Operations.

        .DESCRIPTION
        The Add-vROPSAdapterNsxt cmdlet adds an NSX Adapter for a Workload Domains NSX Manager cluster to VMware Aria
        Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Workload Domain is valid and then obtains the NSX Manager cluster details
        - Validates that the collector group exits in VMware Aria Operations
        - Validates that the NSX Adapter and Credentials do not already exist in VMware Aria Operations
        - Validates that the credentials do not already exist in VMware Aria Operations
        - Creates a new NSX Adapter for the Workload Domain using credentials from SDDC Manager inventory in VMware Aria Operations
        - Starts the collection of the NSX Adapter in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapterNsxt -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -collectorGroupName "sfo-remote-collectors"
        This example creates an NSX Adapter for the Management Workload Domain named in VMware Aria Operations and assigns to the collector group defined

        .EXAMPLE
        Add-vROPSAdapterNsxt -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -collectorGroupName "sfo-remote-collectors"
        This example creates an NSX Adapter for the VI Workload Domain named in VMware Aria Operations and assigns to the collector group defined

        .EXAMPLE
        Add-vROPSAdapterNsxt -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01
        This example creates an NSX Adapter for the Management Workload Domain named in VMware Aria Operations and assigns to the "Default collector group".

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER domain
        The Workload Domain to add the NSX Adapter for.

        .PARAMETER collectorGroupName
        The name of the Collector Group to assign to the NSX Adapter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName="Default collector group"
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -user $user -pass $pass -domain $domain
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                                if (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}) {
                                    if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vcfNsxDetails.fqdn})) {
                                        if (!(Get-vROPSCredential | Where-Object {$_.name -eq $vcfNsxDetails.fqdn})) {
                                            $credentialJson = '{
                                                "name": "'
+ $vcfNsxDetails.fqdn +'",
                                                "adapterKindKey": "NSXTAdapter",
                                                "credentialKindKey": "NSXTCREDENTIAL",
                                                "fields": [
                                                    { "name": "USERNAME", "value": "'
+ $vcfNsxDetails.adminUser +'" },
                                                    { "name": "PASSWORD", "value": "'
+ $vcfNsxDetails.adminPass +'" }
                                            ]}'

                                            $credentialJson | Out-File .\addCredential.json
                                            Add-vROPSCredential -json .\addCredential.json | Out-Null
                                            Remove-Item .\addCredential.json -Force -Confirm:$false
                                        }
                                        $adapterJson = '{
                                            "name": "'
+ $vcfNsxDetails.fqdn +'",
                                            "description": "NSX-T Adapter - '
+ $vcfNsxDetails.fqdn +'",
                                            "adapterKindKey": "NSXTAdapter",
                                            "monitoringInterval": 5,
                                            "collectorGroupId": "'
+ (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id +'",
                                            "resourceIdentifiers": [
                                                { "name": "NSXTHOST", "value": "'
+ $vcfNsxDetails.fqdn +'" }
                                            ],
                                            "credential": {
                                                "id": "'
+ (Get-vROPSCredential | Where-Object {$_.name -eq $vcfNsxDetails.fqdn}).id +'"
                                                }
                                        }'

                                        $adapterJson | Out-File .\addAdapter.json
                                        Add-vROPSAdapter -json .\addAdapter.json | Out-Null
                                        $testAdapter = Test-vROPSAdapterConnection -json .\addAdapter.json
                                        $testAdapter | ConvertTo-Json -Depth 10 | Out-File .\createdAdapter.json
                                        Test-vROPSAdapterConnection -json .\createdAdapter.json -patch
                                        $adapterDetail = Get-Content -Path .\createdAdapter.json -Raw | ConvertFrom-Json
                                        $adapterDetail.PSObject.Properties.Remove('links')
                                        $adapterDetail | Add-Member -NotePropertyName description -NotePropertyValue "NSX-T Adapter - $($vcfNsxDetails.fqdn)"
                                        $adapterDetail.'adapter-certificates' = $adapterDetail.'adapter-certificates' | Select-Object * -ExcludeProperty certificateDetails
                                        $adapterDetail.id = (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vcfNsxDetails.fqdn}).id
                                        $adapterDetail | ConvertTo-Json -Depth 100 | Out-File .\patchAdapter.json  -Force
                                        Set-vROPSAdapter -json .\patchAdapter.json -patch | Out-Null
                                        if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vcfNsxDetails.fqdn}) {
                                            Start-vROPSAdapter -adapterId (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vcfNsxDetails.fqdn}).id | Out-Null
                                            Write-Output "Adding NSX Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($vcfNsxDetails.fqdn)): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding NSX Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($vcfNsxDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                        Remove-Item .\addAdapter.json -Force -Confirm:$false
                                        Remove-Item .\createdAdapter.json -Force -Confirm:$false
                                        Remove-Item .\patchAdapter.json -Force -Confirm:$false 
                                    } else {
                                        Write-Warning "Adding NSX Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($vcfNsxDetails.fqdn)), already exists: SKIPPED"
                                    }      
                                } else {
                                    Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }   
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAdapterNsxt

Function Add-vROPSAdapterPing {
    <#
        .SYNOPSIS
        Adds a Ping Adapter to VMware Aria Operations.

        .DESCRIPTION
        The Add-vROPSAdapterPing cmdlet adds a Ping adapter to VMware Aria Operations. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the collector group exits in VMware Aria Operations
        - Validates that the Ping Adapter does not already exist in VMware Aria Operations
        - Creates a new Ping adapter in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapterPing -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -addressList "192.168.11.30,192.168.11.31,192.168.11.32,192.168.11.33" -adapterName xint-vrops01 -collectorGroupName "sfo-remote-collectors"
        This example creates a new Ping adapter called 'xint-vrops01', assigns the IP Addresses provided and assigned the collector group called 'sfo-remote-collectors'

        .EXAMPLE
        Add-vROPSAdapterPing -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -addressList "192.168.11.50,192.168.11.51,192.168.11.52,192.168.11.53" -adapterName xint-vra01
        This example creates a new Ping adapter called 'xint-vra01', assigns the IP Addresses provided and assigns to the 'Default collector group'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER addressList
        The list of IP Addresses to ping.

        .PARAMETER adapterName
        The name of the Ping Adapter to create.

        .PARAMETER collectorGroupName
        The name of the Collector Group to assign to the Ping Adapter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$addressList,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adapterName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName="Default collector group"
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}) {
                                if (Get-vROPSSolution | Where-Object {$_.id -match "Ping"}) {
                                    if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName})) {
                                        $json = '{
                                            "name": "'
+ $adapterName +'",
                                            "description": "Ping Adapter - '
+ $adapterName +'",
                                            "adapterKindKey": "PingAdapter",
                                            "monitoringInterval": 5,
                                            "collectorGroupId": "'
+ (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id +'",
                                                "resourceIdentifiers": [
                                                    {
                                                        "name": "unique_name",
                                                        "value": "'
+ $adapterName +'"
                                                    },
                                                    {
                                                        "name": "address_list",
                                                        "value": "'
+ $addressList +'"
                                                    },
                                                    {
                                                        "name": "batch_circle_interval",
                                                        "value": "0"
                                                    },
                                                    {
                                                        "name": "count",
                                                        "value": "20"
                                                    },
                                                    {
                                                        "name": "dns_resolving_interval",
                                                        "value": "30"
                                                    },
                                                    {
                                                        "name": "dont_fragment",
                                                        "value": "false"
                                                    },
                                                    {
                                                        "name": "generate_fqdn_children",
                                                        "value": "false"
                                                    },
                                                    {
                                                        "name": "packet_size",
                                                        "value": "56"
                                                    },
                                                    {
                                                        "name": "period",
                                                        "value": "2000"
                                                    }
                                                ]
                                        }'

                                        $json | Out-File .\addAdapter.json
                                        Add-vROPSAdapter -json .\addAdapter.json | Out-Null
                                        if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName}) {
                                            Start-vROPSAdapter -adapterId (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName}).id | Out-Null
                                            Write-Output "Adding Ping Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Ping Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName)): POST_VALDATION_FAILED"
                                        }
                                        Remove-Item .\addAdapter.json -Force -Confirm:$false
                                    } else {
                                        Write-Warning "Adding Ping Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "The Ping Management Pack in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), not activated: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                            }   
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAdapterPing

Function Update-vROPSAdapterSddcHealth {
    <#
        .SYNOPSIS
        Updates the SDDC Health Adapters names in VMware Aria Operations.

        .DESCRIPTION
        The Update-vROPSAdapterSddcHealth cmdlet updates the names of the SDDC Health Adapters in VMware Aria
        Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that SDDC Health Adapters exits in VMware Aria Operations
        - Gathers the unique ID of the collectors
        - Gathers the details of the SDDC Health Adapters
        - Updates the name of the SDDC Health Adapters

        .EXAMPLE
        Update-vROPSAdapterSddcHealth -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example updates all the name of all SDDC Health Adapters .

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if ($adapters = Get-vROPSAdapter | Where-Object {$_.resourceKey.adapterKindKey -eq "SDDCHealthAdapter"}) {
                                Foreach ($adapter in $adapters) {
                                    $collectorDetails = Get-vROPSCollector | Where-Object {$_.id -eq $adapter.collectorId}
                                    $adapterName = (($adapter.resourceKey.name).Split("-"))[0] + "-" + ($collectorDetails.name -Split ("VMware Aria Operations Collector-"))
                                    if ($vropsVersion -lt "8.6.2") {
                                        $json = '{
                                            "resourceKey": {
                                                                "name": "'
+ $adapterName +'",
                                                                "adapterKindKey": "SDDCHealthAdapter",
                                                                "resourceKindKey": "SDDCHealth Instance"
                                                            },
                                            "description": "SDDC Health Adapter for'
+ ($collectorDetails.name -Split ("VMware Aria Operations Collector-")) +'",
                                            "collectorId": '
+ $($collectorDetails.id) +',
                                            "monitoringInterval": 5,
                                            "id": "'
+ $($adapter.id) +'"
                                        }'

                                    } else {
                                        $json = '{
                                            "name": "'
+ $adapterName +'",
                                            "adapterKindKey": "SDDCHealthAdapter",
                                            "description": "SDDC Health Adapter for'
+ ($collectorDetails.name -Split ("VMware Aria Operations Collector-")) +'",
                                            "collectorId": '
+ $($collectorDetails.id) +',
                                            "monitoringInterval": 5,
                                            "id": "'
+ $($adapter.id) +'"
                                        }'

                                    }
                                    $json | Out-File .\updateAdapter.json
                                    if (!($adapter.resourceKey.name -eq $adapterName)) {
                                        Set-vROPSAdapter -json .\updateAdapter.json | Out-Null
                                        Write-Output "Renaming Adapter ($($adapter.resourceKey.name)) to ($adapterName): SUCCESSFUL"
                                        Remove-Item .\updateAdapter.json -Force -Confirm:$false
                                    } else {
                                        Write-Warning "Renaming Adapter ($($adapter.resourceKey.name)) to ($adapterName), already performed: SKIPPED"
                                    }
                                }
                            } else {
                                Write-Error "Unable to locate Adapters of type (SDDCHealthAdapter) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vROPSAdapterSddcHealth

Function Add-vROPSAdapterSddcHealth {
    <#
        .SYNOPSIS
        Adds an SDDC Health Adapters for Collectors.

        .DESCRIPTION
        The Add-vROPSAdapterSddcHealth cmdlet adds SDDC Health Adapters for the Remove Collectors in VMware Aria
        Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that SDDC Health Adapters do not exist in VMware Aria Operations
        - Gathers the collector details from VMware Aria Operations
        - Creates a new SDDC Health Adapter for each Collector in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapterSddcHealth -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example creates an SDDC Health Adapter for each Collector Node found in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            $vropsVersion = ((Get-vROPSVersion).releaseName -split '\s+' -match '\S')[-1] 
                            if ($remoteCollectors = (Get-vROPSCollector | Where-Object { $_.type -eq "REMOTE" -or $_.type -eq "CLOUD_PROXY" })) {
                                Foreach ($collector in $remoteCollectors) {
                                    $adapterName = "SDDC Health Adapter Instance - " + $collector.name
                                    if ($vropsVersion -lt 8.5.0) {
                                        $json = '{
                                            "resourceKey": {
                                                                "name": "'
+ $adapterName +'",
                                                                "adapterKindKey": "SDDCHealthAdapter",
                                                                "resourceKindKey": "SDDCHealth Instance"
                                                            },
                                            "description": "SDDC Health Adapter for '
+ $collector.name +'",
                                            "collectorId": '
+ $($collector.id) +',
                                            "monitoringInterval": 5
                                        }'

                                    } else {
                                        $json = '{
                                            "name": "'
+ $adapterName +'",
                                            "adapterKindKey": "SDDCHealthAdapter",
                                            "description": "SDDC Health Adapter for '
+ $collector.name +'",
                                            "collectorId": '
+ $($collector.id) +',
                                            "monitoringInterval": 5
                                        }'

                                    }
                                    $json | Out-File .\addAdapter.json
                                    if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName})) {                   
                                        Add-vROPSAdapter -json .\addAdapter.json | Out-Null
                                        if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName}) {
                                            Start-vROPSAdapter -adapterId (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName}).id | Out-Null
                                            Write-Output "Adding Adapter ($adapterName) to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Adapter ($adapterName) to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Adding Adapter ($adapterName) to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), already performed: SKIPPED"
                                    }
                                    Remove-Item .\addAdapter.json -Force -Confirm:$false
                                }
                            } else {
                                Write-Error "Unable to locate Collectors in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): PRE_VALIDATION_FAILED"
                            } 
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAdapterSddcHealth

Function Add-vROPSAdapterIdentityManager {
    <#
        .SYNOPSIS
        Adds an Identity Manager adapter to VMware Aria Operations.

        .DESCRIPTION
        The Add-vROPSAdapterIdentityManager cmdlet adds a Identity Manager adapter to VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the collector Group exits in VMware Aria Operations
        - Validates that the Identity Manager adapter does not already exist in VMware Aria Operations
        - Creates a new Identity Manager adapter in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapterIdentityManager -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -wsaUser admin -wsaPass VMw@re1! -collectorGroupName "sfo-remote-collectors"
        This example creates a new Identity Manager adapter and assigns it to the collector group

        .EXAMPLE
        Add-vROPSAdapterIdentityManager -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -wsaFqdn sfo-wsa01.sfo.rainpole.io -wsaUser admin -wsaPass VMw@re1!
        This example creates a new Identity Manager adapter and assigns it to the 'Default collector group'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER wsaFqdn
        The FQDN of the Workspace ONE Access appliance.

        .PARAMETER wsaUser
        The Workspace ONE Access administrator user.

        .PARAMETER wsaPass
        The Workspace ONE Access administrator password.

        .PARAMETER collectorGroupName
        The name of the Collector Group to assign to the Identity Manager Adapter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName="Default collector group"
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}) {
                                if (Get-vROPSSolution | Where-Object {$_.adapterKindKeys -eq "IdentityManagerAdapter"}) {
                                    $adapterName = $wsaFqdn
                                    if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq "IdentityManagerAdapter"})) {
                                        if (!(Get-vROPSCredential | Where-Object {$_.name -eq $wsaFqdn})) {
                                            $credentialJson = '{
                                                "name": "'
+ $adapterName +'",
                                                "adapterKindKey": "IdentityManagerAdapter",
                                                "credentialKindKey": "IDENTITYMANAGERCREDENTIAL",
                                                "fields": [
                                                    { "name": "USERNAME", "value": "'
+ $wsaUser +'" },
                                                    { "name": "PASSWORD", "value": "'
+ $wsaPass +'" }
                                            ]}'

                                            $credentialJson | Out-File .\addCredential.json
                                            Add-vROPSCredential -json .\addCredential.json | Out-Null
                                            Remove-Item .\addCredential.json -Force -Confirm:$false
                                        }
                                        $adapterJson = '{
                                            "name": "'
+ $adapterName +'",
                                            "description": "Workspace ONE Access Adapter - '
+ $adapterName +'",
                                            "adapterKindKey": "IdentityManagerAdapter",
                                            "monitoringInterval": 5,
                                            "collectorGroupId": "'
+ (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id +'",
                                                "resourceIdentifiers": [
                                                    {
                                                        "name": "vIDMHost",
                                                        "value": "'
+ $adapterName +'"
                                                    }
                                                ],
                                            "credential": {
                                                "id": "'
+ (Get-vROPSCredential | Where-Object {$_.name -eq $adapterName}).id +'"
                                                }
                                        }'

                                        $adapterJson | Out-File .\addAdapter.json
                                        Add-vROPSAdapter -json .\addAdapter.json | Out-Null
                                        $testAdapter = Test-vROPSAdapterConnection -json .\addAdapter.json
                                        $adapterDetail = $testAdapter
                                        $adapterDetail | Add-Member -NotePropertyName description -NotePropertyValue "Workspace ONE Access Adapter - $adapterName"
                                        $adapterDetail.PSObject.Properties.Remove('links')
                                        $adapterDetail.'adapter-certificates' = $adapterDetail.'adapter-certificates' | Select-Object * -ExcludeProperty certificateDetails
                                        $certificates = New-Object System.Collections.ArrayList
                                        $certificates = $adapterDetail.'adapter-certificates'
                                        $adapterDetail.PSObject.Properties.Remove('adapter-certificates')
                                        $adapterDetail | Add-Member -NotePropertyName adapter-certificates -NotePropertyValue ([Array]$certificates)
                                        $adapterDetail.id = (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq "IdentityManagerAdapter"}).id
                                        $adapterDetail | ConvertTo-Json -Depth 100 | Out-File .\patchAdapter.json  -Force
                                        Set-vROPSAdapter -json .\patchAdapter.json -patch | Out-Null
                                        if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq "IdentityManagerAdapter"}) {
                                            Start-vROPSAdapter -adapterId (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName}).id | Out-Null
                                            Write-Output "Adding Identity Manager Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Identity Manager Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName)): POST_VALDATION_FAILED"
                                        }
                                        Remove-Item .\addAdapter.json -Force -Confirm:$false
                                        Remove-Item .\patchAdapter.json -Force -Confirm:$false
                                    } else {
                                        Write-Warning "Adding Identity Manager Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "The Identity Manager Management Pack in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), not activated: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                            }   
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAdapterIdentityManager

Function Add-vROPSAdapterSrm {
    <#
        .SYNOPSIS
        Adds a Site Recovery Manager Adapter to VMware Aria Operations.

        .DESCRIPTION
        The Add-vROPSAdapterSrm cmdlet adds an Site Recovery Manager Adapter to VMware Aria Operations. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Workload Domain is valid and then obtains the NSX Manager cluster details
        - Validates that the collector group exits in VMware Aria Operations
        - Validates that the Adapter and Credentials do not already exist in VMware Aria Operations
        - Creates a new Site Recovery Manager Adapter in VMware Aria Operations
        - Starts the collection of the Site Recovery Manager Adapter in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapterSrm -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -srmFqdn sfo-m01-srm01.sfo.rainpole.io -srmUser vrops-srm -srmPass VMw@re1!VMw@re1! -collectorGroupName "sfo-remote-collectors"
        This example creates a Site Recovery Manager Adapter in VMware Aria Operations and assigns to the collector group defined.

        .PARAMETER server
        The IP Address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER srmFqdn
        The FQDN of the Site Recovery Manager instance.

        .PARAMETER srmUser
        The username to authenticate to Site Recovery Manager.

        .PARAMETER srmPass
        The password to authenticate to Site Recovery Manager.

        .PARAMETER collectorGroupName
        The name of the collector group to assign the adapter to.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName="Default collector group"
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}) {
                                if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $srmFqdn})) {
                                    if (!(Get-vROPSCredential | Where-Object {$_.name -eq $srmFqdn})) {
                                        $credentialJson = '{
                                            "name": "'
+ $srmFqdn +'",
                                            "adapterKindKey": "SrmAdapter",
                                            "credentialKindKey": "SRM Credentials",
                                            "fields": [
                                                { "name": "username", "value": "'
+ $srmUser +'" },
                                                { "name": "password", "value": "'
+ $srmPass +'" }
                                        ]}'

                                        $credentialJson | Out-File .\addCredential.json
                                        Add-vROPSCredential -json .\addCredential.json | Out-Null
                                        Remove-Item .\addCredential.json -Force -Confirm:$false
                                    }
                                    $adapterJson = '{
                                        "name": "'
+ $srmFqdn +'",
                                        "description": "SRM Adapter - '
+ $srmFqdn +'",
                                        "adapterKindKey": "SrmAdapter",
                                        "monitoringInterval": 5,
                                        "collectorGroupId": "'
+ (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id +'",
                                        "resourceIdentifiers": [
                                            { "name": "host", "value": "'
+ $srmFqdn +'" },
                                            { "name": "port", "value": "443" }
                                        ],
                                        "credential": {
                                            "id": "'
+ (Get-vROPSCredential | Where-Object {$_.name -eq $srmFqdn}).id +'"
                                            }
                                    }'

                                    $adapterJson | Out-File .\addAdapter.json
                                    Add-vROPSAdapter -json .\addAdapter.json | Out-Null
                                    $testAdapter = Test-vROPSAdapterConnection -json .\addAdapter.json
                                    $adapterDetail = $testAdapter
                                    $adapterDetail | Add-Member -NotePropertyName description -NotePropertyValue "SRM Adapter - $($srmFqdn)"
                                    $adapterDetail.PSObject.Properties.Remove('links')
                                    $adapterDetail.'adapter-certificates' = $adapterDetail.'adapter-certificates' | Select-Object * -ExcludeProperty certificateDetails
                                    $certificates = New-Object System.Collections.ArrayList
                                    $certificates = $adapterDetail.'adapter-certificates'
                                    $adapterDetail.PSObject.Properties.Remove('adapter-certificates')
                                    $adapterDetail | Add-Member -NotePropertyName adapter-certificates -NotePropertyValue ([Array]$certificates)
                                    $adapterDetail.id = (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $srmFqdn}).id
                                    $adapterDetail | ConvertTo-Json -Depth 100 | Out-File .\patchAdapter.json  -Force
                                    Set-vROPSAdapter -json .\patchAdapter.json -patch | Out-Null
                                    if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $srmFqdn}) {
                                        Start-vROPSAdapter -adapterId (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $srmFqdn}).id | Out-Null
                                        Write-Output "Adding Site Recovery Manager Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($srmFqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding Site Recovery Manager Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($srmFqdn)): POST_VALIDATION_FAILED"
                                    }
                                    Remove-Item .\addAdapter.json -Force -Confirm:$false
                                    Remove-Item .\patchAdapter.json -Force -Confirm:$false 
                                } else {
                                    Write-Warning "Adding Site Recovery Manager Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($srmFqdn)), already exists: SKIPPED"
                                }      
                            } else {
                                Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                            }  
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAdapterSrm

Function Add-vROPSAdapterVr {
    <#
        .SYNOPSIS
        Adds a vSphere Replication Adapter to VMware Aria Operations.

        .DESCRIPTION
        The Add-vROPSAdapterVr cmdlet adds an vSphere Replication Adapter to VMware Aria Operations. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Workload Domain is valid and then obtains the NSX Manager cluster details
        - Validates that the collector group exits in VMware Aria Operations
        - Validates that the Adapter and Credentials do not already exist in VMwar eAria Operations
        - Creates a new vSphere Replication Adapter in VMware Aria Operations
        - Starts the collection of the vSphere Replication Adapter in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapterVr -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vrFqdn sfo-m01-vrms01.sfo.rainpole.io -vrUser vrops-vr@vsphere.local -vrPass VMw@re1!VMw@re1! -collectorGroupName "sfo-remote-collectors"
        This example creates a vSphere Replication Adapter in VMware Aria Operations and assigns to the collector group defined.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vrFqdn
        The fully qualified domain name of the vSphere Replication Manager.

        .PARAMETER vrUser
        The username used to connect to the vSphere Replication Manager.

        .PARAMETER vrPass
        The password used to connect to the vSphere Replication Manager.

        .PARAMETER collectorGroupName
        The name of the collector group to assign the vSphere Replication Adapter to.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorGroupName="Default collector group"
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}) {
                                if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vrFqdn})) {
                                    if (!(Get-vROPSCredential | Where-Object {$_.name -eq $vrFqdn})) {
                                        $credentialJson = '{
                                            "name": "'
+ $vrFqdn +'",
                                            "adapterKindKey": "VrAdapter",
                                            "credentialKindKey": "VR Credentials",
                                            "fields": [
                                                { "name": "username", "value": "'
+ $vrUser +'" },
                                                { "name": "password", "value": "'
+ $vrPass +'" }
                                        ]}'

                                        $credentialJson | Out-File .\addCredential.json
                                        Add-vROPSCredential -json .\addCredential.json | Out-Null
                                        Remove-Item .\addCredential.json -Force -Confirm:$false
                                    }
                                    $adapterJson = '{
                                        "name": "'
+ $vrFqdn +'",
                                        "description": "vSphere Replication Adapter - '
+ $vrFqdn +'",
                                        "adapterKindKey": "VrAdapter",
                                        "monitoringInterval": 5,
                                        "collectorGroupId": "'
+ (Get-vROPSCollectorGroup | Where-Object {$_.name -eq $collectorGroupName}).id +'",
                                        "resourceIdentifiers": [
                                            { "name": "vchost", "value": "'
+ (Get-VCFWorkloadDomain | Where-Object {$_.name -eq "sfo-m01"}).vcenters.fqdn +'" }
                                        ],
                                        "credential": {
                                            "id": "'
+ (Get-vROPSCredential | Where-Object {$_.name -eq $vrFqdn}).id +'"
                                            }
                                    }'

                                    $adapterJson | Out-File .\addAdapter.json
                                    Add-vROPSAdapter -json .\addAdapter.json | Out-Null
                                    $testAdapter = Test-vROPSAdapterConnection -json .\addAdapter.json
                                    $adapterDetail = $testAdapter
                                    $adapterDetail | Add-Member -NotePropertyName description -NotePropertyValue "vSphere Replication Adapter - $($vrFqdn)"
                                    $adapterDetail.PSObject.Properties.Remove('links')
                                    $adapterDetail.'adapter-certificates' = $adapterDetail.'adapter-certificates' | Select-Object * -ExcludeProperty certificateDetails
                                    $certificates = New-Object System.Collections.ArrayList
                                    $certificates = $adapterDetail.'adapter-certificates'
                                    $adapterDetail.PSObject.Properties.Remove('adapter-certificates')
                                    $adapterDetail | Add-Member -NotePropertyName adapter-certificates -NotePropertyValue ([Array]$certificates)
                                    $adapterDetail.id = (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vrFqdn}).id
                                    $adapterDetail | ConvertTo-Json -Depth 100 | Out-File .\patchAdapter.json  -Force
                                    Set-vROPSAdapter -json .\patchAdapter.json -patch | Out-Null
                                    if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vrFqdn}) {
                                        Start-vROPSAdapter -adapterId (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $vrFqdn}).id | Out-Null
                                        Write-Output "Adding vSphere Replication Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($vrFqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding vSphere Replication Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($vrFqdn)): POST_VALIDATION_FAILED"
                                    }
                                    Remove-Item .\addAdapter.json -Force -Confirm:$false
                                    Remove-Item .\patchAdapter.json -Force -Confirm:$false 
                                } else {
                                    Write-Warning "Adding vSphere Replication Adapter in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($($vrFqdn)), already exists: SKIPPED"
                                }      
                            } else {
                                Write-Error "Collector Group in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($collectorGroupName), does not exist: PRE_VALIDATION_FAILED"
                            }  
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAdapterVr

Function Undo-vROPSAdapter {
    <#
        .SYNOPSIS
        Removes an adapter from VMware Aria Operations.

        .DESCRIPTION
        The Undo-vROPSAdapter cmdlet adds a Identity Manager adapter to VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Adapter is present
        - Deletes the adapter from VMware Aria Operations

        .EXAMPLE
        Undo-vROPSAdapter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -adapterName sfo-wsa01.sfo.rainpole.io -adapterType IdentityManagerAdapter
        This example deletes the adapter type IdentityManagerAdapter, with a name of sfo-wsa01.sfo.rainpole.io.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER adapterName
        The name of the adapter.

        .PARAMETER adapterType
        The type of adapter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adapterName,
        [Parameter (Mandatory = $true)] [ValidateSet("PingAdapter","IdentityManagerAdapter","NSXTAdapter","SDDCHealthAdapter","SrmAdapter","VrAdapter","VMWARE","VirtualAndPhysicalSANAdapter")] [String]$adapterType
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq $adapterType}) {
                                Remove-vROPSAdapter -id (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq $adapterType}).id | Out-Null
                                Do {
                                    Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq $adapterType} | Out-Null
                                    Start-Sleep 2
                                } While (Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq $adapterType})
                                if (!(Get-vROPSAdapter | Where-Object {$_.resourceKey.name -eq $adapterName -and $_.resourceKey.adapterKindKey -eq $adapterType})) {
                                    Write-Output "Removing adapter of type ($adapterType) from VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing adapter of type ($adapterType) from VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing adapter of type ($adapterType) from VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($adapterName), does not exist: SKIPPED"
                            }   
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vROPSAdapter

Function Undo-vROPSCredential {
    <#
        .SYNOPSIS
        Removes a credential from VMware Aria Operations.

        .DESCRIPTION
        The Undo-vROPSCredential cmdlet removes a credential from VMware Aria Operations. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Credential is present
        - Deletes the credential from VMware Aria Operations

        .EXAMPLE
        Undo-vROPSCredential -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -credentialName sfo-wsa01.sfo.rainpole.io -credentialType IdentityManagerAdapter
        This example deletes the credential type IdentityManagerAdapter, with a name of sfo-wsa01.sfo.rainpole.io.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER credentialName
        The name of the credential.

        .PARAMETER credentialType
        The type of credential.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$credentialName,
        [Parameter (Mandatory = $true)] [ValidateSet("IdentityManagerAdapter","NSXTAdapter","CASAdapter","SrmAdapter","VrAdapter","VMWARE","VirtualAndPhysicalSANAdapter")] [String]$credentialType
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSCredential | Where-Object {$_.name -eq $credentialName -and $_.adapterKindKey -eq $credentialType}) {
                                if (!(Get-vROPSCredential -credentialId (Get-vROPSCredential -adapter | Where-Object {$_.name -eq $credentialName -and $_.adapterKindKey -eq $credentialType}).id -adapter)) {
                                    Remove-vROPSCredential -credentialId (Get-vROPSCredential | Where-Object {$_.name -eq $credentialName -and $_.adapterKindKey -eq $credentialType}).Id | Out-Null
                                    if (!(Get-vROPSCredential | Where-Object {$_.name -eq $credentialName -and $_.adapterKindKey -eq $credentialType})) {
                                        Write-Output "Removing credential of type ($credentialType) from VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing credential of type ($credentialType) from VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Credential of type ($credentialType) named ($credentialName) still assigned to an adapter: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing credential of type ($credentialType) from VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName), does not exist: SKIPPED"
                            }   
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vROPSCredential

Function Add-vROPSAlertPluginEmail {
    <#
        .SYNOPSIS
        Adds an Email based Alert Plugin.

        .DESCRIPTION
        The Add-vROPSAlertPluginEmail cmdlet adds an Email based Alert Plugin in VMware Aria Operations. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the Email Alert Plugin does not exist in VMware Aria Operations
        - Creates a new Email Alert Plugin and enables it in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAlertPluginEmail -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -pluginName "Email-Alert-Plugin" -smtpServer smtp.rainpole.io -smtpPort 25 -senderAddress "vrops-alerts@rainpole.io" -secureConnection true -protocol TLS -authentication false
        This example creates and enables an Email Alert Plugin in VMware Aria Operations without authentication

        .EXAMPLE
        Add-vROPSAlertPluginEmail -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -pluginName "Email-Alert-Plugin" -smtpServer smtp.rainpole.io -smtpPort 25 -senderAddress "vrops-alerts@rainpole.io" -secureConnection true -protocol TLS -authentication true -authUser administrator -authPass VMw@re1!
        This example creates and enables an Email Alert Plugin in VMware Aria Operations with authentication.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to connect to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER pluginName
        The name of the Email Alert Plugin.

        .PARAMETER smtpServer
        The SMTP server to use for sending emails.

        .PARAMETER smtpPort
        The SMTP port to use for sending emails.

        .PARAMETER senderAddress
        The email address to use for sending emails.

        .PARAMETER secureConnection
        Whether to use a secure connection or not.

        .PARAMETER protocol
        The protocol to use for the secure connection.

        .PARAMETER authentication
        Whether to use authentication or not.

        .PARAMETER authUser
        The username to use for authentication.

        .PARAMETER authPass
        The password to use for authentication.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pluginName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpPort,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$senderAddress,
        [Parameter (Mandatory = $true)] [ValidateSet("true","false")] [ValidateNotNullOrEmpty()] [String]$secureConnection,
        [Parameter (Mandatory = $false)] [ValidateSet("SSL","TLS")] [ValidateNotNullOrEmpty()] [String]$protocol,
        [Parameter (Mandatory = $true)] [ValidateSet("true","false")] [ValidateNotNullOrEmpty()] [String]$authentication,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$authUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$authPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (!(Get-vROPSAlertPlugin | Where-Object {$_.name -eq $pluginName})) {
                                if ($authentication -eq "true") {
                                    $json = '{
                                    "pluginTypeId" : "StandardEmailPlugin",
                                    "name" : "'
+ $pluginName +'",
                                    "description" : "",
                                    "configValues" : [ {
                                        "name" : "IS_SECURE_CONNECTION",
                                        "value" : "'
+ $secureConnection +'"
                                    }, {
                                        "name" : "SECURE_CONNECTION_TYPE",
                                        "value" : "'
+ $protocol +'"
                                    }, {
                                        "name" : "IS_REQUIRES_AUTHETICATION",
                                        "value" : "'
+ $authentication +'"
                                    }, {
                                        "name" : "USERNAME",
                                        "value" : "'
+ $authUser +'"
                                    }, {
                                        "name" : "PASSWORD",
                                        "value" : "'
+ $authPass +'"
                                    },{
                                        "name" : "SMTP_HOST",
                                        "value" : "'
+ $smtpServer +'"
                                    }, {
                                        "name" : "SMTP_PORT",
                                        "value" : "'
+ $smtpPort +'"
                                    }, {
                                        "name" : "senderEmailAddress",
                                        "value" : "'
+ $senderAddress +'"
                                    }, {
                                        "name" : "senderName",
                                        "value" : "'
+ ($senderAddress -split("@"))[0] +'"
                                    } ]
                                    }'

                                } else {
                                    $json = '{
                                        "pluginTypeId" : "StandardEmailPlugin",
                                        "name" : "'
+ $pluginName +'",
                                        "description" : "",
                                        "configValues" : [ {
                                            "name" : "IS_SECURE_CONNECTION",
                                            "value" : "'
+ $secureConnection +'"
                                        }, {
                                            "name" : "SECURE_CONNECTION_TYPE",
                                            "value" : "'
+ $protocol +'"
                                        }, {
                                            "name" : "SMTP_HOST",
                                            "value" : "'
+ $smtpServer +'"
                                        }, {
                                            "name" : "SMTP_PORT",
                                            "value" : "'
+ $smtpPort +'"
                                        }, {
                                            "name" : "senderEmailAddress",
                                            "value" : "'
+ $senderAddress +'"
                                        }, {
                                            "name" : "senderName",
                                            "value" : "'
+ ($senderAddress -split("@"))[0] +'"
                                        } ]
                                        }'

                                }
                                $json | Out-File .\addAlertPlugin.json
                                Add-vROPSAlertPlugin -json .\addAlertPlugin.json | Out-Null
                                if (Get-vROPSAlertPlugin | Where-Object {$_.name -eq $pluginName}) {
                                    Set-vROPSAlertPluginStatus -pluginId (Get-vROPSAlertPlugin | Where-Object {$_.name -eq $pluginName}).pluginId -status true | Out-Null
                                    Write-Output "Adding Alert Plugin to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($pluginName): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding Alert Plugin to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($pluginName): POST_VALIDATION_FAILED"
                                }
                                Remove-Item .\addAlertPlugin.json -Force -Confirm:$false
                            } else {
                                Write-Warning "Adding Alert Plugin to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($pluginName), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSAlertPluginEmail

Function Import-vROPSNotification {
    <#
        .SYNOPSIS
        Adds notifications to VMware Aria Operations.

        .DESCRIPTION
        The Import-vROPSNotification cmdlet adds notifications in VMware Aria Operations. The cmdlet connects to SDDC
        Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the .csv provided exists
        - Adds notifications based on a .csv file into VMware Aria Operations

        .EXAMPLE
        Import-vROPSNotification -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -csvPath .\SampleNotifications\aria-operations-notifications-vcf.csv
        This example adds notifications based on the comma seperated value file provided to VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER csvPath
        The path to the .csv file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$csvPath
    )

    if (!$PsBoundParameters.ContainsKey("csvPath")) {
        $csvPath = Get-ExternalFileName -title "Select the Comma Seperated Value (.csv) File" -fileType "csv" -location "default"
    }
    if (!(Test-Path -Path $csvPath)) {
        Write-Error  "Comma Seperated Value (.csv) File ($csvPath) File Not Found"
        Break
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            $StatusMsg = New-vROPSNotification $csvPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ( $ErrorMsg ) {
                                Write-Error "$ErrorMsg"
                            } else {
                                Write-Output "Adding Notifications to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) using Comma Separated Value File ($csvPath): SUCCESSFUL"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Import-vROPSNotification

Function Test-vROPsAdapterStatusByType {
    <#
        .SYNOPSIS
        Validates the integration status of VMware Aria Operations Adapters.

        .DESCRIPTION
        The Test-vROPsAdapterStatusByType cmdlet tests the integration status between VMware Aria Operations and
        configured adapter. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates the integration status between VMware Aria Operations and configured adapter

        .EXAMPLE
        Test-vROPsAdapterStatusByType -server sfo-vcf01.sfo.rainpole.io "administrator@vsphere.local" -pass "VMw@re1!" -adapterKind NSXTAdapter
        This example validates the integration status between VMware Aria Operations and the NSX adapter.

        .EXAMPLE
        Test-vROPsAdapterStatusByType -server sfo-vcf01.sfo.rainpole.io "administrator@vsphere.local" -pass "VMw@re1!" -adapterKind CASAdapter
        This example validates the integration status between VMware Aria Operations and VMware Aria Automation adapter.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER adapterKind
        The adapter kind.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateSet("Container", "EP Ops Adapter", "Http Post", "LogInsight", "MicrosoftAzureAdapter", "AmazonAWSAdapter", "NSXTAdapter", "PingAdapter", "SDDCHealthAdapter", "APPLICATIONDISCOVERY", "VMWARE", "VmcAdapter", "IdentityManagerAdapter", "APPOSUCP", "VOAAdapter", "CASAdapter", "LogInsightAdapter", "NETWORK_INSIGHT", "vCenter Operations Adapter", "vRealizeOpsMgrAPI", "VirtualAndPhysicalSANAdapter")] [ValidateNotNullOrEmpty()] [String]$adapterKind
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {   
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (Get-vROPSSolution | Where-Object { $_.adapterKindKeys -eq $adapterKind }) {  
                                if ((Get-vROPSAdapter | Where-Object { $_.resourceKey.adapterKindKey -eq $adapterKind })) {  
                                    $adapterJson = Get-vROPSAdapter | Where-Object { $_.resourceKey.adapterKindKey -eq $adapterKind } 
                                    $adapterJson | ForEach-Object {
                                        Test-vROPSAdapterStatus -resourceId $_.id
                                    }
                                } else {
                                    Write-Error "'$($adapterKind)' Adapter is not configured" 
                                }
                            } else { 
                                Write-Error "Unable to find '$($adapterKind)' Adapter" 
                            }
                        }                                          
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Test-vROPsAdapterStatusByType

Function Update-vROPSvRAAdapterCredential {
    <#
        .SYNOPSIS
        Update the credential of VMware Aria Automation adapter in VMware Aria Operations.

        .DESCRIPTION
        The Update-vROPSvRAAdapterCredential cmdlet update the credential of VMware Aria Automation adapter in VMware
        Aria Operations. The cmdlet connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity is possible to VMware Aria Automation
        - Validates that the VMware Aria Automation adapter exists and configured in VMware Aria Operations
        - Validates that the credential name of VMware Aria Automation adapter does not already exist in VMware Aria Operations
        - Validates that the given credential is valid and updates VMware Aria Automation adapter in VMware Aria Operations
        - Verifies the VMware Aria Automation adapter status in VMware Aria Operations after updating the credential

        .EXAMPLE
        Update-vROPSvRAAdapterCredential -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -credential_displayname "VMware Aria Automation Credentials" -credential_username svc-vrops-vra@sfo.rainpole.io -credential_password VMw@re1! -adapterKind CASAdapter
        This example update the credential of VMware Aria Automation adapter with name "VMware Aria Automation Credentials" in VMware Aria Operations.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER credential_displayname
        The credential display name.

        .PARAMETER credential_username
        The credential user name.

        .PARAMETER credential_password
        The credential password.

        .PARAMETER adapterKind
        The adapter kind.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$credential_displayname,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$credential_username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$credential_password,
        [Parameter (Mandatory = $true)] [ValidateSet("CASAdapter")] [ValidateNotNullOrEmpty()] [String]$adapterKind
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {   
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                                if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {  
                                    if (Get-vROPSSolution | Where-Object { $_.adapterKindKeys -eq $adapterKind }) {
                                        if ((Get-vROPSAdapter | Where-Object { $_.resourceKey.adapterKindKey -eq $adapterKind })) {
                                            if (!(Get-vROPSCredential | Where-Object { $_.name -eq $credential_displayname })) {
                                                $credentialJson = ' {
                                                                        "name" : "'
+ $credential_displayname + '",
                                                                        "adapterKindKey" : "'
+ $adapterKind + '",
                                                                        "credentialKindKey" : "CMPCREDENTIALS",
                                                                            "fields" : [ {
                                                                                "name" : "USERNAME",
                                                                                "value" : "'
+ $credential_username + '"
                                                                                }, {
                                                                                "name" : "PASSWORD",
                                                                                "value" : "'
+ $credential_password + '"
                                                                            } ]
                                                                        }'

                                                $credentialJson | Out-File .\addCredential.json
                                                Add-vROPSCredential -json .\addCredential.json | Out-Null
                                                Remove-Item .\addCredential.json -Force -Confirm:$false
                                                if ((Get-vROPSCredential | Where-Object { $_.name -eq $credential_displayname })) { 
                                                    Write-Output "Adding VMware Aria Automation credential named ($credential_displayname) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                                    $vraAdapterObj = Get-vROPSAdapter | Where-Object { $_.resourceKey.adapterKindKey -eq $adapterKind } 
                                                    $vraAdapterId = $vraAdapterObj.id
                                                    $adapterName = $vraAdapterObj.resourceKey.name
                                                    $credid = (Get-vROPSCredential | Where-Object { $_.name -eq $credential_displayname }).id
                                                    $vraAdapterObj.credentialInstanceId = $credid
                                                    $vraAdapterObj.PSObject.Properties.Remove('links')
                                                    $vraAdapterObj.PSObject.Properties.Remove('lastHeartbeat')
                                                    $vraAdapterObj.PSObject.Properties.Remove('messageFromAdapterInstance')
                                                    $vraAdapterObj.PSObject.Properties.Remove('lastCollected')
                                                    $vraAdapterObj.PSObject.Properties.Remove('numberOfMetricsCollected')
                                                    $vraAdapterObj.PSObject.Properties.Remove('numberOfResourcesCollected')
                                                    $certificates = New-Object System.Collections.ArrayList
                                                    $vraAdapterObj | Add-Member -NotePropertyName adapter-certificates -NotePropertyValue ([Array]$certificates)
                                                    $vraAdapterObj | ConvertTo-Json -Depth 4 | Out-File .\vraadapter.json
                                                    $testresponse = Test-vROPSAdapterConnection -json .\vraadapter.json -patch
                                                    if ($testresponse.Count) { 
                                                        Write-Output "Validating VMware Aria Automation credential named ($credential_displayname) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                                        Set-vROPSAdapter -json .\vraadapter.json | Out-Null
                                                        Write-Output "Updating VMware Aria Automation adapter named ($adapterName) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"
                                                        Start-vROPSAdapter -adapterId $vraAdapterId | Out-Null
                                                        Start-Sleep 5
                                                        Write-Output "Verifying VMware Aria Automation adapter status. $(Test-vROPsAdapterStatus -resourceId $vraAdapterId)"
                                                    } else {
                                                        Write-Error "Validating VMware Aria Automation credential named ($credential_displayname) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALDATION_FAILED"
                                                        Remove-vROPSCredential -credentialId $credid
                                                        Write-Output "Removing VMware Aria Automation credential named ($credential_displayname) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): SUCCESSFUL"    
                                                    }
                                                    Remove-Item .\vraadapter.json -Force -Confirm:$false 
                                                } else {
                                                    Write-Error "Adding VMware Aria Automation credential named ($credential_displayname) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)): POST_VALDATION_FAILED"
                                                    Break
                                                }
                                            } else {
                                                Write-Error "Adding VMware Aria Automation credential named ($credential_displayname) in VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)), already exists: SKIPPED"
                                                Break
                                            }
                                        } else {
                                            Write-Error "'$($adapterKind)' Adapter is not configured: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find '$($adapterKind)' Adapter: PRE_VALIDATION_FAILED"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vROPSvRAAdapterCredential

Function Add-vROPSVcfCredential {
    <#
        .SYNOPSIS
        Adds a VMware Cloud Foundation Credential.

        .DESCRIPTION
        The Add-vROPSVcfCredential cmdlet adds a VMware Cloud Foundation credential to VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the credential does not already exist in VMware Aria Operations
        - Creates a VMware Cloud Foundation credentials in VMware Aria Operations

        .EXAMPLE
        Add-vROPSVcfCredential -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -serviceUser svc-iom-vcf@sfo.rainpole.io -servicePassword VMw@re1!
        This example adds a VMware Cloud Foundation credential to VMware Aria Operations.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER serviceUser
        The username of the VMware Cloud Foundation service account.

        .PARAMETER servicePassword
        The password of the VMware Cloud Foundation service account.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$servicePassword
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            $credentialName = "VCF Credential - " + $server.Split('.')[-0]     
                            if (!(Get-vROPSCredential | Where-Object {$_.name -eq $credentialName})) {
                                $credentialJson = '{
                                    "name": "'
+ $credentialName +'",
                                    "adapterKindKey": "VcfAdapter",
                                    "credentialKindKey": "VcfCredentials",
                                    "fields": [
                                        { "name": "USER", "value": "'
+ $serviceUser +'" },
                                        { "name": "PASSWORD", "value": "'
+ $servicePassword +'" }
                                ]}'

                                $credentialJson | Out-File .\addCredential.json
                                Add-vROPSCredential -json .\addCredential.json | Out-Null
                                Remove-Item .\addCredential.json -Force -Confirm:$false
                                if (Get-vROPSCredential | Where-Object {$_.name -eq $credentialName}) {
                                    Write-Output "Adding VMware Cloud Foundation Credential to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding VMware Cloud Foundation Credential to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding VMware Cloud Foundation Credential to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSVcfCredential

Function Add-vROPSVcenterCredential {
    <#
        .SYNOPSIS
        Adds a vCenter Server Credential.

        .DESCRIPTION
        The Add-vROPSVcenterCredential cmdlet adds a vCenter Server credential to VMware Aria Operations.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the credential does not already exist in VMware Aria Operations
        - Creates vCenter Server credentials in VMware Aria Operations

        .EXAMPLE
        Add-vROPSVcenterCredential -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -serviceUser svc-iom-vsphere@sfo.rainpole.io -servicePassword VMw@re1!
        This example adds a vCenter Server credential to VMware Aria Operations.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to add the vCenter Server credential to.

        .PARAMETER serviceUser
        The username of the vCenter Server service account.

        .PARAMETER servicePassword
        The password of the vCenter Server service account.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$servicePassword
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                        if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                            $credentialName = "vCenter Credential - " + (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).vcenters.fqdn.Split('.')[-0]     
                            if (!(Get-vROPSCredential | Where-Object {$_.name -eq $credentialName})) {
                                $credentialJson = '{
                                    "name": "'
+ $credentialName +'",
                                    "adapterKindKey": "VMWARE",
                                    "credentialKindKey": "PRINCIPALCREDENTIAL",
                                    "fields": [
                                        { "name": "USER", "value": "'
+ $serviceUser +'" },
                                        { "name": "PASSWORD", "value": "'
+ $servicePassword +'" }
                                ]}'

                                $credentialJson | Out-File .\addCredential.json
                                Add-vROPSCredential -json .\addCredential.json | Out-Null
                                Remove-Item .\addCredential.json -Force -Confirm:$false
                                if (Get-vROPSCredential | Where-Object {$_.name -eq $credentialName}) {
                                    Write-Output "Adding vCenter Server Credential to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding vCenter Server Credential to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding vCenter Server Credential to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSVcenterCredential

Function Add-vROPSNsxCredential {
    <#
        .SYNOPSIS
        Adds an NSX Credential.

        .DESCRIPTION
        The Add-vROPSNsxCredential cmdlet adds an NSX credential to VMware Aria Operations, this can be either a
        regular user or a Principal Identity (certificate based). The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Validates that the credential does not already exist in VMware Aria Operations
        - Creates NSX credential in VMware Aria Operations

        .EXAMPLE
        Add-vROPSNsxCredential -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -serviceUser svc-iom-nsx@sfo.rainpole.io -servicePassword VMw@re1!
        This example adds an NSX credential to VMware Aria Operations

        .EXAMPLE
        Add-vROPSNsxCredential -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -certificate -certificateData sfo-m01-nsx01.cer -certificateKey sfo-m01-nsx01.key
        This example adds an NSX Principal Identity as a client certificate credential to VMware Aria Operations.

        .PARAMETER server
        The IP address or FQDN of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to SDDC Manager.

        .PARAMETER pass
        The password to authenticate to SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to add the NSX credential to.

        .PARAMETER serviceUser
        The username of the NSX service account.

        .PARAMETER servicePassword
        The password of the NSX service account.

        .PARAMETER certificate
        Switch to indicate that the NSX credential is a Principal Identity (certificate based).

        .PARAMETER certificateData
        The path to the NSX certificate file (.cer).

        .PARAMETER certificateKey
        The path to the NSX certificate key file (.key).
    #>


    [CmdletBinding(DefaultParametersetName = "credential")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false, ParameterSetName = "credential")] [ValidateNotNullOrEmpty()] [String]$serviceUser,
        [Parameter (Mandatory = $false, ParameterSetName = "credential")] [ValidateNotNullOrEmpty()] [String]$servicePassword,
        [Parameter (Mandatory = $false, ParameterSetName = "certificate")] [ValidateNotNullOrEmpty()] [Switch]$certificate,
        [Parameter (Mandatory = $false, ParameterSetName = "certificate")] [ValidateNotNullOrEmpty()] [String]$certificateData,
        [Parameter (Mandatory = $false, ParameterSetName = "certificate")] [ValidateNotNullOrEmpty()] [String]$certificateKey
    )

    Try {
        if ($PSBoundParameters.ContainsKey('certificate')) {
            if (!$PsBoundParameters.ContainsKey("certificateData")) {
                $Global:certificateData = Get-ExternalFileName -title "Select the NSX Manager Certificate File (.cer)" -fileType "cer" -location "default"
                
            } else {
                if (!(Test-Path -Path $certificateData)) {
                    Write-Error  "Certificate (cer) for NSX Credential ($certificateData) File Not Found"
                    Break
                }
            }
            if (!$PsBoundParameters.ContainsKey("certificateKey")) {
                $Global:certificateKey = Get-ExternalFileName -title "Select the NSX Manager Certificate File (.key)" -fileType "key" -location "default"
            } else {
                if (!(Test-Path -Path $certificateKey)) {
                    Write-Error  "Certificate (key) for NSX Credential ($certificateKey) File Not Found"
                    Break
                }
            }
            if (Test-Path -Path $certificateData) {
                $dataFile = (Get-Content -Path $certificateData) -join "\n"
            }
            if (Test-Path -Path $certificateKey) {
                $keyFile = (Get-Content -Path $certificateKey) -join "\n"
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                        if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                            if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                                $credentialName = "NSX Credential - " + (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}).nsxtCluster.vipfqdn.Split('.')[-0]     
                                if (!(Get-vROPSCredential | Where-Object {$_.name -eq $credentialName})) {
                                    if ($PSBoundParameters.ContainsKey('credential')) {
                                        $credentialType = "NSX Credential"
                                        $credentialJson = '{
                                            "name": "'
+ $credentialName +'",
                                            "adapterKindKey": "NSXTAdapter",
                                            "credentialKindKey": "NSXTCREDENTIAL",
                                            "fields": [
                                                {
                                                    "name": "USERNAME",
                                                    "value": "'
+ $serviceUser +'"
                                                },
                                                {
                                                    "name": "PASSWORD",
                                                    "value": "'
+ $servicePassword +'"
                                                }
                                        ]}'

                                    } elseif ($PSBoundParameters.ContainsKey('certificate')) {
                                        $credentialType = "NSX Client Certificate Credential"
                                        $credentialJson = '{
                                            "name": "'
+ $credentialName +'",
                                            "adapterKindKey": "NSXTAdapter",
                                            "credentialKindKey": "CERTIFICATE_CREDENTIAL",
                                            "fields": [
                                                {
                                                    "name": "CLIENT_CERT_DATA",
                                                    "value": "'
+ $dataFile +'"
                                                },
                                                {
                                                    "name": "CLIENT_KEY_DATA",
                                                    "value": "'
+ $keyFile +'"
                                                }
                                        ]}'

                                    }
                                    $credentialJson | Out-File .\addCredential.json
                                    Add-vROPSCredential -json .\addCredential.json | Out-Null
                                    Remove-Item .\addCredential.json -Force -Confirm:$false
                                    if (Get-vROPSCredential | Where-Object {$_.name -eq $credentialName}) {
                                        Write-Output "Adding $credentialType to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding $credentialType to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding $credentialType to VMware Aria Operations ($($vcfVropsDetails.loadBalancerFqdn)) named ($credentialName), already exists: SKIPPED"
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROPSNsxCredential

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region P R I V A T E C L O U D A U T O M A T I O N F U N C T I O N S ###########

Function Export-PcaJsonSpec {
    <#
        .SYNOPSIS
        Create JSON specification for Private Cloud Automation

        .DESCRIPTION
        The Export-PcaJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation workbook
        to deploy the Private Cloud Automation for VMware Cloud Foundation validated solution:
        - Validates that the Planning and Preparation is available
        - Generates the JSON specification file using the Planning and Preparation workbook

        .EXAMPLE
        Export-PcaJsonSpec -workbook .\pnp-workbook.xlsx -jsonFile .\pcaDeploySpec.json
        This example creates a JSON specification Private Cloud Automation using the Planning and Preparation Workbook.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER jsonFile
        The path to the JSON specification file to be created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        }
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Generation of Private Cloud Automation (.json) Specification File"
        if (Test-Path -Path $workbook) {
            $pnpWorkbook = Open-ExcelPackage -Path $Workbook
            $jsonObject = @()
            $jsonObject += [pscustomobject]@{
            'sddcManagerFqdn'                   = $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value
            'sddcManagerUser'                   = $pnpWorkbook.Workbook.Names["sso_default_admin"].Value
            'sddcManagerPass'                   = $pnpWorkbook.Workbook.Names["administrator_vsphere_local_password"].Value
            'mgmtSddcDomainName'                = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value
            'contentLibraryName'                = $pnpWorkbook.Workbook.Names["vrslcm_xreg_content_library"].Value
            'customerConnectAlias'              = ($pnpWorkbook.Workbook.Names["xreg_customer_connect_email"].Value).Split('@')[0]
            'customerConnectPassword'           = $pnpWorkbook.Workbook.Names["xreg_customer_connect_password"].Value
            'customerConnectUsername'           = $pnpWorkbook.Workbook.Names["xreg_customer_connect_email"].Value
            'licenseAlias'                      = $pnpWorkbook.Workbook.Names["vra_license_alias"].Value
            'licenseKey'                        = if ($pnpWorkbook.Workbook.Names["vrs_license"].Value) { $pnpWorkbook.Workbook.Names["vrs_license"].Value } else { $pnpWorkbook.Workbook.Names["vra_license"].Value }
            'certificateAlias'                  = $pnpWorkbook.Workbook.Names["xreg_vra_virtual_hostname"].Value
            'rootPasswordAlias'                 = $pnpWorkbook.Workbook.Names["xreg_vra_root_password_alias"].Value
            'rootPassword'                      = $pnpWorkbook.Workbook.Names["xreg_vra_root_password"].Value
            'rootUserName'                      = $pnpWorkbook.Workbook.Names["xreg_vra_root_username"].Value
            'xintPasswordAlias'                 = $pnpWorkbook.Workbook.Names["vrslcm_xreg_env_password_alias"].Value
            'xintPassword'                      = $pnpWorkbook.Workbook.Names["vrslcm_xreg_env_password"].Value
            'xintUserName'                      = $pnpWorkbook.Workbook.Names["vrslcm_xreg_admin_username"].Value
            'environmentName'                   = $pnpWorkbook.Workbook.Names["vrslcm_xreg_env"].Value
            'datacenter'                        = $pnpWorkbook.Workbook.Names["vrslcm_xreg_dc"].Value
            'vcenterFqdn'                       = $pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value
            'vcenterDatacenter'                 = $pnpWorkbook.Workbook.Names["mgmt_datacenter"].Value
            'vcenterCluster'                    = $pnpWorkbook.Workbook.Names["mgmt_cluster"].Value
            'vcenterDatastore'                  = $pnpWorkbook.Workbook.Names["mgmt_vsan_datastore"].Value
            'network'                           = $pnpWorkbook.Workbook.Names["xreg_seg01_name"].Value
            'dns'                               = ($pnpWorkbook.Workbook.Names["region_dns1_ip"].Value + "," + $pnpWorkbook.Workbook.Names["region_dns2_ip"].Value)
            'gateway'                            = $pnpWorkbook.Workbook.Names["xreg_seg01_gateway_ip"].Value
            'netmask'                            = $pnpWorkbook.Workbook.Names["xreg_seg01_mask"].Value
            'domain'                            = $pnpWorkbook.Workbook.Names["region_ad_parent_fqdn"].Value
            'searchpath'                        = $pnpWorkbook.Workbook.Names["parent_dns_zone"].Value
            'ntp'                                = $pnpWorkbook.Workbook.Names["xregion_ntp1_server"].Value
            'nodeSize'                            = $pnpWorkbook.Workbook.Names["xreg_vra_appliance_size"].Value.ToLower()
            'vraK8ServiceCidr'                  = $pnpWorkbook.Workbook.Names["xreg_vra_k8s_cluster_cidr"].Value
            'vraK8ClusterCidr'                  = $pnpWorkbook.Workbook.Names["xreg_vra_k8s_service_cidr"].Value
            'clusterFqdn'                       = $pnpWorkbook.Workbook.Names["xreg_vra_virtual_fqdn"].Value
            'clusterIp'                         = $pnpWorkbook.Workbook.Names["xreg_vra_virtual_ip"].Value
            'vraNodeaFqdn'                      = $pnpWorkbook.Workbook.Names["xreg_vra_nodea_fqdn"].Value
            'vraNodeaHostname'                  = $pnpWorkbook.Workbook.Names["xreg_vra_nodea_hostname"].Value
            'vraNodeaIp'                        = $pnpWorkbook.Workbook.Names["xreg_vra_nodea_ip"].Value
            'vraNodebFqdn'                      = $pnpWorkbook.Workbook.Names["xreg_vra_nodeb_fqdn"].Value
            'vraNodebHostname'                  = $pnpWorkbook.Workbook.Names["xreg_vra_nodeb_hostname"].Value
            'vraNodebIp'                        = $pnpWorkbook.Workbook.Names["xreg_vra_nodeb_ip"].Value
            'vraNodecFqdn'                      = $pnpWorkbook.Workbook.Names["xreg_vra_nodec_fqdn"].Value
            'vraNodecHostname'                  = $pnpWorkbook.Workbook.Names["xreg_vra_nodec_hostname"].Value
            'vraNodecIp'                        = $pnpWorkbook.Workbook.Names["xreg_vra_nodec_ip"].Value
            'wldSddcDomainName'                 = $pnpWorkbook.Workbook.Names["wld_sddc_domain"].Value
            'vmFolder'                          = $pnpWorkbook.Workbook.Names["xreg_vra_vm_folder"].Value
            'vmList'                            = $pnpWorkbook.Workbook.Names["xreg_vra_nodea_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vra_nodeb_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_vra_nodec_hostname"].Value
            'vmListWsa'                         = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_hostname"].Value
            'antiAffinityRuleName'              = $pnpWorkbook.Workbook.Names["xreg_vra_anti_affinity_rule"].Value
            'drsGroupNameWsa'                   = $pnpWorkbook.Workbook.Names["xreg_wsa_vm_group_name"].Value
            'drsGroupNameVra'                   = $pnpWorkbook.Workbook.Names["xreg_vra_vm_group_name"].Value
            'drsVmGroupNameAz'                  = $pnpWorkbook.Workbook.Names["mgmt_az1_vm_group_name"].Value
            'vmToVmRuleNameWsa'                 = $pnpWorkbook.Workbook.Names["xreg_vra_vm_vm_rule"].Value
            'folderSuffix'                      = "-fd-workload"
            'resourcePoolSuffix'                = "-rp-workload"
            'stretchedCluster'                  = $pnpWorkbook.Workbook.Names["mgmt_stretched_cluster_chosen"].Value
            'consolidatedCluster'               = $pnpWorkbook.Workbook.Names["mgmt_consolidated_chosen"].Value
            'wsaFqdn'                           = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_fqdn"].Value
            'wsaUser'                           = $pnpWorkbook.Workbook.Names["local_admin_username"].Value
            'wsaPass'                           = $pnpWorkbook.Workbook.Names["local_admin_password"].Value
            'domainFqdn'                        = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
            'domainAlias'                       = $pnpWorkbook.Workbook.Names["region_ad_child_netbios"].Value
            'domainBindUserWsa'                 = $pnpWorkbook.Workbook.Names["child_svc_wsa_ad_user"].Value
            'domainBindPassWsa'                 = $pnpWorkbook.Workbook.Names["child_svc_wsa_ad_password"].Value
            'domainBindUserVsphere'             = $pnpWorkbook.Workbook.Names["child_svc_vsphere_ad_user"].Value
            'domainBindPassVsphere'             = $pnpWorkbook.Workbook.Names["child_svc_vsphere_ad_password"].Value
            'baseDnGroup'                       = $pnpWorkbook.Workbook.Names["child_ad_groups_ou"].Value
            'orgOwner'                          = $pnpWorkbook.Workbook.Names["group_gg_vra_org_owners"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'cloudAssemblyAdmins'               = $pnpWorkbook.Workbook.Names["group_gg_vra_cloud_assembly_admins"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'cloudAssemblyUsers'                = $pnpWorkbook.Workbook.Names["group_gg_vra_cloud_assembly_users"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'cloudAssemblyViewers'              = $pnpWorkbook.Workbook.Names["group_gg_vra_cloud_assembly_viewers"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'serviceBrokerAdmins'               = $pnpWorkbook.Workbook.Names["group_gg_vra_service_broker_admins"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'serviceBrokerUsers'                = $pnpWorkbook.Workbook.Names["group_gg_vra_service_broker_users"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'serviceBrokerViewers'              = $pnpWorkbook.Workbook.Names["group_gg_vra_service_broker_viewers"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'orchestratorAdmins'                = $pnpWorkbook.Workbook.Names["group_gg_vra_orchestrator_admins"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'orchestratorDesigners'             = $pnpWorkbook.Workbook.Names["group_gg_vra_orchestrator_designers"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'orchestratorViewers'               = $pnpWorkbook.Workbook.Names["group_gg_vra_orchestrator_viewers"].Value + "@" + $pnpWorkbook.Workbook.Names["child_dns_zone"].Value
            'adGroups'                          = "$($pnpWorkbook.Workbook.Names["group_gg_vra_org_owners"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_cloud_assembly_admins"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_cloud_assembly_users"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_cloud_assembly_viewers"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_service_broker_admins"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_service_broker_users"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_service_broker_viewers"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_orchestrator_admins"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_orchestrator_designers"].Value)", "$($pnpWorkbook.Workbook.Names["group_gg_vra_orchestrator_viewers"].Value)"
            'displayName'                       = $pnpWorkbook.Workbook.Names["xreg_vra_org_name"].Value
            'automationUser'                    = $pnpWorkbook.Workbook.Names["local_configadmin_username"].Value
            'automationPassword'                = $pnpWorkbook.Workbook.Names["local_configadmin_password"].Value
            'vsphereRoleNameAutomation'         = $pnpWorkbook.Workbook.Names["xreg_vra_vsphere_role_name"].Value
            'vsphereRoleNameOrchestrator'       = $pnpWorkbook.Workbook.Names["xreg_vro_vsphere_role_name"].Value
            'serviceAccountAutomation'          = $pnpWorkbook.Workbook.Names["user_svc_vra_vsphere"].Value
            'serviceAccountOrchestrator'        = $pnpWorkbook.Workbook.Names["user_svc_vro_vsphere"].Value
            'serviceAccountOrchestratorPass'    = $pnpWorkbook.Workbook.Names["svc_vro_vsphere_password"].Value
            'serviceAccountNsx'                 = $pnpWorkbook.Workbook.Names["user_svc_vra_nsx"].Value
            'nsxEdgeVmFolderSuffix'             = "-fd-edge"
            'localDatastoreFolderSuffix'        = "-fd-ds-local"
            'readOnlyDatastoreFolder'           = "-fd-ds-readonly"
            'capabilityTag'                     = $pnpWorkbook.Workbook.Names["xreg_vra_cloud_account_cloud_capability_tag"].Value
            'tagKey'                            = $pnpWorkbook.Workbook.Names["xreg_vra_cloud_account_region_capability_tag"].Value.Split(":")[-0]
            'tagValue'                          = $pnpWorkbook.Workbook.Names["xreg_vra_cloud_account_region_capability_tag"].Value.Split(":")[-1]
            'smtpServer'                        = $pnpWorkbook.Workbook.Names["smtp_server"].Value
            'emailAddress'                      = $pnpWorkbook.Workbook.Names["xreg_vra_smtp_sender_email_address"].Value
            'senderName'                        = $pnpWorkbook.Workbook.Names["xreg_vra_smtp_sender_name"].Value
            }
            Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
            $jsonObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonFile
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            Foreach ($jsonValue in $jsonInput.psobject.properties) {
                if ($jsonValue.value -eq "Value Missing" -or $null -eq $jsonValue.value ) {
                    $issueWithJson = $true
                }
            }
            if ($issueWithJson) {
                Show-PowerValidatedSolutionsOutput -type ERROR -message  "Creation of JSON Specification file for Private Cloud Automation, missing data: POST_VALIDATION_FAILED"
            } else { 
                Show-PowerValidatedSolutionsOutput -message  "Creation of JSON Specification file for Private Cloud Automation: SUCCESSFUL"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message  "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-PcaJsonSpec

Function Invoke-PcaDeployment {
    <#
        .SYNOPSIS
        End-to-end Deployment of Private Cloud Automation

        .DESCRIPTION
        The Invoke-PcaDeployment cmdlet is a single function to implement the configuration of the Private Cloud Automation
        for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-PcaDeployment -jsonFile .\pcaDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\"
        This example configures Private Cloud Automation using the JSON specification provided.

        .EXAMPLE
        Invoke-PcaDeployment -jsonFile .\pcaDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\" -useContentLibrary
        This example configures Private Cloud Automation using the JSON specification provided. and using a content library for VMware Aria Suite Lifecycle

        .PARAMETER jsonFile
        The path to the JSON specification file.

        .PARAMETER certificates
        The path to the certificates folder.

        .PARAMETER binaries
        The path to the binaries folder.

        .PARAMETER useContentLibrary
        Switch to indicate that a content library is being used for VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificates,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$binaries,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary
    )

    # Define Reusable Parameters
    $solutionName               = "Private Cloud Automation for VMware Cloud Foundation"
    $automationProductName      = "VMware Aria Automation"
    $orchestratorProductName    = "VMware Aria Automation Orchestrator"
    $lcmProductName             = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Deployment of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            $automationPem = $certificates + $jsonInput.certificateAlias + ".2.chain.pem"
            $rootCer = $certificates + "Root64.cer"
            if (Test-Path -Path $automationPem) {
                if (Test-Path -Path $rootCer) {
                    if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                        if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                            if (Get-VCFWsa) {
                                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                                    if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                        $allWorkloadDomains = Get-VCFWorkloadDomain
                                        $failureDetected = $false
                                        $automationVsphereTemplate = $pvsModulePath + "\vSphereRoles\" + "aria-automation-assembler-vsphere-integration.role"
                                        $orchestratorVsphereTemplate = $pvsModulePath + "\vSphereRoles\" + "aria-automation-orchestrator-vsphere-integration.role"

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Creating a vSphere Content Library for Operational Management"
                                            $StatusMsg = Add-ContentLibrary -Server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -Domain $jsonInput.mgmtSddcDomainName -ContentLibraryName $jsonInput.contentLibraryName -published -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                $automationOvaPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match "Prelude_VA"}).name
                                                if ((([regex]::Match(((Split-Path $automationOvaPath -leaf)), "(?<=-)\d+\.\d+\.\d+").Value) -notin (Get-vRSLCMProductVersion -productId vra))) {
                                                    Show-PowerValidatedSolutionsOutput -type ERROR -message "$automationProductName OVA ($binaryFile) does not match a supported version: PRE_VALIDATION_FAILED"; $failureDetected = $true
                                                } elseif (($automationOvaPath -match "Prelude_VA")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Importing $automationProductName OVA into vSphere Content Library"
                                                    $StatusMsg = Import-ContentLibraryItem -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibrary $jsonInput.contentLibraryName -file $automationOvaPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                } else {
                                                    Show-PowerValidatedSolutionsOutput -type ERROR -message "$automationProductName OVA ($automationOvaPath) File Not Found: PRE_VALIDATION_FAILED"
                                                }
                                            }
                                            $allDatacenters = Get-vRSLCMDatacenter
                                            foreach ($datacenter in $allDatacenters) {
                                                Sync-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid -vcenterName (Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid).vcenterName | Out-Null
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Adding the $automationProductName License to $lcmProductName"
                                            $StatusMsg = New-vRSLCMLockerLicense -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.licenseAlias -license $jsonInput.licenseKey -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Importing the Certificate for $automationProductName to $lcmProductName"
                                            $StatusMsg = Import-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -certChainPath $automationPem -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Adding the $automationProductName Password to $lcmProductName"
                                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.rootPasswordAlias -password $jsonInput.rootPassword  -userName $jsonInput.rootUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.xintPasswordAlias -password $jsonInput.xintPassword -userName $jsonInput.xintUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Deploying $automationProductName by Using $lcmProductName"
                                            if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                $StatusMsg = New-vRADeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -useContentLibrary -contentLibrary $jsonInput.contentLibraryName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            } else {
                                                $StatusMsg = New-vRADeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            }
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            if ( $StatusMsg -contains "FAILED") { Show-PowerValidatedSolutionsOutput -type ERROR -message "Deployment of $automationProductName failed"; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Creating a Virtual Machine and Template Folder for the $automationProductName Cluster Appliances"
                                            $StatusMsg = Add-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -folderName $jsonInput.vmFolder -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Moving the $automationProductName Cluster Appliances to the Dedicated Folder"
                                            $StatusMsg = Move-VMtoFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -vmList $jsonInput.vmList -folder $jsonInput.vmFolder -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg -match "SUCCESSFUL" ) { Show-PowerValidatedSolutionsOutput -message "Relocating $automationProductName Cluster Appliances to Dedicated Folder: SUCCESSFUL"  } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -yype ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Creating a Virtual Machine and Template Folder and a Resource Pool for the $automationProductName-Managed Workloads"
                                                    $StatusMsg = Add-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -folderName ($sddcDomain.name + $jsonInput.folderSuffix) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                    Foreach ($cluster in $sddcDomain.clusters) {
                                                        $StatusMsg = Add-ResourcePool -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -resourcePoolName (((Get-VCFCluster -id $cluster.id).name) + $jsonInput.resourcePoolSuffix) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                    }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Synchronizing the Active Directory Groups for $automationProductName in Workspace ONE Access"
                                            $StatusMsg = Add-WorkspaceOneDirectoryGroup -server $jsonInput.wsaFqdn -user $jsonInput.wsaUser -pass $jsonInput.wsaPass -domain $jsonInput.domainFqdn -bindUser $jsonInput.domainBindUserWsa -bindPass $jsonInput.domainBindPassWsa -baseDnGroup $jsonInput.baseDnGroup -adGroups $jsonInput.adGroups -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -type INFO -Message "Creating a VM Group and Define the Startup Order of the $automationProductName Cluster Appliances"
                                            $StatusMsg = Add-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameWsa -drsGroupVMs $jsonInput.vmListWsa -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameVra -drsGroupVMs $jsonInput.vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-VmStartupRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.vmToVmRuleNameWsa -vmGroup  $jsonInput.drsGroupNameVra -dependOnVmGroup $jsonInput.drsGroupNameWsa -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            if ($stretchedCluster -eq "Include") {
                                                Show-PowerValidatedSolutionsOutput -message "Adding the $automationProductName Cluster Appliances to the First Availability Zone VM Group"
                                                $StatusMsg = Add-VmGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -name $jsonInput.drsVmGroupNameAz -vmList $jsonInput.vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg"  } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring the Organization Name for $automationProductName"
                                            $StatusMsg = Update-vRAOrganizationDisplayName -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -displayName $jsonInput.displayName -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Assigning Organization and Service Roles to the Groups for $automationProductName"
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.orgOwner -orgRole org_owner -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.cloudAssemblyAdmins -orgRole org_member -serviceRole automationservice:cloud_admin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.cloudAssemblyUsers -orgRole org_member -serviceRole automationservice:user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif  ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.cloudAssemblyViewers -orgRole org_member -serviceRole automationservice:viewer -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.serviceBrokerAdmins -orgRole org_member -serviceRole catalog:admin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.serviceBrokerUsers -orgRole org_member -serviceRole catalog:user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.serviceBrokerViewers -orgRole org_member -serviceRole catalog:viewer -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.orchestratorAdmins -orgRole org_member -serviceRole orchestration:admin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.orchestratorDesigners -orgRole org_member -serviceRole orchestration:designer -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vRAGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPassword -displayName $jsonInput.orchestratorViewers -orgRole org_member -serviceRole orchestration:viewer -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Defining Custom Roles in vSphere for $automationProductName and $orchestratorProductName"
                                            $StatusMsg = Add-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName -roleName $jsonInput.vsphereRoleNameAutomation -template $automationVsphereTemplate -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Add-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName -roleName $jsonInput.vsphereRoleNameOrchestrator -template $orchestratorVsphereTemplate -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring Service Account Permissions for the $automationProductName and $orchestratorProductName Integrations to vSphere"
                                            $StatusMsg = Add-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -principal $jsonInput.serviceAccountAutomation -role $jsonInput.vsphereRoleNameAutomation -propagate true -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true } 
                                            $StatusMsg = Add-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName -domain $jsonInput.domainFqdn -domainBindUser $jsonInput.domainBindUserVsphere -domainBindPass $jsonInput.domainBindPassVsphere -principal $jsonInput.serviceAccountOrchestrator -role $jsonInput.vsphereRoleNameOrchestrator -propagate true -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Restricting the $automationProductName and $orchestratorProductName Service Accounts Access to the Management Domain"
                                            $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $jsonInput.mgmtSddcDomainName -principal $jsonInput.serviceAccountAutomation "NoAccess" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $jsonInput.mgmtSddcDomainName -principal $jsonInput.serviceAccountOrchestrator -role "NoAccess" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Creating a Virtual Machine and Template Folder for the $automationProductName Workload Virtual Machines"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Creating a Virtual Machine and Template Folder for the $automationProductName Workload Virtual Machines for Workload Domain ($($sddcDomain.name))"
                                                    $StatusMsg = Add-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -folderName ($sddcDomain.name + $jsonInput.nsxEdgeVmFolderSuffix) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Creating Local Storage Folders for the $automationProductName Workload Virtual Machines"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Creating a Local Storage Folder for the $automationProductName Workload Virtual Machines for Workload Domain ($($sddcDomain.name))"
                                                    $StatusMsg = Add-StorageFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -foldername ($sddcDomain.name + $jsonInput.localDatastoreFolderSuffix) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                    Show-PowerValidatedSolutionsOutput -message "Creating a Read-Only Storage Folder for the $automationProductName Workload Virtual Machines for Workload Domain ($($sddcDomain.name))"
                                                    $StatusMsg = Add-StorageFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -foldername ($sddcDomain.name + $jsonInput.readOnlyDatastoreFolder) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Restricting the $automationProductName and $orchestratorProductName Service Accounts Access to Virtual Machine and Datastore Folders in the VI Workload Domain"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Restricting the $automationProductName and $orchestratorProductName Service Accounts Access to Virtual Machine and Datastore Folders in Workload Domain ($($sddcDomain.name))"
                                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $sddcDomain.name -principal $jsonInput.serviceAccountAutomation -role "NoAccess" -folderName $jsonInput.nsxEdgeVmFolderSuffix -folderType "VM" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $sddcDomain.name -principal $jsonInput.serviceAccountAutomation -role "NoAccess" -folderName $jsonInput.localDatastoreFolderSuffix -folderType "Datastore" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $sddcDomain.name -principal $jsonInput.serviceAccountAutomation -role "NoAccess" -folderName $jsonInput.readOnlyDatastoreFolder -folderType "Datastore" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $sddcDomain.name -principal $jsonInput.serviceAccountOrchestrator -role "NoAccess" -folderName $jsonInput.nsxEdgeVmFolderSuffix -folderType "VM" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $sddcDomain.name -principal $jsonInput.serviceAccountOrchestrator -role "NoAccess" -folderName $jsonInput.localDatastoreFolderSuffix -folderType "Datastore" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                                    $StatusMsg = Set-vCenterPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainAlias -workloadDomain $sddcDomain.name -principal $jsonInput.serviceAccountOrchestrator -role "NoAccess" -folderName $jsonInput.readOnlyDatastoreFolder -folderType "Datastore" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -Message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring Service Account Permissions for the $automationProductName to NSX-T Data Center Integration on the VI Workload Domain NSX Manager Cluster"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Configuring Service Account Permissions for the $automationProductName to NSX-T Data Center Integration on the Workload Domain ($($sddcDomain.name))"
                                                    $StatusMsg = Add-NsxtVidmRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -type user -principal $jsonInput.serviceAccountNsx -role enterprise_admin -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Adding Cloud Accounts for the VI Workload Domains to $automationProductName"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Adding Cloud Accounts for the Workload Domains ($($sddcDomain.name)) to $automationProductName"
                                                    $StatusMsg = New-vRACloudAccount -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.wldSddcDomainName -vraUser $jsonInput.vraUser -vraPass $jsonInput.vraPass -capabilityTab $jsonInput.capabilityTag -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -Message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring the Cloud Zones in $automationProductName"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Configuring the Cloud Zones in $automationProductName for Workload Domain ($($sddcDomain.name))"
                                                    $StatusMsg = Update-vRACloudAccountZone -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPass -tagKey $jsoninput.tagKey -tagValue $jsonInput.tagValue -folder ($sddcDomain.name + $jsonInput.folderSuffix) -resourcePool ($sddcDomain.name + $jsonInput.resourcePoolSuffix) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configure Email Alerts in Service Broker"
                                            $StatusMsg = Add-vRANotification -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPass -smtpServer $jsonInput.smtpServer -emailAddress $jsonInput.emailAddress -sender $jsonInput.senderName -connection NONE -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -Message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Import the Trusted Certificates into $orchestratorProductName"
                                            $StatusMsg = Add-vROTrustedCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPass -certFile $rootCer -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -Message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Attempting to Add the VI Workload Domain vCenter Server to $orchestratorProductName"
                                            foreach ($sddcDomain in $allWorkloadDomains) {
                                                if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                                    $StatusMsg = Add-vROvCenterServer -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -vraUser $jsonInput.automationUser -vraPass $jsonInput.automationPass -vcUser ($jsonInput.serviceAccountOrchestrator + "@" + $jsonInput.domainFqdn) -vcPass $jsonInput.serviceAccountOrchestratorPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }
                                    }
                                }
                            } else {
                                Show-PowerValidatedSolutionsOutput -type ERROR -Message "Unable to find Workspace ONE Access in ($($jsonInput.sddcManagerFqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            } else {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Certificate File (.pem) for $automationProductName ($automationPem): File Not Found"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $solutionName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-CatchWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-PcaDeployment

Function Invoke-UndoPcaDeployment {
    <#
        .SYNOPSIS
        End-to-end removal of Private Cloud Automation

        .DESCRIPTION
        The Invoke-UndoPcaDeployment cmdlet is a single function to removal the configuration of the Private Cloud Automation
        for VMware Cloud Foundation validated solution.

        .EXAMPLE
        Invoke-UndoPcaDeployment -jsonFile .\pcaDeploySpec.json
        This example removal Private Cloud Automation using the JSON specification provided.

        .PARAMETER jsonFile
        The JSON specification file for the Private Cloud Automation for VMware Cloud Foundation validated solution.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    # Define Reusable Parameters
    $solutionName               = "Private Cloud Automation for VMware Cloud Foundation"
    $automationProductName      = "VMware Aria Automation"
    $orchestratorProductName    = "VMware Aria Automation Orchestrator"
    $lcmProductName             = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Removal of $solutionName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domainType "MANAGEMENT")) {
                        if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $allWorkloadDomains = Get-VCFWorkloadDomain
                                $failureDetected = $false

                                if (!$failureDetected) {
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                            Show-PowerValidatedSolutionsOutput -message "Removing Virtual Machine and Template Folder and Resource Pool for the $automationProductName-Managed Workloads"
                                            $StatusMsg = Undo-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -foldername ($sddcDomain.name + $jsonInput.folderSuffix) -folderType VM -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            Foreach ($cluster in $sddcDomain.clusters) {
                                                $StatusMsg = Undo-ResourcePool -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -resourcePoolName (((Get-VCFCluster -id $cluster.id).name) + $jsonInput.resourcePoolSuffix) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Virtual Machine and Template Folder for the $automationProductName Workload Virtual Machines"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                            Show-PowerValidatedSolutionsOutput -message "Removing Virtual Machine and Template Folder for the $automationProductName Workload Virtual Machines for Workload Domain ($($sddcDomain.name))"
                                            $StatusMsg = Undo-VMFolder -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -foldername ($sddcDomain.name + $jsonInput.nsxEdgeVmFolderSuffix) -folderType VM -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Service Account Permissions for the $automationProductName from NSX-T Data Center Integration on the VI Workload Domain NSX Manager Cluster"
                                    foreach ($sddcDomain in $allWorkloadDomains) {
                                        if ($jsonInput.consolidatedCluster -eq "Include" -or ($jsonInput.consolidatedCluster -eq "Exclude" -and $sddcDomain.type -eq "VI")) {
                                            Show-PowerValidatedSolutionsOutput -message "Removeing Service Account Permissions for the $automationProductName to NSX-T Data Center Integration on the Workload Domain ($($sddcDomain.name))"
                                            $StatusMsg = Undo-NsxtVidmRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $sddcDomain.name -principal $jsonInput.serviceAccountNsx -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Active Directory Groups for $automationProductName from Workspace ONE Access"
                                    $StatusMsg = Undo-WorkspaceOneDirectoryGroup -server $jsonInput.wsaFqdn -user $jsonInput.wsaUser -pass $jsonInput.wsaPass -domain $jsonInput.domainFqdn -bindUser $jsonInput.domainBindUserWsa -bindPass $jsonInput.domainBindPassWsa -baseDnGroup $jsonInput.baseDnGroup -adGroups $jsonInput.adGroups -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing a VM Group and Startup Order of the $automationProductName Cluster Appliances"
                                    $StatusMsg = Undo-VmStartupRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.vmToVmRuleNameWsa -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameVra -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                            foreach ($vm in ($jsonInput.vmList -Split ',')) {
                                                if (Get-VM -name $vm -ErrorAction SilentlyContinue ) {
                                                    Get-VM -name $vm | Stop-VM -RunAsync -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                    Do {$powerState = (Get-VM -name $vm | Select-Object PowerState).PowerState } Until ($powerState -eq "PoweredOff")
                                                    Get-VM -name $vm | Remove-VM -DeletePermanently -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                }
                                            }
                                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                            Show-PowerValidatedSolutionsOutput -message "Deleting $automationProductName from $lcmProductName"
                                            $StatusMsg = Undo-vRADeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -environmentName $jsonInput.environmentName -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing the $automationProductName Password from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.rootPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.xintPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing the Certificate for $automationProductName from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing the $automationProductName License from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerLicense -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.licenseAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Service Account Permissions for the $automationProductName and $orchestratorProductName Integrations to vSphere"
                                    $StatusMsg = Undo-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName -domain $jsonInput.domainFqdn -principal $jsonInput.serviceAccountAutomation -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true } 
                                    $StatusMsg = Undo-vCenterGlobalPermission -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName -domain $jsonInput.domainFqdn -principal $jsonInput.serviceAccountOrchestrator -type user -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Custom Roles from vSphere for $automationProductName and $orchestratorProductName"
                                    $StatusMsg = Undo-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName-roleName $jsonInput.vsphereRoleNameAutomation -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-vSphereRole -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -sddcDomain $jsonInput.mgmtSddcDomainName-roleName $jsonInput.vsphereRoleNameOrchestrator -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $solutionName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-CatchWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-UndoPcaDeployment

Function Export-vRAJsonSpec {
    <#
        .SYNOPSIS
        Create VMware Aria Automation Deployment JSON specification

        .DESCRIPTION
        The Export-vRAJsonSpec cmdlet creates the JSON specification file using the Private Cloud Automation JSON
        specification file generated from the Planning and Preparation Workbook to deploy VMware Aria Automation using
        VMware Aria Suite Lifecycle:
        - Validates that network connectivity is available to VMware Aria Suite Lifecycle
        - Makes a connection to the VMware Aria Suite Lifecycle instance and validates that authentication possible
        - Generates the JSON specification file using the Planning and Preparation workbook and details from VMware Aria Suite Lifecycle

        .EXAMPLE
        Export-vRAJsonSpec -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\pcaDeploySpec.json
        This example creates a JSON deployment specification in the current folder for VMware Aria Automation using the Private Cloud Automation JSON specification

        .EXAMPLE
        Export-vRAJsonSpec -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\pcaDeploySpec.json -outputPath .\myJsons
        This example creates a JSON deployment specification in the folder defined for VMware Aria Automation using the Private Cloud Automation JSON specification

        .PARAMETER server
        The fully qualified domain name of the VMware Cloud Foundation SDDC Manager

        .PARAMETER user
        The username of the VMware Cloud Foundation SDDC Manager

        .PARAMETER pass
        The password of the VMware Cloud Foundation SDDC Manager

        .PARAMETER jsonFile
        The JSON specification file for the Private Cloud Automation for VMware Cloud Foundation validated solution

        .PARAMETER outputPath
        The folder path to store the JSON specification file for the Private Cloud Automation for VMware Cloud Foundation validated solution

        .PARAMETER customVersion
        The version of the Private Cloud Automation for VMware Cloud Foundation validated solution to deploy

        .PARAMETER useContentLibrary
        Use a Content Library to store the Private Cloud Automation for VMware Cloud Foundation validated solution OVA

        .PARAMETER contentLibrary
        The name of the Content Library to store the Private Cloud Automation for VMware Cloud Foundation validated solution OVA.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$outputPath,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                        $vcfVersion = ((Get-VCFManager).version -Split ('\.\d{1}\-\d{8}')) -split '\s+' -match '\S'
                        if ($PsBoundParameters.ContainsKey("outputPath")) {
                            $jsonSpecFileName = $outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "automationDeploySpec.json")
                        } else {
                            $jsonSpecFileName = (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "automationDeploySpec.json")
                        }
                        if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                if ($automationLicense = Get-vRSLCMLockerLicense | Where-Object {$_.key -eq $jsonInput.licenseKey}) { 
                                    if ($automationCertificate =Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $jsonInput.certificateAlias}) {
                                        if ($adminPassword = Get-vRSLCMLockerPassword -alias $jsonInput.xintPasswordAlias) {
                                            if ($automationRootPassword = Get-vRSLCMLockerPassword -alias $jsonInput.rootPasswordAlias) {
                                                if ($vcfVersion -ge "4.5.0") {
                                                    $vcCredentials = Get-vRSLCMLockerPassword | Where-Object {$_.userName -match (($jsonInput.vcenterFqdn).Split(".")[0] + "@vsphere.local")}
                                                } else {
                                                    $vcCredentials = Get-vRSLCMLockerPassword -alias (($jsonInput.vcenterFqdn).Split(".")[0] + "-" + $jsonInput.vcenterDatacenter)
                                                }
                                                if ($datacenterName = Get-vRSLCMDatacenter | Where-Object {$_.dataCenterName -eq $jsonInput.datacenter}) {
                                                    $xintEnvironment = Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $jsonInput.environmentName}
                                                    if (!$PsBoundParameters.ContainsKey("customVersion")) {
                                                        if ($vcfVersion -eq "4.3.0") { $vraVersion = "8.4.1" }
                                                        if ($vcfVersion -eq "4.3.1") { $vraVersion = "8.5.0" }
                                                        if ($vcfVersion -eq "4.4.0") { $vraVersion = "8.6.2" }
                                                        if ($vcfVersion -eq "4.4.1") { $vraVersion = "8.6.2" }
                                                        if ($vcfVersion -eq "4.5.0") { $vraVersion = "8.8.2" }
                                                        if ($vcfVersion -eq "4.5.1") { $vraVersion = "8.14.0" }
                                                        if ($vcfVersion -eq "4.5.2") { $vraVersion = "8.14.0" }
                                                        if ($vcfVersion -eq "5.0.0") { $vraVersion = "8.14.0" }
                                                        if ($vcfVersion -eq "5.1.0") { $vraVersion = "8.14.0" }
                                                    } else {
                                                        $vraVersion = $customVersion
                                                    }

                                                    ### Generate the Properties Details
                                                    if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                        $contentLibraryItems = ((Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenterName.dataCenterVmid -vcenterName ($jsonInput.vcenterFqdn).Split(".")[0]).contentLibraries | Where-Object {$_.contentLibraryName -eq $contentLibrary}).contentLibraryItems
                                                        if ($contentLibraryItems) {
                                                            $contentLibraryItemId = ($contentLibraryItems | Where-Object {$_.contentLibraryItemName -match "Prelude_VA-$vraVersion"}).contentLibraryItemId
                                                        } else {
                                                            Write-Error "Unable to find vSphere Content Library ($contentLibrary) or Content Library Item in VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"
                                                            Break
                                                        }
                                                    }

                                                    $infrastructurePropertiesObject = @()
                                                    $infrastructurePropertiesObject += [pscustomobject]@{
                                                        'acceptEULA'            = "true"
                                                        'enableTelemetry'        = "true"
                                                        'regionName'            = "default"
                                                        'zoneName'                = "default"
                                                        'dataCenterVmid'        = $datacenterName.dataCenterVmid
                                                        'vCenterName'            = ($jsonInput.vcenterFqdn).Split(".")[0]
                                                        'vCenterHost'            = $jsonInput.vcenterFqdn
                                                        'vcUsername'            = $vcCredentials.userName
                                                        'vcPassword'            = ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                        'defaultPassword'        = ("locker:password:" + $($adminPassword.vmid) + ":" + $($adminPassword.alias))
                                                        'certificate'            = ("locker:certificate:" + $($automationCertificate.vmid) + ":" + $($automationCertificate.alias))
                                                        'cluster'                = ($jsonInput.vcenterDatacenter + "#" + $jsonInput.vcenterCluster)
                                                        'storage'                =  $jsonInput.vcenterDatastore
                                                        'diskMode'                = "thin"
                                                        'network'                = $jsonInput.network
                                                        'masterVidmEnabled'        = "false"
                                                        'dns'                    = $jsonInput.dns
                                                        'domain'                = $jsonInput.domain
                                                        'gateway'                = $jsonInput.gateway
                                                        'netmask'                = $jsonInput.netmask
                                                        'searchpath'            = $jsonInput.searchpath
                                                        'timeSyncMode'            = "ntp"
                                                        'ntp'                    = $jsonInput.ntp
                                                        'vcfProperties'            = '{"vcfEnabled":true,"sddcManagerDetails":[{"sddcManagerHostName":"' + $jsonInput.sddcManagerFqdn + '","sddcManagerName":"default","sddcManagerVmid":"default"}]}'
                                                    }

                                                    $infrastructureObject = @()
                                                    $infrastructureObject += [pscustomobject]@{
                                                        'properties'    = ($infrastructurePropertiesObject | Select-Object -Skip 0)
                                                    }

                                                    $productPropertiesObject = @()
                                                    $productPropertiesObject += [pscustomobject]@{
                                                        'certificate'                    = ("locker:certificate:" + $($automationCertificate.vmid) + ":" + $($automationCertificate.alias))
                                                        'productPassword'                = ("locker:password:" + $($automationRootPassword.vmid) + ":" + $($automationRootPassword.alias))
                                                        'licenseRef'                    = ("locker:license:" + $($automationLicense.vmid) + ":" + $($automationLicense.alias))
                                                        'fipsMode'                        = "false"
                                                        'timeSyncMode'                    = "ntp"
                                                        'ntp'                            = $jsonInput.ntp
                                                        'affinityRule'                    = "true"
                                                        'configureAffinitySeparateAll'  = "true"
                                                        'contentLibraryItemId'          = $contentLibraryItemId
                                                        'nodeSize'                        = $jsonInput.nodeSize.ToLower()
                                                        'vraK8ServiceCidr'              = $jsonInput.vraK8ServiceCidr
                                                        'vraK8ClusterCidr'              = $jsonInput.vraK8ClusterCidr
                                                        'clusterFqdn'                   = $jsonInput.clusterFqdn
                                                    }

                                                    #### Generate VMware Aria Automation Cluster Details
                                                    $clusterVipProperties = @()
                                                    $clusterVipProperties += [pscustomobject]@{
                                                        'controllerType'        = "NSX_T"
                                                        'hostName'                = $jsonInput.clusterFqdn
                                                    }
                                                    $clusterVipsObject = @()
                                                    $clusterVipsObject += [pscustomobject]@{
                                                        'type'            = "vra-va"
                                                        'properties'    = ($clusterVipProperties | Select-Object -Skip 0)
                                                    }
                                                    $clusterObject = @()
                                                    $clusterObject += [pscustomobject]@{
                                                    'clusterVips'    = $clusterVipsObject
                                                    }

                                                    #### Generate VMware Aria Automation Node Details
                                                    $vraPrimaryProperties = @()
                                                    $vraPrimaryProperties += [pscustomobject]@{
                                                        'hostName'          = $jsonInput.vraNodeaFqdn
                                                        'vmName'            = $jsonInput.vraNodeaHostname
                                                        'ip'                = $jsonInput.vraNodeaIp
                                                    }
                                                    $vraSecondary1Properties = @()
                                                    $vraSecondary1Properties += [pscustomobject]@{
                                                        'hostName'          = $jsonInput.vraNodebFqdn
                                                        'vmName'            = $jsonInput.vraNodebHostname
                                                        'ip'                = $jsonInput.vraNodebIp
                                                    }
                                                    $vraSecondary2Properties = @()
                                                    $vraSecondary2Properties += [pscustomobject]@{
                                                        'hostName'          = $jsonInput.vraNodecFqdn
                                                        'vmName'            = $jsonInput.vraNodecHostname
                                                        'ip'                = $jsonInput.vraNodecIp
                                                    }
                                                    $nodesObject = @()
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'            = "vrava-primary"
                                                        'properties'    = ($vraPrimaryProperties | Select-Object -Skip 0)
                                                    }
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'            = "vrava-secondary"
                                                        'properties'    = ($vraSecondary1Properties | Select-Object -Skip 0)
                                                    }
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'            = "vrava-secondary"
                                                        'properties'    = ($vraSecondary2Properties | Select-Object -Skip 0)
                                                    }

                                                    #### Generate the VMware Aria Automation Properties Section
                                                    $productsObject = @()
                                                    $productsObject += [pscustomobject]@{
                                                        'id'             = "vra"
                                                        'version'        = $vraVersion
                                                        'properties'    = ($productPropertiesObject  | Select-Object -Skip 0)
                                                        'clusterVIP'    = ($clusterObject  | Select-Object -Skip 0)
                                                        'nodes'            = $nodesObject    
                                                    }
                                                    if (!($xintEnvironment)) { 
                                                        $automationDeploymentObject = @()
                                                        $automationDeploymentObject += [pscustomobject]@{
                                                            'environmentName'       = $jsonInput.environmentName
                                                            'infrastructure'        = ($infrastructureObject  | Select-Object -Skip 0)
                                                            'products'              = $productsObject     
                                                        }
                                                    } else {
                                                        $automationDeploymentObject = @()
                                                        $automationDeploymentObject += [pscustomobject]@{
                                                            'environmentId'         = $xintEnvironment.environmentId
                                                            'environmentName'       = $jsonInput.environmentName
                                                            'infrastructure'        = ($infrastructureObject  | Select-Object -Skip 0)
                                                            'products'              = $productsObject     
                                                        }
                                                    }
                                                    $automationDeploymentObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonSpecFileName
                                                    Write-Output "Creation of VMware Aria Suite Lifecycle Deployment JSON Specification file for VMware Aria Automation: SUCCESSFUL"
                                                } else {
                                                    Write-Error "Datacenter Provided ($($jsonInput.datacenter)) does not exist: PRE_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Error "Root Password with alias ($($jsonInput.rootPasswordAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Admin Password with alias ($($jsonInput.xintPasswordAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Certificate with alias ($($jsonInput.certificateAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "License with alias ($($jsonInput.licenseAlias)) not found in the VMware Aria Suite Lifecycle Locker: PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for Private Cloud Automaton ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-vRAJsonSpec

Function New-vRADeployment {
    <#
        .SYNOPSIS
        Deploy VMware Aria Automation to VMware Aria Suite Lifecycle

        .DESCRIPTION
        The New-vRADeployment cmdlet deploys VMware Aria Automation via VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has not been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Requests a new deployment of VMware Aria Automation

        .EXAMPLE
        New-vRADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\pcaDeploySpec.json -outputPath .\
        This example starts a deployment of VMware Aria Automation using the JSON Specification for VMware Aria Automation

        .EXAMPLE
        New-vRADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\deplyPcaSpec.json -customVersion 8.10.0
        This example starts a deployment of VMware Aria Automation using a custom version and the JSON Specification for VMware Aria Automation

        .EXAMPLE
        New-vRADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\deplyPcaSpec.json -useContentLibrary -contentLibrary Operations
        This example starts a deployment of VMware Aria Automation using the JSON Specification for VMware Aria Automation and deploys the OVAs from a vSphere Content Library

        .EXAMPLE
        New-vRADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\deplyPcaSpec.json -monitor
        This example starts a deployment of VMware Aria Automation using the JSON Specification for VMware Aria Automation and monitors the request.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                        if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $commandSwitch = ""
                                if ($PsBoundParameters.ContainsKey("customVersion")) {
                                    $commandSwitch = $commandSwitch + " -customVersion $customVersion"
                                }
                                if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                    $commandSwitch = $commandSwitch + " -useContentLibrary -contentLibrary $contentLibrary"
                                }
                                $outputPath = ($outputPath = Split-Path $jsonFile -Parent) + "\"
                                Invoke-Expression "Export-vRAJsonSpec -server $server -user $user -pass $pass -jsonFile $jsonFile -outputPath $outputPath $($commandSwitch) | Out-Null"
                                $json = (Get-Content -Raw ($outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "automationDeploySpec.json")))
                                $jsonSpec = $json | ConvertFrom-Json
                                $pcaJsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
                                if (!(((Get-vRSLCMLoadbalancer -type NSX_T) | Where-Object {$_.loadBalancerDetails -match $pcaJsonInput.clusterFqdn}))) {
                                    New-vRSLCMLoadbalancer -type NSX_T -loadBalancerIp $pcaJsonInput.clusterIp -loadBalancerFqdn $pcaJsonInput.clusterFqdn | Out-Null
                                }
                                if (!((Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $jsonSpec.environmentName}).products.id -contains $jsonSpec.products.id)) {
                                    if (Get-vRSLCMLockerPassword -alias $($jsonSpec.products.properties.productPassword.Split(":")[3])) {
                                        if (Get-vRSLCMLockerCertificate | Where-Object {$_.alias -Match $($jsonSpec.products.properties.certificate.Split(":")[3])}) {
                                            if (Get-vRSLCMLockerLicense | Where-Object {$_.alias -eq $($jsonSpec.products.properties.licenseRef.Split(":")[3])}) {
                                                if ($jsonSpec.environmentId) {
                                                    $newRequest = Add-vRSLCMEnvironment -json $json -environmentId $jsonSpec.environmentId -addProduct
                                                } else {
                                                    $newRequest = Add-vRSLCMEnvironment -json $json
                                                }
                                                if ($newRequest) {
                                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                                        Start-Sleep 10
                                                        Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                                    } else {
                                                        Write-Output "Deployment Request for VMware Aria Automation Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                                    }
                                                } else {
                                                    Write-Error "Request to deploy VMware Aria Automation failed, check the VMware Aria Suite Lifecycle UI"
                                                }
                                            } else {
                                                Write-Error "License in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.licenseRef.Split(":")[3])), does not exist: FAILED"
                                            }
                                        } else {
                                            Write-Error "Certificate in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.certificate.Split(":")[3])), does not exist: FAILED"
                                        }
                                    } else {
                                        Write-Error "Password in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.productPassword.Split(":")[3])), does not exist: FAILED"
                                    }
                                } else {
                                    Write-Warning "VMware Aria Automation in environment ($($jsonSpec.environmentName)) on VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already exists: SKIPPED"
                                }
                            }
                        }
                    } 
                }
            }
        } else {
            Write-Error "JSON Specification file for Private Cloud Automaton ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-vRADeployment

Function Undo-vRADeployment {
    <#
        .SYNOPSIS
        Remove the VMware Aria Automation from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-vRADeployment cmdlet removes VMware Aria Automation from VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment exist in VMware Aria Suite Lifecycle
        - Requests a the deletion of VMware Aria Automation from VMware Aria Suite Lifecycle

        .EXAMPLE
        Undo-vRADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName xint-env
        This example starts a removal of VMware Aria Automation from VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER environmentName
        The VMware Aria Automation Environment Name.

        .PARAMETER monitor
        Monitor the VMware Aria Suite Lifecycle request.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName -and $_.products.id -eq 'vra'}) {
                                $newRequest = Remove-vRSLCMEnvironment -environmentId (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName}).environmentId -productId vra -ErrorAction SilentlyContinue
                                if ($newRequest) {
                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                        Start-Sleep 10
                                        $status = Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                        if (!(Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName -and $_.products.id -eq 'vra'})) {
                                            if ($status -match "COMPLETED") {
                                                Write-Output "Removal of VMware Aria Automation from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removal of VMware Aria Automation from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Removal of VMware Aria Automation from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Output "Removal request of VMware Aria Automation Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                    }
                                } else {
                                    Write-Error "Removal request of VMware Aria Automation failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Environment with name ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already removed: SKIPPED"
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRADeployment

Function Update-vRAOrganizationDisplayName {
    <#
        .SYNOPSIS
        Configures the organization name.

        .DESCRIPTION
        The Update-vRAOrganizationDisplayName cmdlet configures the organization display name in VMware Aria Automation. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Verifies if the organization name is already configured based on the input
        - Configures the organization name

        .EXAMPLE
        Update-vRAOrganizationDisplayName -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -displayName "Rainpole" -vraUser configadmin -vraPass VMw@re1!
        This example configures the organization display name as 'Rainpole'.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER displayName
        The organization display name.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$displayName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vraPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            $orgId = (Get-vRAOrganizationId).Split("orgs/")[-1]
                            if (!((Get-vRAOrganizationDisplayName -orgId $orgId).displayname -eq $displayName)) {
                                Set-vRAOrganizationDisplayName -orgId $orgId -displayName $displayName | Out-Null
                                if ((Get-vRAOrganizationDisplayName -orgId $orgId).displayname -eq $displayName) {
                                    Write-Output "Updating Organization Display Name in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)): SUCCESSFUL"
                                } else {
                                    Write-Error "Updating Organization Display Name in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)): FAILED"
                                }
                            } else {
                                Write-Warning "Updating Organization Display Name in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)), already defined: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vRAOrganizationDisplayName

Function New-vRACloudAccount {
    <#
        .SYNOPSIS
        Creates vSphere and NSX Cloud Accounts.

        .DESCRIPTION
        The New-vRACloudAccount cmdlet creates the vSphere and NSX Cloud Accounts for a Workload Domain in VMware Aria
        Automation. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Retrives details from SDDC Manager for the vCenter Server and NSX Manager cluster
        - Adds a Cloud Account for vCenter Server and NSX Manager cluster

        .EXAMPLE
        New-vRACloudAccount -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -vraUser configadmin -vraPass VMw@re1! -capabilityTab private
        This example creates vSphere and NSX Cloud Accounts in VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.

        .PARAMETER capabilityTab
        The capability tag.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$capabilityTab
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                                $vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain
                                $vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain
                                if (!(Get-vRACloudAccount -type vsphere | Where-object {$_.name -eq $($vcfVcenterDetails.vmName)})) {
                                    Connect-VIServer -Server $vcfVcenterDetails.fqdn -User $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass | Out-Null
                                    if ($DefaultVIServer.Name -eq $($vcfVcenterDetails.fqdn)) {
                                        $dataCenterMoref = (Get-View -Server $($vcfVcenterDetails.fqdn) -viewtype Datacenter).MoRef
                                        $vcenterCloudAccount = '{
                                            "hostName": "'
 + $($vcfVcenterDetails.fqdn) + '",
                                            "acceptSelfSignedCertificate": true,
                                            "username": "'
 + $($vcfVcenterDetails.ssoAdmin) + '",
                                            "password": "'
 + $($vcfVcenterDetails.ssoAdminPass) + '",
                                            "dcId": "onprem",
                                            "createDefaultZones": true,
                                            "name": "'
 + $($vcfVcenterDetails.vmName) + '",
                                            "regionIds": [ "'
 + $($dataCenterMoref.type) + ":" + $($dataCenterMoref.value) +'" ],
                                            "tags": [ { "key": "'
 + $capabilityTag + '", "value": "" } ]
                                        }'

                                        Add-vRACloudAccount -type vsphere -json $vcenterCloudAccount | Out-Null
                                        if (Get-vRACloudAccount -type vsphere | Where-object {$_.name -eq $($vcfVcenterDetails.vmName)}) {
                                            Write-Output "Creating vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to connect to vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                                    }
                                    Disconnect-VIServer $($vcfVcenterDetails.fqdn) -Confirm:$false -WarningAction SilentlyContinue
                                } else {
                                    Write-Warning "Creating vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($vcfVcenterDetails.fqdn)), already exists: SKIPPED"
                                }
                                if (!(Get-vRACloudAccount -type nsx-t | Where-object {$_.name -eq ($vcfNsxtDetails.fqdn).Split(".")[0]})) {
                                    $nsxtCloudAccount = '{
                                        "hostName": "'
 + $($vcfNsxtDetails.fqdn) + '",
                                        "acceptSelfSignedCertificate": true,
                                        "password": "'
 + $($vcfNsxtDetails.adminPass) + '",
                                        "name": "'
 + ($vcfNsxtDetails.fqdn).Split(".")[0] + '",
                                        "username": "'
 + $($vcfNsxtDetails.adminUser) + '",
                                        "associatedCloudAccountIds": [ "'
 + (Get-vRACloudAccount -type vsphere | Where-Object {$_.name -eq $vcfVcenterDetails.vmName}).id + '" ],
                                        "tags": [ { "key": "'
 + $capabilityTag + '", "value": "" } ]
                                    }'

                                    Add-vRACloudAccount -type nsx-t -json $nsxtCloudAccount | Out-Null
                                    if (Get-vRACloudAccount -type nsx-t | Where-object {$_.name -eq ($vcfNsxtDetails.fqdn).Split(".")[0]}) {
                                        Write-Output "Creating NSX Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($(($vcfNsxtDetails.fqdn).Split(".")[0])): SUCCESSFUL"
                                    } else {
                                        Write-Error "Creating NSX Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($(($vcfNsxtDetails.fqdn).Split(".")[0])): POST_VALIDATED_FAILED"
                                    }
                                } else {
                                    Write-Warning "Creating NSX Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($(($vcfNsxtDetails.fqdn).Split(".")[0])), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-vRACloudAccount

Function Undo-vRACloudAccount {
    <#
        .SYNOPSIS
        Removes the vSphere and NSX Cloud Accounts.

        .DESCRIPTION
        The Undo-vRACloudAccount cmdlet removes the vSphere and NSX Cloud Accounts for a Workload Domain in VMware
        Aria Automation. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Retrives details from SDDC Manager for the vCenter Server and NSX Manager cluster
        - Removes the Cloud Accounts for vCenter Server and NSX Manager cluster

        .EXAMPLE
        Undo-vRACloudAccount -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -vraUser configadmin -vraPass VMw@re1!
        This example creates vSphere and NSX Cloud Accounts in VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vraPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                                $vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain
                                $vcfNsxtDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain
                                if (Get-vRACloudAccount -type nsx-t | Where-object {$_.name -eq ($vcfNsxtDetails.fqdn).Split(".")[0]}) {
                                    Remove-vRACloudAccount -id (Get-vRACloudAccount -type nsx-t | Where-object {$_.name -eq ($vcfNsxtDetails.fqdn).Split(".")[0]}).id | Out-Null
                                    if (!(Get-vRACloudAccount -type nsx-t | Where-object {$_.name -eq ($vcfNsxtDetails.fqdn).Split(".")[0]})) {
                                        Write-Output "Removing NSX Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($(($vcfNsxtDetails.fqdn).Split(".")[0])): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing NSX Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($(($vcfNsxtDetails.fqdn).Split(".")[0])): POST_VALIDATED_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing NSX Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($(($vcfNsxtDetails.fqdn).Split(".")[0])), does not exist: SKIPPED"
                                }
                                if (Get-vRACloudAccount -type vsphere | Where-object {$_.name -eq $($vcfVcenterDetails.vmName)}) {
                                    Remove-vRACloudAccount -id (Get-vRACloudAccount -type vsphere | Where-object {$_.name -eq $($vcfVcenterDetails.vmName)}).id | Out-Null
                                    if (!(Get-vRACloudAccount -type vsphere | Where-object {$_.name -eq $($vcfVcenterDetails.vmName)})) {
                                        Write-Output "Removing vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                    } 
                                } else {
                                    Write-Warning "Removing vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($vcfVcenterDetails.fqdn)), does not exist: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRACloudAccount

Function Update-vRACloudAccountZone {
    <#
        .SYNOPSIS
        Update Cloud Zone Configuration.

        .DESCRIPTION
        The Update-vRACloudAccountZone cmdlet updated the Cloud Zone with folder and tags on the resource pool for a
        Workload Domain in VMware Aria Automation. The cmdlet connects to SDDC Manager using the -server, -user,
        and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates the Workload Domain is available in the SDDC Manager inventory
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Validates that a Cloud Account exists for the Workload Domain in VMware Aria Automation instance
        - Validates that the Resource Pool is available in VMware Aria Automation as a Compute Resource
        - Adds the tag to the Resource Pool Compute Resource
        - Adds the folder to the Cloud Account Zone as a target
        - Adds a dynamic filter to use the defined tags
        - Updates the placement policy

        .EXAMPLE
        Update-vRACloudAccountZone -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -vraUser configadmin -vraPass VMw@re1! -tagKey enabled -tagValue true -folder "sfo-w01-fd-workload" -resourcePool "sfo-w01-cl01-rp-workload"
        This example updates the Cloud Zone for the Workload Domain with a default folder and adds tags to the resource pool for dynamic provisioning in VMware Aria Automation
        
        .EXAMPLE
        Update-vRACloudAccountZone -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -vraUser configadmin -vraPass VMw@re1! -placementPolicy ADVANCED
        This example updates the placement policy for the Cloud Zone to ADVANCED in VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.

        .PARAMETER tagKey
        The tag key.

        .PARAMETER tagValue
        The tag value.

        .PARAMETER folder
        The folder name.

        .PARAMETER resourcePool
        The resource pool name.

        .PARAMETER placementPolicy
        The placement policy.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tagKey,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tagValue,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$folder,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$resourcePool,
        [Parameter (Mandatory = $false)] [ValidateSet("ADVANCED", "DEFAULT", "SPREAD", "BINPACK")][ValidateNotNullOrEmpty()] [String]$placementPolicy
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            $vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain
                            if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                                if (Get-vRACloudAccount -type vsphere | Where-Object { $_.name -eq $($vcfVcenterDetails.vmName) }) {
                                    if ($PsBoundParameters.ContainsKey("resourcePool")) { 
                                        $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                        if (Get-vRAResourceCompute | Where-Object { $_.name -eq ($cluster + " / " + $resourcePool) }) {
                                            $cloudZoneDetails = Get-vRACloudZone | Where-Object { $_.cloudAccountId -eq (Get-vRACloudAccount -type vsphere | Where-Object { $_.name -eq $($vcfVcenterDetails.vmName) }).id }
                                            Add-vRAResourceComputeTag -id (Get-vRAResourceCompute | Where-Object { $_.name -eq ($cluster + " / " + $resourcePool) }).id -tagKey $tagKey -tagValue $tagValue | Out-Null
                                            Update-VRACloudZone -id $cloudZoneDetails.id -folder $folder | Out-Null
                                            Update-VRACloudZone -id $cloudZoneDetails.id -tagKey $tagKey -tagValue $tagValue | Out-Null
                                            Write-Output "Updating Cloud Zone Configuration in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($($cluster + " / " + $resourcePool)): SUCCESSFUL"
                                        } else {
                                            Write-Error "Unable to find Resource Pool in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn) named ($resourcePool): PRE_VALIDATION_FAILED"
                                        } 
                                    } 
                                    if ($PsBoundParameters.ContainsKey("placementPolicy")) { 
                                        $cloudZoneDetails = Get-vRACloudZone | Where-Object { $_.cloudAccountId -eq (Get-vRACloudAccount -type vsphere | Where-Object { $_.name -eq $($vcfVcenterDetails.vmName) }).id }
                                        Update-VRACloudZone -id $cloudZoneDetails.id -placementPolicy $placementPolicy | Out-Null
                                        Write-Output "Updating placement policy to $placementPolicy in Cloud Zone Configuration in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)): SUCCESSFUL"
                                    }
                                } else {
                                    Write-Error "Unable to find vSphere Cloud Account in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn) named ($($vcfVcenterDetails.vmName)): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }   
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vRACloudAccountZone

Function Add-vROvCenterServer {
    <#
        .SYNOPSIS
        Adds a vCenter Server instance to an embedded VMware Aria Automation Orchestrator.

        .DESCRIPTION
        The Add-vROvCenterServer cmdlet invokes the workflow in VMware Aria Automation Orchestrator to add a vCenter Server.
        The cmdlet connects to SDDC Manager using the -server, -user, -password, and -domain values
        to return the workload domain vCenter Server details from its inventory and then:
        - Makes a connection to the embedded VMware Aria Automation Orchestrator using the -vraUser and -vraPass values.
        - Verifies the workflow exists.
        - Verifies that the vCenter Server instance exists in the VMware Aria Automation Orchestrator catalog.
        - Adds the vCenter Server instance using the -vcUser and -vcPass values.

        .EXAMPLE
        Add-vROvCenterServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -vraUser configadmin -vraPass VMw@re1! -vcUser administrator@vsphere.local -vcPass VMw@re1!
        This example adds the vCenter Server instance from the "sfo-w01" workload domain from the embedded VMware Aria Automation Orchestrator catalog.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER vraUser
        The VMware Aria Automation Orchestrator user name.

        .PARAMETER vraPass
        The VMware Aria Automation Orchestrator password.

        .PARAMETER vcUser
        The vCenter Server user name.

        .PARAMETER vcPass
        The vCenter Server password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcPass
    )

    $workflowName = "Add a vCenter Server instance"

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                                $vcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain                    
                                $checkExists = (Invoke-RestMethod -Method 'GET' -URI "https://$($vcfVraDetails.loadBalancerFqdn)/vco/api/catalog/VC" -headers $vraHeaders)
                                if ((($checkExists.relations.link.attributes | Where-Object { $_.name -eq "id" }).value) -ne "$($vcenter.fqdn)") {
                                    if ($workflow = Get-vROWorkflow -name $workflowName) {
                                        $parameters =  
                                        @"
{"parameters":
    [
        {
            "value": {
                "boolean": {
                    "value": true
                }
            },
            "type": "boolean",
            "name": "enabled",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "$($vcenter.fqdn)"
                }
            },
            "type": "string",
            "name": "host",
            "scope": "local"
        },
        {
            "value": {
                "number": {
                    "value": 443
                }
            },
            "type": "number",
            "name": "port",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "/sdk"
                }
            },
            "type": "string",
            "name": "path",
            "scope": "local"
        },
        {
            "value": {
                "boolean": {
                    "value": false
                }
            },
            "type": "boolean",
            "name": "sessionPerUser",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "$vcUser"
                }
            },
            "type": "string",
            "name": "userName",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "$vcPass"
                }
            },
            "type": "string",
            "name": "password",
            "scope": "local"
        },
        {
            "value": {
                "boolean": {
                    "value": true
                }
            },
            "type": "boolean",
            "name": "ignoreCertificateWarnings",
            "scope": "local"
        },
        {
            "value": {
                "number": {
                    "value": 443
                }
            },
            "type": "number",
            "name": "httpPort",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "https://$($vcenter.fqdn):443/pbm"
                }
            },
            "type": "string",
            "name": "pbmUrl",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "https://$($vcenter.fqdn):443/sms/sdk"
                }
            },
            "type": "string",
            "name": "smsUrl",
            "scope": "local"
        }
    ]
}
"@

                                        $response = Invoke-vROWorkflow -id $($workflow.ID) -parameters ($parameters | ConvertFrom-Json).parameters 
                                        if (Get-vROWorkflowExecutionState -executionStateRef $response.Execution | Where-Object {$_.Execution -ne "failed"}) { 
                                            Do {
                                                $workflowStatus = (Get-vROWorkflowExecutionState -executionStateRef $response.Execution).Execution
                                            }  Until ($workflowStatus -ne "running")
                                            if (Get-vROWorkflowExecutionState -executionStateRef $response.Execution | Where-Object {$_.Execution -eq "completed"}) { 
                                                Write-Output "Adding vCenter Server ($($vcenter.fqdn)) to embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain): SUCCESSFUL"
                                            } else {
                                                Write-Error "Adding vCenter Server ($($vcenter.fqdn)) to embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain), check credentials: POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Adding vCenter Server ($($vcenter.fqdn)) to embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain): FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find the workflow named ($workflowName) to embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding vCenter Server ($($vcenter.fqdn)) to embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain), already exists: SKIPPED"
                                }                                
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROvCenterServer

Function Remove-vROvCenterServer {
    <#
        .SYNOPSIS
        Removes a vCenter Server instance from an embedded VMware Aria Automation Orchestrator.

        .DESCRIPTION
        The Remove-vROvCenterServer cmdlet invokes the workflow in VMware Aria Automation Orchestrator to remove a vCenter Server.
        The cmdlet connects to SDDC Manager using the -server, -user, -password, and -domain values
        to return the workload domain vCenter Server details from its inventory and then:
        - Makes a connection to the embedded VMware Aria Automation Orchestrator using the -vraUser and -vraPass values
        - Verifies the workflow exists
        - Verifies that the vCenter Server instance exists in the VMware Aria Automation Orchestrator catalog
        - Removes the vCenter Server instance

        .EXAMPLE
        Remove-vROvCenterServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -vraUser configadmin -vraPass VMw@re1!
        This example removes the vCenter Server instance from the "sfo-w01" workload domain from the embedded VMware Aria Automation Orchestrator catalog.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass
    )

    $workflowName = "Remove a vCenter Server instance"

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                                $vcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain                    
                                $checkExists = (Invoke-RestMethod -Method 'GET' -URI "https://$($vcfVraDetails.loadBalancerFqdn)/vco/api/catalog/VC" -headers $vraHeaders)
                                if ((($checkExists.relations.link.attributes | Where-Object { $_.name -eq "id" }).value) -eq "$($vcenter.fqdn)") {
                                    if ($workflow = Get-vROWorkflow -name $workflowName) {
                                        $parameters =  
                                        @"
{"parameters":
    [
        {
            "value": {
                "string": {
                    "value": "https://$($vcenter.fqdn):443/sdk"
                }
            },
            "type": "string",
            "name": "host",
            "scope": "local"
        }
    ]
}
"@

                                        $response = Invoke-vROWorkflow -id $($workflow.ID) -parameters ($parameters | ConvertFrom-Json).parameters 
                                        if (Get-vROWorkflowExecutionState -executionStateRef $response.Execution | Where-Object {$_.Execution -ne "failed"}) { 
                                            Do {
                                                $workflowStatus = (Get-vROWorkflowExecutionState -executionStateRef $response.Execution).Execution
                                            } Until ($workflowStatus -ne "running")
                                            if (Get-vROWorkflowExecutionState -executionStateRef $response.Execution | Where-Object {$_.Execution -eq "completed"}) { 
                                                Write-Output "Removing vCenter Server ($($vcenter.fqdn)) from embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removing vCenter Server ($($vcenter.fqdn)) from embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Removing vCenter Server ($($vcenter.fqdn)) from embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain): FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to find the workflow named ($workflowName) in embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing vCenter Server ($($vcenter.fqdn)) from embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)) for Workload Domain ($domain), does not exist: SKIPPED"
                                }                                
                            } else {
                                Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Remove-vROvCenterServer

Function Add-vROTrustedCertificate {
    <#
        .SYNOPSIS
        Adds a trusted certificate to an embedded VMware Aria Automation Orchestrator.

        .DESCRIPTION
        The Add-vROTrustedCertificate cmdlet invokes a workflow in VMware Aria Automation Orchestrator to add trusted
        certificate. The cmdlet connects to SDDC Manager using the -server, -user, and -password values and then:
        - Makes a connection to the embedded VMware Aria Automation Orchestrator using the -vraUser and -vraPass values
        - Verifies the workflow exists
        - Adds the trusted certificate using the -certFile value

        .EXAMPLE
        Add-vROTrustedCertificate -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -certFile "C:\Root64.pem"
        This example adds a trusted certificate in PEM-encoded format to the embedded VMware Aria Automation Orchestrator.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user account to use for authentication.

        .PARAMETER vraPass
        The VMware Aria Automation user password to use for authentication.

        .PARAMETER certFile
        The trusted certificate file in PEM-encoded format.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certFile
    )

    $workflowName = "Import a trusted certificate from a file"

    if (!$PsBoundParameters.ContainsKey("certFile")) {
        $certFile = Get-ExternalFileName -title "Select the trusted certificate file (.cer)" -fileType "cer" -location "default"
    } elseif ($PsBoundParameters.ContainsKey("certFile")) {
        if (!(Test-Path -Path $certFile)) {
            Write-Error  "Selecting the trusted certificate file ($certFile), file not found: PRE_VALIDATION_FAILED"
            Break
        }
    }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {         
                            if ($workflow = Get-vROWorkflow -name $workflowName) {
                                $certName = Split-Path -Path "$certFile" -Leaf
                                $certContent = [Convert]::ToBase64String([IO.File]::ReadAllBytes("$certFile"))
                                $parameters =  
                                @"
{"parameters":
    [
        {"value": {
            "mime-attachment": {
                "name":"$certName",
                "content": "$certContent",
                "mime-type": "application/x-x509-ca-cert"}
            },
            "type": "MimeAttachment",
            "name": "cer",
            "scope": "local"
        }
    ]
}
"@

                                $response = Invoke-vROWorkflow -id $($workflow.ID) -parameters ($parameters | ConvertFrom-Json).parameters 
                                if (Get-vROWorkflowExecutionState -executionStateRef $response.Execution | Where-Object { $_.Execution -ne "failed" }) {
                                    Do {
                                        $workflowStatus = (Get-vROWorkflowExecutionState -executionStateRef $response.Execution).Execution
                                    }  Until ($workflowStatus -ne "running")
                                    if (Get-vROWorkflowExecutionState -executionStateRef $response.Execution | Where-Object { $_.Execution -eq "completed" }) { 
                                        Write-Output "Adding trusted certificate ($certFile) to the embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding trusted certificate ($certFile) to the embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)), check certificate format: POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Adding trusted certificate ($certFile) to the embedded VMware Aria Automation Orchestrator ($($vcfVraDetails.loadBalancerFqdn)): FAILED"
                                }
                            }                             
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vROTrustedCertificate

Function Add-vRANotification {
    <#
        .SYNOPSIS
        Adds notification settings in VMware Aria Automation.

        .DESCRIPTION
        The Add-vRANotification cmdlet adds notification settings to VMware Aria Automation. The cmdlet connects to SDDC
        Manager using the -server, -user, -password, and -domain values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - MValidates that network connectivity and authentication is possible to VMware Aria Automation
        - Adds notifications settings to VMware Aria Automation

        .EXAMPLE
        Add-vRANotification -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -smtpServer smtp.raipole.io -emailAddress vra-no-reply@rainpole.io -sender "Rainpole Cloud" -connection NONE
        This example adds notifications settings for VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user account to use for authentication.

        .PARAMETER vraPass
        The VMware Aria Automation user password to use for authentication.

        .PARAMETER smtpServer
        The SMTP server to use for notifications.

        .PARAMETER emailAddress
        The email address to use for notifications.

        .PARAMETER sender
        The sender name to use for notifications.

        .PARAMETER connection
        The connection type to use for notifications.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$emailAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sender,
        [Parameter (Mandatory = $true)] [ValidateSet("SSL","STARTTLS","NONE")] [ValidateNotNullOrEmpty()] [String]$connection
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            New-vRANotification -name $smtpServer -serverName $smtpServer -emailAddress $emailAddress -sender $sender -trustCert true -connection $connection -authentication false | Out-Null
                            if (Get-vRANotification | Where-Object {$_.name -eq $smtpServer}) {
                                Write-Output "Configuring Notification settings in VMware ria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($smtpServer): SUCCESSFUL"
                            } else {
                                Write-Output "Configuring Notification settings in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) named ($smtpServer): POST_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRANotification

Function Add-vRAUser {
    <#
        .SYNOPSIS
        Adds user access in an organization.

        .DESCRIPTION
        The Add-vRAUser cmdlet adds user access in VMware Aria Automation. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Adds the user to both an organization role and a service role

        .EXAMPLE
        Add-vRAUser -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -email jdoe@rainpole.io -orgRole org_member -serviceRole automationservice:cloud_admin
        This example adds user access in VMware Aria Automation by userId and orgId along with the required orgRole and serviceRole.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user account to use for authentication.

        .PARAMETER vraPass
        The VMware Aria Automation user password to use for authentication.

        .PARAMETER email
        The user email address to add to VMware Aria Automation.

        .PARAMETER orgRole
        The organization role to add to VMware Aria Automation.

        .PARAMETER serviceRole
        The service role to add to VMware Aria Automation.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$email,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner","org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole,
        [Parameter (Mandatory = $true)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            $orgId = (Get-vRAOrganizationId).Split("orgs/")[-1]
                            if (Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.user.email -eq $email }) {
                                $userId = (Get-vRAUser -orgId $orgId -email $email).user.userId
                                $services = (Get-vRAServices -orgId $orgId)
                                $serviceDefinitionId = (($services.serviceRoles | Where-Object {$_.name -eq $serviceRole -and $_.displayName -ne $serviceRole}).serviceDefinitionLink -Split("external/"))[-1]
                                if (!(Get-vRAUserRoles -userId $userId -orgId $orgId | Where-Object { $_.organizationRoles.name -eq $orgRole -and $_.serviceRoles.serviceRoles.name -eq $serviceRole -and $_.serviceRoles.serviceDefinitionId -eq $serviceDefinitionId})) {
                                    New-vRAUser -userId $userId -orgId $orgId -orgRole $orgRole -serviceRole $serviceRole -serviceDefinitionId $serviceDefinitionId | Out-Null
                                    if (Get-vRAUserRoles -userId $userId -orgId $orgId | Where-Object { $_.organizationRoles.name -eq $orgRole -and $_.serviceRoles.serviceRoles.name -eq $serviceRole -and $_.serviceRoles.serviceDefinitionId -eq $serviceDefinitionId}) {
                                        Write-Output "Assigning user email ($email) the organization role ($orgRole) and service role ($serviceRole) in VMware Aria Automation: SUCCESSFUL"
                                    } else {
                                        Write-Error "Assigning user email ($email) the organization role ($orgRole) and service role ($serviceRole) in VMware Aria Automation: POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Assigning user email ($email) the organization role ($orgRole) and service role ($serviceRole) in VMware Aria Automation, already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find user email ($email) in Workspace ONE Access for VMware Aria Automation, check user synchronization or email: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRAUser

Function Undo-vRAUser {
    <#
        .SYNOPSIS
        Removes user access from an organization.

        .DESCRIPTION
        The Undo-vRAUser cmdlet removes user access in VMware Aria Automation. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Removes the user from an organization role and all service roles

        .EXAMPLE
        Undo-vRAUser -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -email jdoe@rainpole.io
        This example removes user access from VMware Aria Automation by email.

        Note: This cmdlet currently only supports a single serviceRole.

        Note: This cmdlet does not remove the user from the organization, only the organization role and service roles.

        Note: This cmdlet does not remove the user from the VMware Cloud Foundation SDDC Manager.

        Note: This cmdlet does not remove the user from Workspace ONE Access.

        Note: This cmdlet does not remove the user from the vCenter Server.

        Note: This cmdlet does not remove the user from the vRealize Automation Cloud Zone.

        Note: This cmdlet does not remove the user from the vRealize Automation Cloud Zone Configuration.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager.

        .PARAMETER user
        The user name of the SDDC Manager.

        .PARAMETER pass
        The password of the SDDC Manager.

        .PARAMETER vraUser
        The user name of the VMware Aria Automation Orchestrator.

        .PARAMETER vraPass
        The password of the VMware Aria Automation Orchestrator.

        .PARAMETER email
        The email address of the user to remove from the organization role and service roles.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$email
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            $orgId = (Get-vRAOrganizationId).Split("orgs/")[-1]
                            if (Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.user.email -eq $email -and $_.organizationRoles.name -ne $null -and $_.serviceRoles.serviceDefinitionId -ne $null}) {
                                if ($objectCheck = Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.user.email -eq $email }) {
                                    if ($orgRole = ($objectCheck.organizationRoles.name)) {
                                        Remove-vRAUserOrgRole -userId $userId -orgId $orgId -orgRole $orgRole
                                    }
                                    if ($serviceRoles = ($objectCheck.serviceRoles.serviceRoles.name)) {
                                        $services = (Get-vRAServices -orgId $orgId)
                                        Foreach ($serviceRole in $serviceRoles) {
                                            $serviceDefinitionId = (($services.serviceRoles | Where-Object {$_.name -eq $serviceRole -and $_.displayName -ne $serviceRole}).serviceDefinitionLink -Split("external/"))[-1]
                                            Remove-vRAUserServiceRole -userId $userId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -serviceRole $serviceRole
                                        }
                                    }
                                    if ($orgRole -eq $null) {
                                        $orgRole = "none"
                                    }
                                    if ($serviceRoles -eq $null) {
                                        $serviceRole = "none"
                                    } else {
                                        $serviceRole = $serviceRoles -join ', '
                                    }
                                    if (Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.organizationRoles.name -eq $null -and $_.serviceRoles.serviceRoles.name -eq $null -and $_.serviceRoles.serviceDefinitionId -eq $null}) {
                                        Write-Output "Removing user email ($email) from organization role ($orgRole) and service roles(s) ($serviceRole) in Aria Automation: SUCCESSFUL"
                                    } else {
                                        Write-Warning "Removing user email ($email) from organization role ($orgRole) and service roles(s) ($serviceRole) in Aria Automation: POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find user email ($email) in Workspace ONE Access for Aria Automation, check email variable: PRE_VALIDATION_FAILED"
                                }
                            } elseif (Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.user.email -eq $email -and $_.organizationRoles.name -ne $null -or $_.serviceRoles.serviceDefinitionId -ne $null}) {
                                if ($objectCheck = Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.user.email -eq $email }) {
                                    if ($orgRole = ($objectCheck.organizationRoles.name)) {
                                        Remove-vRAUserOrgRole -userId $userId -orgId $orgId -orgRole $orgRole
                                    }
                                    if ($serviceRoles = ($objectCheck.serviceRoles.serviceRoles.name)) {
                                        $services = (Get-vRAServices -orgId $orgId)
                                        Foreach ($serviceRole in $serviceRoles) {
                                            $serviceDefinitionId = (($services.serviceRoles | Where-Object {$_.name -eq $serviceRole -and $_.displayName -ne $serviceRole}).serviceDefinitionLink -Split("external/"))[-1]
                                            Remove-vRAUserServiceRole -userId $userId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -serviceRole $serviceRole
                                        }
                                    }
                                    if ($orgRole -eq $null) {
                                        $orgRole = "none"
                                    }
                                    if ($serviceRoles -eq $null) {
                                        $serviceRole = "none"
                                    } else {
                                        $serviceRole = $serviceRoles -join ', '
                                    }
                                    if (Get-vRAUser -orgId $orgId -email $email | Where-Object { $_.organizationRoles.name -eq $null -and $_.serviceRoles.serviceRoles.name -eq $null -and $_.serviceRoles.serviceDefinitionId -eq $null}) {
                                        Write-Output "Removing user email ($email) from organization role ($orgRole) and service roles(s) ($serviceRole) in VMware Aria Automation: SUCCESSFUL"
                                    } else {
                                        Write-Warning "Removing user email ($email) from organization role ($orgRole) and service roles(s) ($serviceRole) in VMware Aria Automation: POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find user email ($email) in Workspace ONE Access for VMware Aria Automation, check email variable: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing user email ($email) from organization role and service roles(s) in VMware Aria Automation, no roles assigned: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRAUser

Function Add-vRAGroup {
    <#
        .SYNOPSIS
        Adds a group in an organization.

        .DESCRIPTION
        The Add-vRAGroup cmdlet adds a group in VMware Aria Automation. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Adds the group to an organization role and a service role

        .EXAMPLE
        Add-vRAGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -displayName gg-vra-org-owners@rainpole.io -orgRole org_owner
        This example adds a group to VMware Aria Automation by groupId and orgId along with the required orgRole.

        .EXAMPLE
        Add-vRAGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -displayName gg-vra-cloud-assembly-admins@rainpole.io -orgRole org_member -serviceRole automationservice:cloud_admin
        This example adds a group to VMware Aria Automation by groupId and orgId along with the required orgRole and serviceRole.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username used to authenticate to SDDC Manager.

        .PARAMETER pass
        The password used to authenticate to SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user to connect with.

        .PARAMETER vraPass
        The VMware Aria Automation password to connect with.

        .PARAMETER displayName
        The group display name to add.

        .PARAMETER orgRole
        The organization role to add.

        .PARAMETER serviceRole
        The service role to add.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$displayName,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner","org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole,
        [Parameter (Mandatory = $false)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            $orgId = (Get-vRAOrganizationId).Split("orgs/")[-1]
                            if (Get-vRAGroup -orgId $orgId -displayName $displayName | Where-Object { $_.displayName -eq $displayName }) {
                                $groupId = (Get-vRAGroup -orgId $orgId -displayName $displayName).id 
                                if ($PsBoundParameters.ContainsKey("orgRole") -and ($PsBoundParameters.ContainsKey("serviceRole"))) {
                                    $services = (Get-vRAServices -orgId $orgId)
                                    $serviceDefinitionId = (($services.serviceRoles | Where-Object {$_.name -eq $serviceRole -and $_.displayName -ne $serviceRole}).serviceDefinitionLink -Split("external/"))[-1]
                                    if (!(Get-vRAGroupRoles -groupId $groupId -orgId $orgId | Where-Object { $_.organizationRoles.name -eq $orgRole -and $_.serviceRoles.serviceRoleNames -eq $serviceRole -and $_.serviceRoles.serviceDefinitionId -eq $serviceDefinitionId})) {
                                        New-vRAGroup -groupId $groupId -orgId $orgId -orgRole $orgRole -serviceRole $serviceRole -serviceDefinitionId $serviceDefinitionId | Out-Null
                                        if (Get-vRAGroupRoles -groupId $groupId -orgId $orgId | Where-Object { $_.organizationRoles.name -eq $orgRole -and $_.serviceRoles.serviceRoleNames -eq $serviceRole -and $_.serviceRoles.serviceDefinitionId -eq $serviceDefinitionId}) {
                                            Write-Output "Assigning group ($displayName) the organization role ($orgRole) and service role ($serviceRole) in VMware Aria Automation: SUCCESSFUL"
                                        } else {
                                            Write-Error "Assigning group ($displayName) the organization role ($orgRole) and service role ($serviceRole) in VMware Aria Automation: POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Assigning group ($displayName) the organization role ($orgRole) and service role ($serviceRole) in VMware Aria Automation, already exists: SKIPPED"
                                    }
                                }
                                elseif (!$PsBoundParameters.ContainsKey("serviceRole")) {
                                    if (!(Get-vRAGroupRoles -groupId $groupId -orgId $orgId | Where-Object { $_.organizationRoles.name -eq $orgRole -and $_.serviceRoles.serviceRoleNames -eq $null -and $_.serviceRoles.serviceDefinitionId -eq $null})) {
                                        New-vRAGroup -groupId $groupId -orgId $orgId -orgRole $orgRole | Out-Null
                                        if (Get-vRAGroupRoles -groupId $groupId -orgId $orgId | Where-Object { $_.organizationRoles.name -eq $orgRole -and $_.serviceRoles.serviceRoleNames -eq $null -and $_.serviceRoles.serviceDefinitionId -eq $null}) {
                                            Write-Output "Assigning group ($displayName) the organization role ($orgRole) in VMware Aria Automation: SUCCESSFUL"
                                        } else {
                                            Write-Error "Assigning group ($displayName) the organization role ($orgRole) in VMware Aria Automation: POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Assigning group ($displayName) the organization role ($orgRole) in VMware Aria Automation, already exists: SKIPPED"
                                    }
                                }
                            } else {
                                Write-Error "Unable to find group ($displayName) in Workspace ONE Access for VMware Aria Automation, check group synchronization or displayName: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRAGroup

Function Undo-vRAGroup {
    <#
        .SYNOPSIS
        Removes a group in an organization.

        .DESCRIPTION
        The Undo-vRAGroup cmdlet removes a group in VMware Aria Automation. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Removes the group from an organization role and all service roles

        .EXAMPLE
        Undo-vRAGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vraUser configadmin -vraPass VMw@re1! -displayName gg-vra-cloud-assembly-admins@rainpole.io
        This example removes a group from VMware Aria Automation by displayName.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.

        .PARAMETER displayName
        The group display name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$displayName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            $orgId = (Get-vRAOrganizationId).Split("orgs/")[-1]
                            if (Get-vRAGroup -orgId $orgId -displayName $displayName | Where-Object { $_.displayName -eq $displayName }) {
                                $groupId = (Get-vRAGroup -orgId $orgId -displayName $displayName).id 
                                if (Get-vRAGroup -orgId $orgId -displayName $displayName | Where-Object { $_.organizationRoles.name -ne $null -or $_.serviceRoles.serviceDefinitionId -ne $null}) {
                                    Remove-vRAGroupRoles -groupId $groupId -orgId $orgId | Out-Null
                                    if (!(Get-vRAGroup -orgId $orgId -displayName $displayName | Where-Object { $_.organizationRoles.name -ne $null -and $_.serviceRoles.serviceRoleNames -ne $null -and $_.serviceRoles.serviceDefinitionId -ne $null})) {
                                        Write-Output "Removing group ($displayName) from VMware Aria Automation: SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing group ($displayName) from VMware Aria Automation:: POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing group ($displayName) from VMware Aria Automation:, does not exist: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find group ($displayName) in Workspace ONE Access for VMware Aria Automation, check group synchronization or displayName: PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRAGroup

Function New-vRAvROPSIntegrationItem {
    <#
        .SYNOPSIS
        Creates new VMware Aria Operations integration in VMware Aria Automation.

        .DESCRIPTION
        The New-vRAvROPSIntegrationItem cmdlet creates an integration in VMware Aria Automation.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Creates VMware Aria Operations integration in VMware Aria Automation

        .EXAMPLE
        New-vRAvROPSIntegrationItem -server "sfo-vcf01.sfo.rainpole.io" -user "administrator@vsphere.local" -pass "VMw@re1!" -vraUser "configadmin@rainpole.io" -vraPass "VMw@re1!" -vropsIntegrationUser "svc-vrops-vra@sfo.rainpole.io@vIDMAuthSource" -vropsIntegrationPass "VMw@re1!" -vropsIntegrationName "VMware Aria Operations"
        This example creates VMware Aria Operations integration with name "VMware Aria Operations" in VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.

        .PARAMETER vropsIntegrationUser
        The VMware Aria Operations integration user name.

        .PARAMETER vropsIntegrationPass
        The VMware Aria Operations integration password.

        .PARAMETER vropsIntegrationName
        The VMware Aria Operations integration name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vropsIntegrationUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vropsIntegrationPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vropsIntegrationName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                                if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                                    if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                                        $response = Add-vRAIntegrationItem -integrationType "vrops" -integrationName $vropsIntegrationName -integrationUser $vropsIntegrationUser -integrationPassword $vropsIntegrationPass #| Out-Null
                                        if ($response.status -eq "FINISHED") {
                                            if (Get-vRAIntegrationDetail -integrationType "vrops"  -integrationName $vropsIntegrationName -getIntegrationID) {
                                                Write-Output "Creating VMware Aria Operations integration with name ($vropsIntegrationName) in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Creating VMware Aria Operations integration with name ($vropsIntegrationName) in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)): POST_VALIDATION_FAILED" 
                                            }
                                        } else {
                                            Write-Error "Creating VMware Aria Operations integration with name ($vropsIntegrationName) in VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)) failed with '$($response.message)': FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-vRAvROPSIntegrationItem

Function Undo-vRAvROPsIntegrationItem {
    <#
        .SYNOPSIS
        Deletes VMware Aria Operations from VMware Aria Automation.

        .DESCRIPTION
        The Undo-vRAvROPsIntegrationItem cmdlet deletes VMware Aria Operations integration from VMware Aria Automation.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Automation
        - Validates that VMware Aria Operations has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Operations
        - Deletes VMware Aria Operations integration from VMware Aria Automation

        .EXAMPLE
        Undo-vRAvROPsIntegrationItem -server "sfo-vcf01.sfo.rainpole.io" -user "administrator@vsphere.local" -pass "VMw@re1!" -vraUser "svc-vra-vrops@sfo.rainpole.io@vIDMAuthSource" -vraPass "VMw@re1!" -vropsIntegrationName "VMware Aria Operations"
        This example deletes VMware Aria Operations in VMware Aria Automation.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER vraUser
        The VMware Aria Automation user name.

        .PARAMETER vraPass
        The VMware Aria Automation password.

        .PARAMETER vropsIntegrationName
        The VMware Aria Operations integration name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass, 
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vraPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vropsIntegrationName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVraDetails = Get-vRAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRAConnection -server $vcfVraDetails.loadBalancerFqdn) {
                        if (Test-vRAAuthentication -server $vcfVraDetails.loadBalancerFqdn -user $vraUser -pass $vraPass) {
                            if (($vcfVropsDetails = Get-vROPsServerDetail -fqdn $server -username $user -password $pass)) {
                                if (Test-vROPSConnection -server $vcfVropsDetails.loadBalancerFqdn) {
                                    if (Test-vROPSAuthentication -server $vcfVropsDetails.loadBalancerFqdn -user $vcfVropsDetails.adminUser -pass $vcfVropsDetails.adminPass) {
                                        if ($null -eq (Get-vRAIntegrationDetail -integrationType "vrops"  -integrationName $vropsIntegrationName -getIntegrationID ) ) {
                                            Write-Warning "VMware Aria Operations Integration with name ($vropsIntegrationName) not found: SKIPPED" 
                                            break
                                        }
                                        Remove-vRAIntegrationItem -integrationType vrops -integrationId (Get-vRAIntegrationDetail -integrationType vrops -integrationName $vropsIntegrationName -getIntegrationID) | Out-Null
                                    }
                                    if ($null -eq (Get-vRAIntegrationDetail -integrationType "vrops"  -integrationName $vropsIntegrationName -getIntegrationID) ) {
                                        Write-Output "Removing VMware Aria Operations Integration with name ($vropsIntegrationName) from VMware Aria Automation ($($vcfVraDetails.loadBalancerFqdn)): SUCCESSFUL"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRAvROPsIntegrationItem

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region H E A L T H R E P O R T I N G A N D M O N I T O R I N G F U N C T I O N S ###########

Function Deploy-PhotonAppliance {
    <#
        .SYNOPSIS
        Deploy a Photon appliance.

        .DESCRIPTION
        The Deploy-PhotonAppliance cmdlet deploys the Photon appliance to a vSphere Cluster of a workload Domain.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to the vCenter Server
        - Deploys the Photon Appliance into a vSphere Cluster

        .EXAMPLE
        Deploy-PhotonAppliance -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -hostname sfo-m01-hrm01 -ipAddress 172.18.95.50 -netmask "24 (255.255.255.0)" -gateway 172.18.95.1 -domain sfo.rainpole.io -dnsServer "172.18.95.4 172.18.95.5" -ntpServer ntp.sfo.rainpole.io -rootPassword VMw@re1! -enableSsh True -enableDebug False -portGroup sfo-m01-cl01-vds01-mgmt -folder sfo-m01-fd-hrm -ovaPath .\vvs_appliance_v0.0.1.ova
        This example deploys the Photon appliance named sfo-m01-hrm01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the workload domain to deploy the Photon appliance.

        .PARAMETER hostname
        The hostname of the Photon appliance.

        .PARAMETER domain
        The domain namespace for the Photon appliance.

        .PARAMETER ipAddress
        The IP address of the Photon appliance.

        .PARAMETER netmask
        The netmask of the Photon appliance.

        .PARAMETER gateway
        The gateway of the Photon appliance.

        .PARAMETER dnsServer
        The DNS servers for the Photon appliance.

        .PARAMETER ntpServer
        The NTP servers for the Photon appliance.

        .PARAMETER rootPassword
        The root password for the Photon appliance.

        .PARAMETER enableSsh
        Enable SSH on the Photon appliance.

        .PARAMETER enableDebug
        Enable debug mode on the Photon appliance.

        .PARAMETER portgroup
        The portgroup to place the Photon appliance on.

        .PARAMETER folder
        The virtual machine folder to place the Photon appliance in.

        .PARAMETER ovaPath
        The path to the Photon appliance OVA file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$hostname,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ipAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$netmask,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$dnsServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPassword,
        [Parameter (Mandatory = $true)] [ValidateSet('True', 'False')] [String]$enableSsh,
        [Parameter (Mandatory = $true)] [ValidateSet('True', 'False')] [String]$enableDebug,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$portgroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$folder,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ovaPath
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("ovaPath")) {
            $ovaPath = Get-ExternalFileName -title "Select the OVA file (.ova)" -fileType "ova" -location "default"
        }
        if (Test-Path -Path $ovaPath) {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (!(Get-VM -Name $hostname -Server ($vcfVcenterDetails.fqdn).Name -ErrorAction Ignore)) {
                                    $ovfConfiguration = Get-OvfConfiguration $ovaPath
                                    $ovfConfiguration.Common.guestinfo.hostname.Value = ($hostname + "." + $domain)
                                    $ovfConfiguration.Common.guestinfo.ipaddress.Value = $ipaddress
                                    $ovfConfiguration.Common.guestinfo.netmask.Value = $netmask
                                    $ovfConfiguration.Common.guestinfo.gateway.Value = $gateway
                                    $ovfConfiguration.Common.guestinfo.dns.Value = $dnsServer
                                    $ovfConfiguration.Common.guestinfo.domain.Value = $domain
                                    $ovfConfiguration.Common.guestinfo.ntp.Value = $ntpServer
                                    $ovfConfiguration.Common.guestinfo.root_password.Value = $rootPassword
                                    $ovfConfiguration.Common.guestinfo.enable_ssh.Value = $enableSsh
                                    $ovfConfiguration.Common.guestinfo.debug.Value = $enableDebug
                                    $ovfConfiguration.NetworkMapping.DHCP.Value = $portgroup
                                    Import-vApp -Source $ovaPath -OvfConfiguration $ovfConfiguration -Name $hostname -VMHost (Get-VMHost -Server $vcfVcenterDetails.fqdn).Name[-1] -Location (Get-Cluster -Server $vcfVcenterDetails.fqdn).Name -InventoryLocation $folder -Datastore (Get-Datastore -Server $vcfVcenterDetails.fqdn).Name -DiskStorageFormat Thin -Server $vcfVcenterDetails.fqdn -Confirm:$false -Force | Out-Null
                                    Start-VM -VM $hostname -Server ($vcfVcenterDetails.fqdn).Name | Out-Null
                                    if ((Get-VM -Name $hostname -Server ($vcfVcenterDetails.fqdn).Name).PowerState -eq "PoweredOn") {
                                        Write-Output "Deploying and Powering On Virtual Machine ($hostname) in vCenter Server ($($vcfVcenterDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "Deploying and Powering On Virtual Machine ($hostname) in vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Deploying and Powering On Virtual Machine ($hostname) in vCenter Server ($($vcfVcenterDetails.fqdn)), already exists: SKIPPED"
                                }
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        } else {
            Write-Error  "Unable to locate Photon OVA ($ovaPath), File Not Found: PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Deploy-PhotonAppliance

Function Remove-PhotonAppliance {
    <#
        .SYNOPSIS
        Remove the Photon appliance.

        .DESCRIPTION
        The Remove-PhotonAppliance cmdlet deploys the Photon appliance to a vSphere Cluster of a workload Domain.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to the vCenter Server
        - Deploys the Photon Appliance into a vSphere Cluster

        .EXAMPLE
        Remove-PhotonAppliance -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-w01 -vmName sfo-m01-hrm01
        This example removes the Photon appliance named sfo-m01-hrm01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The name of the workload domain the Photon appliance is deployed to.

        .PARAMETER vmName
        The name of the virtual machine for the Photon appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VM -name $vmName -ErrorAction SilentlyContinue ) {
                                Get-VM -name $vmName | Stop-VM -RunAsync -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                Do {$powerState = (Get-VM -name $vmName | Select-Object PowerState).PowerState } Until ($powerState -eq "PoweredOff")
                                Get-VM -name $vmName | Remove-VM -DeletePermanently -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                if (!(Get-VM -name $vmName -ErrorAction SilentlyContinue)) {
                                    Write-Output "Deleting the Host Virtual Machine ($vmName) from vCenter Server ($server): SUCCESSFUL"
                                } else {
                                    Write-Error "Deleting the Host Virtual Machine ($vmName) from vCenter Server ($($vcfVcenterDetails.fqdn)): POST_VALIDATIO_FAILED"
                                }
                            } else {
                                Write-Warning "Deleting the Host Virtual Machine ($vmName) from vCenter Server ($($vcfVcenterDetails.fqdn)), does not exist: SKIPPED"
                            }
                        }
                        Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Remove-PhotonAppliance

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region V M W A R E A R I A S U I T E L I F E C Y C L E F U N C T I O N S ###########

Function Export-vRSLCMJsonSpec {
    <#
        .SYNOPSIS
        Create JSON specification for VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Export-vRSLCMJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation workbook
        to deploy the VMware Aria Suite Lifecycle:
        - Validates that the Planning and Preparation is available
        - Generates the JSON specification file using the Planning and Preparation workbook

        .EXAMPLE
        Export-vRSLCMJsonSpec -workbook .\pnp-workbook.xlsx -jsonFile .\vrslcmDeploySpec.json
        This example creates a JSON specification VMware Aria Suite Lifecycleusing the Planning and Preparation Workbook.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER jsonFile
        The path to the JSON specification file to be created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        }
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Generation of VMware Aria Suite Lifecycle (.json) Specification File"
        if (Test-Path -Path $workbook) {
            $pnpWorkbook = Open-ExcelPackage -Path $Workbook
            $jsonObject = @()
            $jsonObject += [pscustomobject]@{
                'sddcManagerFqdn'                   = $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value
                'sddcManagerUser'                   = $pnpWorkbook.Workbook.Names["sso_default_admin"].Value
                'sddcManagerPass'                   = $pnpWorkbook.Workbook.Names["administrator_vsphere_local_password"].Value
                'mgmtSddcDomainName'                = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value
                'contentLibraryName'                = $pnpWorkbook.Workbook.Names["vrslcm_xreg_content_library"].Value
                'customerConnectAlias'              = ($pnpWorkbook.Workbook.Names["xreg_customer_connect_email"].Value).Split('@')[0]
                'customerConnectPassword'           = $pnpWorkbook.Workbook.Names["xreg_customer_connect_password"].Value
                'customerConnectUsername'           = $pnpWorkbook.Workbook.Names["xreg_customer_connect_email"].Value
                'aslcmFqdn'                         = $pnpWorkbook.Workbook.Names["xreg_vrslcm_fqdn"].Value
                'aslcmIp'                           = $pnpWorkbook.Workbook.Names["vrs_t1_lb_si_ip"].Value
                'aslcmAdminPassword'                = $pnpWorkbook.Workbook.Names["vcfadmin_local_password"].Value
                'aslcmSshPassword'                  = $pnpWorkbook.Workbook.Names["vrslcm_root_password"].Value
                'country'                           = $pnpWorkbook.Workbook.Names["ca_country"].Value
                'email'                             = $pnpWorkbook.Workbook.Names["ca_email_address"].Value
                'keyAlgorithm'                      = $pnpWorkbook.Workbook.Names["ca_algorithm"].Value
                'keySize'                           = $pnpWorkbook.Workbook.Names["ca_key_size"].Value
                'locality'                          = $pnpWorkbook.Workbook.Names["ca_locality"].Value
                'organization'                      = $pnpWorkbook.Workbook.Names["ca_organization"].Value
                'organizationUnit'                  = $pnpWorkbook.Workbook.Names["ca_organization_unit"].Value
                'state'                             = $pnpWorkbook.Workbook.Names["ca_state"].Value
                'psPack'                            = $pnpWorkbook.Workbook.Names["xreg_vrslcm_pspack"].Value
            }
            Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
            $jsonObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonFile
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            Foreach ($jsonValue in $jsonInput.psobject.properties) {
                if ($jsonValue.value -eq "Value Missing" -or $null -eq $jsonValue.value ) {
                    $issueWithJson = $true
                }
            }
            if ($issueWithJson) {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Creation of JSON Specification file for VMware Aria Suite Lifecycle, missing data: POST_VALIDATION_FAILED"
            } else { 
                Show-PowerValidatedSolutionsOutput -message "Creation of JSON Specification file for VMware Aria Suite Lifecycle: SUCCESSFUL"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-vRSLCMJsonSpec

Function Invoke-vRSLCMDeployment {
    <#
        .SYNOPSIS
        End-to-end deployment of VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Invoke-vRSLCMDeployment cmdlet is a single function to deploy and configure VMware Aria Suite Lifecycle.

        .EXAMPLE
        Invoke-vRSLCMDeployment -jsonFile .\vrslcmDeploySpec.json -binaries .\binaries
        This example deploys and configures VMware Aria Suite Lifecycle.

        .PARAMETER jsonFile
        The path to the JSON specification file to be used.

        .PARAMETER binaries
        The path to the product binaries.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$binaries
    )

    # Define Reusable Parameters
    $lcmProductName = "VMware Aria Suite Lifecycle"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Deployment of $lcmProductName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    $failureDetected = $false
                    
                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Downloading $lcmProductName Install Bundle in SDDC Manager"
                        $StatusMsg = Request-vRSLCMBundle -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                    }

                    if (!$failureDetected) { 
                        Show-PowerValidatedSolutionsOutput -message "Deploying $lcmProductName using SDDC Manager"
                        $outputPath = ($outputPath = Split-Path $jsonFile -Parent) + "\" + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmDeploymentSpec.json")
                        $StatusMsg = New-vRSLCMDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -outputPath $outputPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                    }

                    if (!$failureDetected) {
                        Show-PowerValidatedSolutionsOutput -message "Creating a vSphere Content Library for Operational Management"
                        $StatusMsg = Add-ContentLibrary -Server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibraryName $jsonInput.contentLibraryName -published -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                        if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg"; $ErrorMsg = $null }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                    }

                    if (Get-VCFvRSLCM) {
                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Replacing the Certificate of the $lcmProductName Instance using SDDC Manager"
                            $StatusMsg = Install-vRSLCMCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -jsonFile $jsonFile -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -message "Adding the VMware Customer Connect Password to $lcmProductName"
                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.customerConnectAlias -password $jsonInput.customerConnectPassword -userName $jsonInput.customerConnectUsername -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }

                        if (!$failureDetected) {
                            Show-PowerValidatedSolutionsOutput -type INFO -Message "Adding Customer Connect Account to $lcmProductName"
                            $StatusMsg = Add-vRslcmMyVMwareAccount -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.customerConnectAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                        }

                        if (((Get-VCFVrslcm).version -Split ('-'))[-0] -lt "8.14.0") {
                            if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Applying a Product Support Pack to $lcmProductName"
                                    $StatusMsg = Update-vRSLCMPSPack -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -psPack $jsonInput.psPack -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg }
                            }

                            if (!$failureDetected) {
                                Show-PowerValidatedSolutionsOutput -message "Obtain and Upload $lcmProductName Upgrade ISO to vSphere Content Library"
                                $upgradeIsoPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match ("(updaterepo.iso)")}).name
                                if ($upgradeIsoPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match ("(updaterepo.iso)")}).name) {
                                    Show-PowerValidatedSolutionsOutput -message "Importing $lcmProductName Upgrade ISO into vSphere Content Library"
                                    $StatusMsg = Import-ContentLibraryItem -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibrary $jsonInput.contentLibraryName -file $upgradeIsoPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" }; if ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg }; if ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                } else {
                                    Show-PowerValidatedSolutionsOutput -type ERROR -message "$lcmProductName Upgrade ISO ($upgradeIsoPath) File Not Found: PRE_VALIDATION_FAILED"
                                }
                                
                            }

                            if (!$failureDetected) {
                                Show-PowerValidatedSolutionsOutput -message "Upgrading VMware Aria Suite Lifecycle"
                                Show-PowerValidatedSolutionsOutput -type NOTE -message "AUTOMATION TO BE ADDED"
                            }

                            if (!$failureDetected) {
                                Show-PowerValidatedSolutionsOutput -message "Deleting Snapshots of $lcmProductName"
                                Show-PowerValidatedSolutionsOutput -type NOTE -message "AUTOMATION TO BE ADDED"
                            }
                        }
                    } else {
                        Show-PowerValidatedSolutionsOutput -type ERROR -message "Deployment of $lcmProductName Not Found"
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $solutionName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-CatchWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-vRSLCMDeployment

Function Add-vRSLCMMyVMwareAccount {
    <#
        .SYNOPSIS
        Add a VMware Customer Connect account to the VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Add-vRSLCMMyVMwareAccount cmdlet adds a VMware Customer Connect Account to VMware Aria Suite Lifecycle based on
        credentials added to the VMware Aria Suite Lifecycle locker. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the account is not present in VMware Aria Suite Lifecycle
        - Adds the VMware Customer Connect Account to VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMMyVMwareAccount -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alias myVmwareAccount
        This example adds a VMware Customer Connect account using an alias of 'myVmwareAccount' to VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER alias
        The alias of the password credential in the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMLockerPassword -alias $alias) {
                                if (!(Get-vRSLCMMyVmwareAccount | Where-Object {$_.userName -match $alias})) {
                                    New-vRSLCMMyVmwareAccount -alias $alias | Out-Null
                                    if ((Get-vRSLCMMyVmwareAccount | Where-Object {$_.userName -match $alias})) {
                                        Write-Output "Adding VMware Customer Connect Account to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with alias ($alias): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding VMware Customer Connect Account to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with alias ($alias): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding VMware Customer Connect Account to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with alias ($alias), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to locate the password with alias ($alias) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vRSLCMMyVMwareAccount

Function Undo-vRSLCMMyVMwareAccount {
    <#
        .SYNOPSIS
        Remove a VMware Customer Connect Account from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-vRSLCMMyVMwareAccount cmdlet removes a VMware Customer Connect Account from VMware Aria Suite Lifecycle.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the account is present in VMware Aria Suite Lifecycle
        - Removes the VMware Customer Connect Account from VMware Aria Suite Lifecycle

        .EXAMPLE
        Undo-vRSLCMMyVMwareAccount -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alias myVmwareAccount
        This example removes the VMware Customer Connect Account 'myVmwareAccount' from VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER alias
        The alias of the password credential in the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMMyVmwareAccount | Where-Object {$_.userName -match $alias}) {
                                Remove-vRSLCMMyVmwareAccount -alias $alias | Out-Null
                                if (!(Get-vRSLCMMyVmwareAccount | Where-Object {$_.userName -match $alias})) {
                                    Write-Output "Removing VMware Customer Connect Account from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with alias ($alias): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing VMware Customer Connect Account from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with alias ($alias): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing VMware Customer Connect Account from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) with alias ($alias), does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRSLCMMyVMwareAccount

Function New-vRSLCMDatacenter {
    <#
        .SYNOPSIS
        Adds a datacenter to VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRSLCMDatacenter cmdlet adds a datacenter to the VMware Aria Suite Lifecycle inventory. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the datacenter has not already been created in the inventory
        - Creates the datacenter in the inventory

        .EXAMPLE
        New-vRSLCMDatacenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -datacenterName xint-m01-dc01 -location "San Francisco, California, US"
        This example adds a datacenter to the VMware Aria Suite Lifecycle inventory.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER datacenterName
        The name of the datacenter to add to the inventory.

        .PARAMETER location
        The location of the datacenter to add to the inventory.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$location
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) { 
                            if (!(Get-vRSLCMDatacenter -datacenterName $datacenterName -ErrorAction SilentlyContinue )) {
                                Add-vRSLCMDatacenter -datacenterName $datacenterName -location $location | Out-Null
                                if (Get-vRSLCMDatacenter -datacenterName $datacenterName -ErrorAction SilentlyContinue ) {
                                    Write-Output "Adding Datacenter to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) inventory name ($datacenterName): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding Datacenter to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) inventory name ($datacenterName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding Datacenter to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) inventory name ($datacenterName), already exists: SKIPPED"
                            }
                        }
                    }
                }                         
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMDatacenter

Function New-vRSLCMDatacenterVcenter {
    <#
        .SYNOPSIS
        Adds a vCenter Server to a Datacenter to VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRSLCMDatacenterVcenter cmdlet adds a vCenter Server to a Datacenter to the VMware Aria Suite Lifecycle
        Manager inventory. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the vCenter Server has not already been added to the Datacenter
        - Adds the vCenter Server to the Datacenter

        .EXAMPLE
        New-vRSLCMDatacenterVcenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -datacenterName xint-m01-dc01 -vcenterFqdn sfo-m01-vc01.sfo.rainpole.io -userLockerAlias sfo-m01-vc01-sfo-m01-dc01
        This example adds a vCenter Server to a Datacenter in VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER datacenterName
        The name of the datacenter to add the vCenter Server to.

        .PARAMETER vcenterFqdn
        The FQDN of the vCenter Server to add to the Datacenter.

        .PARAMETER userLockerAlias
        The user locker alias of the vCenter Server to add to the Datacenter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userLockerAlias
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) { 
                            if (Get-vRSLCMDatacenter -datacenterName $datacenterName -ErrorAction SilentlyContinue ) {
                                if (Get-vRSLCMLockerPassword -alias $userLockerAlias) {
                                    if (!(Get-vRSLCMDatacenterVcenter -datacenterVmid (Get-vRSLCMDatacenter -datacenterName $datacenterName).datacenterVmid -vcenterName  ($vcenterFqdn.Split(".")[0]) -ErrorAction SilentlyContinue)) {
                                        Add-vRSLCMDatacenterVcenter -datacenterVmid (Get-vRSLCMDatacenter -datacenterName $datacenterName).datacenterVmid -vcenterFqdn $vcenterFqdn -userLockerAlias $userLockerAlias | Out-Null
                                        Start-Sleep 10
                                        if (Get-vRSLCMDatacenterVcenter -datacenterVmid (Get-vRSLCMDatacenter -datacenterName $datacenterName).datacenterVmid -vcenterName ($vcenterFqdn.Split(".")[0]) -ErrorAction SilentlyContinue) {
                                            Write-Output "Adding vCenter Server to Datacenter ($datacenterName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) named ($($vcenterFqdn.Split(".")[0])): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding vCenter Server to Datacenter ($datacenterName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) named ($($vcenterFqdn.Split(".")[0])): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Adding vCenter Server to Datacenter ($datacenterName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) named ($($vcenterFqdn.Split(".")[0])), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to find Password alias in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) named ($userLockerAlias): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to find Datacenter named ($datacenterName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }                         
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMDatacenterVcenter

Function Undo-vRSLCMDatacenter {
    <#
        .SYNOPSIS
        Deletes a datacenter from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-vRSLCMDatacenter cmdlet deletes a datacenter from the VMware Aria Suite Lifecycle inventory. The
        cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the datacenter has not already been removed from the inventory
        - Deletes the datacenter from the inventory

        .EXAMPLE
        Undo-vRSLCMDatacenter -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -datacenterName xint-m01-dc01
        This example deletes a datacenter from the VMware Aria Suite Lifecycle inventory.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER datacenterName
        The name of the datacenter to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) { 
                            if (Get-vRSLCMDatacenter -datacenterName $datacenterName -ErrorAction SilentlyContinue ) {
                                Remove-vRSLCMDatacenter -datacenterVmid ((Get-vRSLCMDatacenter -datacenterName $datacenterName).datacenterVmid) | Out-Null
                                Start-Sleep 5
                                if (!(Get-vRSLCMDatacenter -datacenterName $datacenterName -ErrorAction SilentlyContinue )) {
                                    Write-Output "Removing Datacenter from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) inventory named ($datacenterName): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing Datacenter from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) inventory named ($datacenterName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing Datacenter from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) inventory named ($datacenterName), does not exist: SKIPPED"
                            }
                        }
                    }
                }                         
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Undo-vRSLCMDatacenter

Function Update-vRSLCMPSPack {
    <#
        .SYNOPSIS
        Refresh Product Support Packs and Install.

        .DESCRIPTION
        The Update-vRSLCMPSPack cmdlet refreshes the available Product Support Packs and installs the required version
        to VMware Aria Suite Lifecycle. The cmdlet connects to SDDC Manager using the -server, -user, and -password
        values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that Aria Suite Lifecycle has been deployed in VCF-aware mode and retrieves its details
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle

        .EXAMPLE
        Update-vRSLCMPSPack -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -psPack PSPACK6
        This example refreshes the available Product Support Packs and installs the required version to VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER psPack
        The Product Support Pack to install.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$psPack
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            $request = Get-vRSLCMPSPack -checkOnline
                            Start-Sleep 3
                            Do { $getStatus = (Get-vRSLCMRequest $request.requestId).state } Until ($getStatus -ne "INPROGRESS")
                            if ($getStatus -eq "COMPLETED") {
                                $allPsPacks = Get-vRSLCMPSPack
                                $pspackId = ($allPsPacks | Where-Object {$_.fileName -like "*$psPack"}).pspackId
                                if ($pspackId) {
                                    $vcenterDetails = Get-vRSLCMDatacenterVcenter -datacenterVmid (Get-vRSLCMDatacenter).dataCenterVmid
                                    $request = Start-vRSLCMSnapshot -vcenterFqdn $vcenterDetails.vCenterHost -vcenterName $vcenterDetails.vCenterName -username $vcenterDetails.vcUsername
                                    Start-Sleep 3
                                    Do { $getStatus = (Get-vRSLCMRequest $request.requestId).state } Until ($getStatus -ne "INPROGRESS")
                                    if ($getStatus -eq "COMPLETED") {
                                        Start-Sleep 3
                                        $request = Install-vRSLCMPSPack -pspackId $pspackId
                                        Do { $getStatus = (Get-vRSLCMRequest $request.requestId).state } Until ($getStatus -ne "INPROGRESS") 
                                        Write-Output "Product Support Pack ($psPack) install started on VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): SUCCESSFUL"
                                    } else {
                                        Write-Error "VMware Aria Suite Lifecycle Snapshot Task ($($getStatus.vmid)) finished with state ($($getStatus)): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Product Support Pack ($psPack) not found in VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "VMware Aria Suite Lifecycle Product Support Pack Check Task ($($getStatus.vmid)) finished with state ($($getStatus)): POST_VALIDATION_FAILED"
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-vRSLCMPSPack

Function Request-vRSLCMBundle {
    <#
        .SYNOPSIS
        Request the download of the VMware Aria Suite Lifecycle bundle.

        .DESCRIPTION
        The Request-vRSLCMBundle cmdlet requests the download of the VMware Aria Suite Lifecycle bundle in SDDC
        Manager.

        .EXAMPLE
        Request-vRSLCMBundle -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example requests the download of the VMware Aria Suite Lifecycle bundle in SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                $releaseBom = Get-VCFRelease -domainId ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"})).id | Select-Object bom
                $vrslcmVersion = ($releaseBom.bom | Where-Object {$_.name -eq "VRSLCM"}).version
                if ((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).downloadStatus -ne 'SUCCESSFUL') {
                    $request = Request-VCFBundle -id (Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).id
                    Start-Sleep 5
                    Do { $taskStatus = Get-VCFTask -id $($request.id) | Select-Object status; Start-Sleep 5 } Until ($taskStatus -ne "IN_PROGRESS")
                    if ((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).downloadStatus -eq 'SUCCESSFUL') {
                        Write-Output "Download VMware Aria Suite Lifecycle Bundle ($((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).components.toVersion)) to SDDC Manager: SUCCESSFUL"
                    } else {
                        Write-Error "Download VMware Aria Suite Lifecycle Bundle ($((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).components.toVersion)) to SDDC Manager: POST_VALIDATION_FAILED"
                    }
                } else {
                    Write-Warning "Download VMware Aria Suite Lifecycle Bundle ($((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).components.toVersion)) to SDDC Manager, already downloaded: SKIPPED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Request-vRSLCMBundle

Function New-vRSLCMDeployment {
    <#
        .SYNOPSIS
        Deploy VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRSLCMDeployment cmdlet deploys VMware Aria Suite Lifecycle via SDDC Manager. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Suite Lifecycle has not been deployed
        - Requests a new deployment of VMware Aria Suite Lifecycle

        .EXAMPLE
        New-vRSLCMDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\vrslcmDeploySpec.json
        This example starts a deployment of VMware Aria Suite Lifecycle using the JSON Specification for VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER jsonFile
        The path to the JSON specification file to be used.

        .PARAMETER outputPath
        The path to the output file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$outputPath
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (!((Get-VCFVrslcm).fqdn -eq $jsonInput.aslcmFqdn)) {
                        if ($PsBoundParameters.ContainsKey("outputPath")) {
                            $jsonSpecFileName = $outputPath + (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmDeploymentSpec.json")
                        } else {
                            $jsonSpecFileName = (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmDeploymentSpec.json")
                        }
                        $deployVrslcmObject = @()
                        $deployVrslcmObject += [pscustomobject]@{
                            'apiPassword'           = $jsonInput.aslcmAdminPassword
                            'fqdn'                  = $jsonInput.aslcmFqdn
                            'nsxtStandaloneTier1Ip' = $jsonInput.aslcmIp
                            'sshPassword'           = $jsonInput.aslcmSshPassword
                        }
                        $deployVrslcmObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonSpecFileName
                        $releaseBom = Get-VCFRelease -domainId ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"})).id | Select-Object bom
                        $vrslcmVersion = ($releaseBom.bom | Where-Object {$_.name -eq "VRSLCM"}).version
                        if ((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).downloadStatus -eq 'SUCCESSFUL') {
                            $newRequest = New-VCFvRSLCM -json $jsonSpecFileName
                            Start-Sleep 5
                            Do { $request = Get-VCFTask -id $newRequest.id } Until ($request.status -ne "In Progress")
                            if ($request.status -eq "Failed") {
                                Write-Error "Deployment of VMware Aria Suite Lifecyle Finished with a Status ($(($request.status).ToUpper())): POST_VALIDATED_FAILED"
                            } else {
                                Write-Output "Deployment of VMware Aria Suite Lifecyle Finished with a Status: SUCCESSFUL"
                            }
                        } else {
                            Write-Error "VMware Aria Suite Lifecycle Bundle ($((Get-VCFBundle | Where-Object {$_.components.toVersion -eq $vrslcmVersion}).components.toVersion)) to SDDC Manager. Not Found: PRE_VALIDATION_FAILED"
                        }
                    } else {
                        Write-Warning "VMware Aria Suite Lifecycle Manager ($($jsonInput.aslcmFqdn)), already exists: SKIPPED"
                    }
                }
            }
        } else {
            Write-Error "JSON Specification file for VMware Aria Suite Lifecycle ($jsonFile), File Not Found: PRE_VALIDATED_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-vRSLCMDeployment

Function Undo-vRSLCMDeployment {
    <#
        .SYNOPSIS
        Remove VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-vRSLCMDeployment cmdlet removes VMware Aria Suite Lifecycle from SDDC Manager. The cmdlet connects to
        SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment exist in VMware Aria Suite Lifecycle
        - Requests a deletion of VMware Aria Suite Lifecycle

        .EXAMPLE
        Undo-vRSLCMDeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example starts the removal of VMware Aria Suite Lifecycle from SDDC Manager.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER rootPass
        The root password to authenticate to the SDDC Manager appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType "MANAGEMENT")) {
                    if (Get-VCFvRSLCM) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $scriptCommand = 'psql -h localhost -U postgres -d platform -c "update vrslcm set status = ''DISABLED''"'
                                Invoke-VMScript -VM  (($server).split('.')[-0]) -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass | Out-Null
                                $newRequest = Remove-VCFvRSLCM
                                Start-Sleep 3
                                Do { $request = Get-VCFTask -id $newRequest.id } Until ($request.status -ne "In Progress")
                                if ($request.status -eq "FAILED") {
                                    Write-Error "Removing VMware Aria Suite Lifecycle ($((Get-VCFvRSLCM).fqdn)) from SDDC Manager: POST_VALIDATED_FAILED"
                                } else {
                                    Write-Output "Removing VMware Aria Suite Lifecycle ($((Get-VCFvRSLCM).fqdn)) from SDDC Manager: SUCCESSFUL"
                                }
                            }
                        }
                    } else {
                        Write-Warning "Removing VMware Aria Suite Lifecycle from SDDC Manager, not present: SKIPPED"
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vRSLCMDeployment

Function Install-vRSLCMCertificate {
    <#
        .SYNOPSIS
        Install a signed certificate on VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Install-vRSLCMCertificate cmdlet installs a Certifiate Authority signed certificate on VMware Aria Suite
        Lifecycle. The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that VMware Aria Automation has not been deployed in VMware Cloud Foundation aware mode and retrieves its details
        - Install a signed certificate on VMware Aria Suite Lifecycle

        .EXAMPLE
        Install-vRSLCMCertificate -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -jsonFile .\vrslcmDeploySpec.json
        This example installs a Certifiate Authority signed certificate on VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER jsonFile
        The path to the JSON specification file to be used.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (Get-VCFCertificateAuthority -caType Microsoft) {
                        if ((Get-VCFVrslcm).fqdn -eq $jsonInput.aslcmFqdn) {
                            $outputPath = ($outputPath = Split-Path $jsonFile -Parent) + "\"
                            $csrGenerationSpecJson = '{
                                "csrGenerationSpec": {
                                    "country": "'
+ $jsonInput.country + '",
                                    "email": "'
+ $jsonInput.email + '",
                                    "keyAlgorithm": "'
+ $jsonInput.keyAlgorithm + '",
                                    "keySize": "'
+ $jsonInput.keySize + '",
                                    "locality": "'
+ $jsonInput.locality + '",
                                    "organization": "'
+ $jsonInput.organization + '",
                                    "organizationUnit": "'
+ $jsonInput.organizationUnit + '",
                                    "state": "'
+ $jsonInput.state + '"
                                    },
                                    "resources": [
                                        {
                                            "fqdn": "'
+(Get-VCFvRSLCM).fqdn+'",
                                            "name": "'
+(Get-VCFvRSLCM).fqdn.Split(".")[0]+'",
                                            "resourceId": "'
+(Get-VCFvRSLCM).id+'",
                                            "type": "VRSLCM"
                                        }
                                    ]
                                }'

                            $csrGenerationSpecJson | Out-File ($outputPath + ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmRequestCsrSpec.json")
                            $caTypeJson = '{
                                "caType": "Microsoft",
                                    "resources": [
                                        {
                                            "fqdn": "'
+(Get-VCFvRSLCM).fqdn+'",
                                            "name": "'
+(Get-VCFvRSLCM).fqdn.Split(".")[0]+'",
                                            "resourceId": "'
+(Get-VCFvRSLCM).id+'",
                                            "type": "VRSLCM"
                                        }
                                    ]
                                }'

                            $caTypeJson | Out-File ($outputPath + ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmRequestCertificateSpec.json")
                            $operationTypeJson = '{
                                "operationType": "INSTALL",
                                    "resources": [
                                        {
                                            "fqdn": "'
+(Get-VCFvRSLCM).fqdn+'",
                                            "name": "'
+(Get-VCFvRSLCM).fqdn.Split(".")[0]+'",
                                            "resourceId": "'
+(Get-VCFvRSLCM).id+'",
                                            "type": "VRSLCM"
                                        }
                                    ]
                                }'

                            $operationTypeJson | Out-File ($outputPath + ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmUpdateCertificateSpec.json")
                            $newRequest = Request-VCFCertificateCSR -domainName (Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name -json ($outputPath + ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmRequestCsrSpec.json")
                            Start-Sleep 3
                            Do { $request = Get-VCFTask -id $newRequest.id } Until ($request.status -ne "IN_PROGRESS")
                                if ($request.status -eq "FAILED") {
                                    Write-Error "Generating VMware Aria Suite Lifecyle ($($jsonInput.aslcmFqdn)) Certifcate CSR: POST_VALIDATED_FAILED"
                                } else {
                                    $newRequest = Request-VCFCertificate -domainName (Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name -json ($outputPath + ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmRequestCertificateSpec.json")
                                    Start-Sleep 3
                                    Do { $request = Get-VCFTask -id $newRequest.id } Until ($request.status -ne "IN_PROGRESS")
                                    if ($request.status -eq "FAILED") {
                                        Write-Error "Generating VMware Aria Suite Lifecyle ($($jsonInput.aslcmFqdn)) Certifcate: POST_VALIDATED_FAILED"
                                    } else {
                                        $newRequest = Set-VCFCertificate -domainName (Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name -json ($outputPath + ((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "vrslcmUpdateCertificateSpec.json")
                                        Start-Sleep 3
                                        Do { $request = Get-VCFTask -id $newRequest.id } Until ($request.status -ne "In Progress")
                                        if ($request.status -eq "FAILED") {
                                            Write-Error "Installing VMware Aria Suite Lifecyle ($($jsonInput.aslcmFqdn)) Certifcate: POST_VALIDATED_FAILED"
                                        } else {
                                            Write-Output "Installing VMware Aria Suite Lifecyle ($($jsonInput.aslcmFqdn)) Certifcate: SUCCESSFUL"
                                        }
                                    }
                                }
                        } else {
                            Write-Error "VMware Aria Suite Lifecycle Manager ($($jsonInput.aslcmFqdn)), Not Found: PRE_VALIDATION_FAILED"
                        }
                    } else {
                        Write-Error "Microsoft Certificate Authority Not Configured in SDDC Manager ($server): PRE_VALIDATION_FAILED"
                    }
                }
            }
        } else {
            Write-Error "JSON Specification file for VMware Aria Suite Lifecycle ($jsonFile), File Not Found: PRE_VALIDATED_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-vRSLCMCertificate

Function Connect-vRSLCMUpgradeIso {
    <#
        .SYNOPSIS
        Connects the upgrade ISO to VMware Aria Suite Lifecycle appliance.

        .DESCRIPTION
        The Connect-vRSLCMUpgradeIso cmdlet connects the upgrade ISO to VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validated the content library and ISO file are present
        - Connects the ISO to the VMware Aria Suite Lifecycle appliance

        .EXAMPLE
        Connect-vRSLCMUpgradeIso -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -contentLibrary Operations -libraryItem "VMware-Aria-Suite-Lifecycle-Appliance-8.14.0.4-22630472-updaterepo"
        This example connects the upgrade ISO to VMware Aria Suite Lifecycle appliance.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER contentLibrary
        The name of the vSphere content library.

        .PARAMETER libraryItem
        The name of the ISO file in the vSphere content library.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$contentLibrary,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$libraryItem
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                                if ($contentLibraryDetail = Get-ContentLibrary -Name $contentLibrary -Server $($($vcfVcenterDetails.fqdn)) -ErrorAction SilentlyContinue) {
                                    if ($isoName = (Get-ContentLibraryItem -ContentLibrary $contentLibrary -Name $libraryItem -ErrorAction SilentlyContinue).Name) { 
                                        $datastore = Get-Datastore -Name $contentLibraryDetail.Datastore
                                        New-PSDrive -Name TempDrive -PSProvider VimDatastore -Root '\' -Location $datastore | Out-Null
                                        $isoPath = Get-ChildItem -Path "TempDrive:" -Recurse -Filter "$libraryItem*" | Select-Object -ExpandProperty DatastoreFullPath
                                        Remove-PSDrive -Name TempDrive -Confirm:$false | Out-Null
                                        if ($isoPath) {
                                            if (Get-VM -Name $vcfVrslcmDetails.hostname -Server $vcfVcenterDetails.fqdn) {
                                                if (!((Get-CDDrive -VM ($vcfVrslcmDetails.fqdn).Split('.')[-0]).IsoPath)) {
                                                    Get-VM -Name $vcfVrslcmDetails.hostname | Get-CDDrive | Set-CDDrive -Connected $true -IsoPath $isoPath -Confirm:$False | Out-Null
                                                    if ((Get-CDDrive -VM ($vcfVrslcmDetails.fqdn).Split('.')[-0]).IsoPath) {
                                                        Write-Output "Attaching Upgrade ISO to VMware Aria Suite Lifecycle instance ($(($vcfVrslcmDetails.fqdn))): SUCCESSFUL"
                                                    } else {
                                                        Write-Error "Attaching Upgrade ISO to VMware Aria Suite Lifecycle instance ($(($vcfVrslcmDetails.fqdn))): POST_VALIDATION_FAILED"
                                                    }
                                                } else {
                                                    Write-Warning "Attaching Upgrade ISO to VMware Aria Suite Lifecycle instance ($(($vcfVrslcmDetails.fqdn))), already connected: SKIPPED"
                                                }
                                            } else {
                                                Write-Error "Unable to locate Virtual Machine ($($vcfVrslcmDetails.hostname)) in vCenter Server ($($($vcfVcenterDetails.fqdn))): PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Unable to establish the full ISO path in Content Library ($contentLibrary): PRE_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Unable to locate file ($libraryItem) in Content Library ($contentLibrary): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find Content Library ($contentLibrary) in vCenter Server ($($($vcfVcenterDetails.fqdn))): PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                        Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Connect-vRSLCMUpgradeIso

Function Disconnect-vRSLCMUpgradeIso {
    <#
        .SYNOPSIS
        Disconnects the upgrade ISO to VMware Aria Suite Lifecycle appliance.

        .DESCRIPTION
        The Disconnect-vRSLCMUpgradeIso cmdlet disconnects the upgrade ISO from VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Disconnects an ISO file from the VMware Aria Suite Lifecycle appliance

        .EXAMPLE
        Disconnect-vRSLCMUpgradeIso -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1!
        This example disconnects the upgrade ISO from VMware Aria Suite Lifecycle appliance.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                                if (Get-VM -Name $vcfVrslcmDetails.hostname -Server $vcfVcenterDetails.fqdn) {
                                    if ((Get-CDDrive -VM ($vcfVrslcmDetails.fqdn).Split('.')[-0]).IsoPath) {
                                        $scriptCommand = "eject"
                                        Invoke-VMScript -VM $vcfVrslcmDetails.hostname -ScriptText $scriptCommand -GuestUser $vcfVcenterDetails.root -GuestPassword $vcfVcenterDetails.rootPass | Out-Null
                                        Get-VM -Name $vcfVrslcmDetails.hostname | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$False | Out-Null
                                        if (!((Get-CDDrive -VM ($vcfVrslcmDetails.fqdn).Split('.')[-0]).IsoPath)) {
                                            Write-Output "Disconnecting Upgrade ISO to VMware Aria Suite Lifecycle instance ($(($vcfVrslcmDetails.fqdn))): SUCCESSFUL"
                                        } else {
                                            Write-Error "Disconnecting Upgrade ISO to VMware Aria Suite Lifecycle instance ($(($vcfVrslcmDetails.fqdn))): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Disconnecting Upgrade ISO from VMware Aria Suite Lifecycle instance ($(($vcfVrslcmDetails.fqdn))), not connected: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to locate Virtual Machine ($($vcfVrslcmDetails.hostname)) in vCenter Server ($($($vcfVcenterDetails.fqdn))): PRE_VALIDATION_FAILED"
                                }
                            }
                        }
                        Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Disconnect-vRSLCMUpgradeIso

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region W O R K S P A C E O N E A C C E S S F U N C T I O N S ###########

Function Export-GlobalWsaJsonSpec {
    <#
        .SYNOPSIS
        Create JSON specification for Global Workspace ONE Access

        .DESCRIPTION
        The Export-GlobalWsaJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation
        workbook to deploy and configure Global Workspace ONE Access:
        - Validates that the Planning and Preparation is available
        - Generates the JSON specification file using the Planning and Preparation workbook

        .EXAMPLE
        Export-GlobalWsaJsonSpec -workbook .\pnp-workbook.xlsx -jsonFile .\wsaDeploySpec.json
        This example creates a JSON specification for Global Workspace ONE Access using the Planning and Preparation Workbook.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER jsonFile
        The fully qualified path to the JSON specification file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        }
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Generation of Global Workspace ONE Access JSON (.json) Specification File"
        if (Test-Path -Path $workbook) {
            $pnpWorkbook = Open-ExcelPackage -Path $Workbook
            $jsonObject = @()
            $jsonObject += [pscustomobject]@{
            'sddcManagerFqdn'                   = $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value
            'sddcManagerUser'                   = $pnpWorkbook.Workbook.Names["sso_default_admin"].Value
            'sddcManagerPass'                   = $pnpWorkbook.Workbook.Names["administrator_vsphere_local_password"].Value
            'mgmtSddcDomainName'                = $pnpWorkbook.Workbook.Names["mgmt_sddc_domain"].Value
            'environmentName'                   = "globalenvironment"
            'contentLibraryName'                = $pnpWorkbook.Workbook.Names["vrslcm_xreg_content_library"].Value
            'xintDatacenter'                    = $pnpWorkbook.Workbook.Names["vrslcm_xreg_dc"].Value
            'xintLocation'                      = $pnpWorkbook.Workbook.Names["vrslcm_xreg_location"].Value
            'certificateAlias'                  = $pnpWorkbook.Workbook.Names["xreg_wsa_cert_name"].Value
            'globalPasswordAlias'               = $pnpWorkbook.Workbook.Names["global_env_admin_password_alias"].Value
            'globalPassword'                    = $pnpWorkbook.Workbook.Names["global_env_admin_username"].Value
            'globalUserName'                    = $pnpWorkbook.Workbook.Names["xreg_vra_root_username"].Value
            'rootPasswordAlias'                 = $pnpWorkbook.Workbook.Names["local_vcf_aware_wsa_root_password_alias"].Value
            'rootPassword'                      = $pnpWorkbook.Workbook.Names["local_vcf_aware_wsa_root_password"].Value
            'rootUserName'                      = $pnpWorkbook.Workbook.Names["local_vcf_aware_wsa_root_password_username"].Value
            'adminPasswordAlias'                = $pnpWorkbook.Workbook.Names["local_admin_password_alias"].Value
            'adminPassword'                     = $pnpWorkbook.Workbook.Names["local_admin_password"].Value
            'adminUserName'                     = $pnpWorkbook.Workbook.Names["local_admin_username"].Value
            'configAdminPasswordAlias'          = $pnpWorkbook.Workbook.Names["local_configadmin_password_alias"].Value
            'configAdminPassword'               = $pnpWorkbook.Workbook.Names["local_configadmin_password"].Value
            'configAdminUserName'               = $pnpWorkbook.Workbook.Names["local_configadmin_username"].Value
            'vcFqdn'                            = $pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value
            'vcHostname'                        = $pnpWorkbook.Workbook.Names["mgmt_vc_hostname"].Value
            'vmList'                            = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_hostname"].Value + "," + $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_hostname"].Value
            'antiAffinityRuleName'              = "anti-affinity-rule-wsa" # $pnpWorkbook.Workbook.Names["xreg_wsa_anti_affinity_rule"].Value
            'drsGroupNameWsa'                   = $pnpWorkbook.Workbook.Names["xreg_wsa_vm_group_name"].Value
            'stretchedCluster'                  = $pnpWorkbook.Workbook.Names["mgmt_stretched_cluster_chosen"].Value
            'drsVmGroupNameAz'                  = $pnpWorkbook.Workbook.Names["mgmt_az1_vm_group_name"].Value
            'ntpServer'                         = $pnpWorkbook.Workbook.Names["xregion_ntp1_server"].Value
            'domainFqdn'                        = $pnpWorkbook.Workbook.Names["region_ad_child_fqdn"].Value
            'domainBindDn'                      = $pnpWorkbook.Workbook.Names["child_ad_bind_dn"].Value
            'domainBindUser'                    = $pnpWorkbook.Workbook.Names["child_svc_wsa_ad_user"].Value
            'domainBindPass'                    = $pnpWorkbook.Workbook.Names["child_svc_wsa_ad_password"].Value
            'baseGroupDn'                       = $pnpWorkbook.Workbook.Names["child_ad_groups_ou"].Value
            'baseUserDn'                        = $pnpWorkbook.Workbook.Names["child_ad_users_ou"].Value
            'adGroups'                          = "$($pnpWorkbook.Workbook.Names["group_child_gg_wsa_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_child_gg_wsa_directory_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_child_gg_wsa_read_only"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrslcm_admins"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrslcm_release_managers"].Value)","$($pnpWorkbook.Workbook.Names["group_gg_vrslcm_content_developers"].Value)"
            'wsaAdminGroup'                     = $pnpWorkbook.Workbook.Names["group_child_gg_wsa_admins"].Value
            'wsaDirectoryAdminGroup'            = $pnpWorkbook.Workbook.Names["group_child_gg_wsa_directory_admins"].Value
            'wsaReadOnlyGroup'                  = $pnpWorkbook.Workbook.Names["group_child_gg_wsa_read_only"].Value
            'aslcmAdminGroup'                   = $pnpWorkbook.Workbook.Names["group_gg_vrslcm_admins"].Value
            'aslcmReleaseManagersGroup'         = $pnpWorkbook.Workbook.Names["group_gg_vrslcm_release_managers"].Value
            'aslcmContentDevelopersGroup'       = $pnpWorkbook.Workbook.Names["group_gg_vrslcm_content_developers"].Value
            'clusterFqdn'                       = $pnpWorkbook.Workbook.Names["xreg_wsa_virtual_fqdn"].Value
            'vmNameNodeA'                       = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_hostname"].Value
            'hostNameNodeA'                     = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_fqdn"].Value
            'ipNodeA'                           = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_ip"].Value
            'vmNameNodeB'                       = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_hostname"].Value
            'hostNameNodeB'                     = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_fqdn"].Value
            'ipNodeB'                           = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_ip"].Value
            'vmNameNodeC'                       = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_hostname"].Value
            'hostNameNodeC'                     = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_fqdn"].Value
            'ipNodeC'                           = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_ip"].Value
        }
        Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
            $jsonObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonFile
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            Foreach ($jsonValue in $jsonInput.psobject.properties) {
                if ($jsonValue.value -eq "Value Missing" -or $null -eq $jsonValue.value ) {
                    $issueWithJson = $true
                }
            }
            if ($issueWithJson) {
                Show-PowerValidatedSolutionsOutput -type ERROR -message  "Creation of JSON Specification file for Global Workspace ONE Access, missing data: POST_VALIDATION_FAILED"
            } else { 
                Show-PowerValidatedSolutionsOutput -message  "Creation of JSON Specification file for Global Workspace ONE Access: SUCCESSFUL"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message  "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-GlobalWsaJsonSpec

Function Invoke-GlobalWsaDeployment {
    <#
        .SYNOPSIS
        End-to-end Deployment of Global Workspace ONE Access

        .DESCRIPTION
        The Invoke-GlobalWsaDeployment cmdlet is a single function to deploy and configure Global Workspace ONE Access.

        .EXAMPLE
        Invoke-GlobalWsaDeployment -jsonFile .\wsaDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\"
        This example deploys and configures Global Workspace ONE Access using the JSON specification provided.

        .EXAMPLE
        Invoke-GlobalWsaDeployment -jsonFile .\wsaDeploySpec.json -certificates ".\certificates\" -binaries ".\binaries\" -useContentLibrary
        This example deploys and configures Global Workspace ONE Access using the JSON specification provided. and using a content library for VMware Aria Suite Lifecycle

        .PARAMETER jsonFile
        The fully qualified path to the JSON specification file.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER certificates
        The fully qualified path to the certificates folder.

        .PARAMETER binaries
        The fully qualified path to the binaries folder.

        .PARAMETER useContentLibrary
        Use a content library for VMware Aria Suite Lifecycle

        .PARAMETER standard
        Deploy Global Workspace ONE Access in standard mode.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificates,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$binaries,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$standard
    )

    # Define Reusable Parameters
    $lcmProductName = "VMware Aria Suite Lifecycle"
    $wsaProductName = "Workspace ONE Access"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Deployment of $wsaProductName"
        if (Test-Path -Path $jsonFile) {
            if (Test-Path -Path $workbook) {
                $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
                $wsaPem = $certificates + $jsonInput.certificateAlias + ".2.chain.pem"
                if (Test-Path -Path $wsaPem) {
                    $rootPem = $certificates + "Root64.pem"
                    if (Test-Path -Path $rootPem) {
                        if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                            if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                                    if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                        $failureDetected = $false

                                        
                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Creating a vSphere Content Library for Operational Management"
                                            $StatusMsg = Add-ContentLibrary -Server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ContentLibraryName $jsonInput.contentLibraryName -published -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                $wsaOvaPath = $binaries + (Get-ChildItem $binaries | Where-Object {$_.name -match "identity-manager"}).name
                                                if ((([regex]::Match(((Split-Path $wsaOvaPath -leaf)), "(?<=-)\d+\.\d+\.\d+").Value) -notin (Get-vRSLCMProductVersion -productId vidm))) {
                                                    Show-PowerValidatedSolutionsOutput -type ERROR -message "$wsaProductName OVA ($(Split-Path $wsaOvaPath -leaf)) does not match a supported version: PRE_VALIDATION_FAILED"; $failureDetected = $true
                                                } elseif (($wsaOvaPath -match "identity-manager")) {
                                                    Show-PowerValidatedSolutionsOutput -message "Importing $wsaProductName OVA into vSphere Content Library"
                                                    $StatusMsg = Import-ContentLibraryItem -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -contentLibrary $jsonInput.contentLibraryName -file $wsaOvaPath -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                } else {
                                                    Show-PowerValidatedSolutionsOutput -type ERROR -message "$wsaProductName OVA ($(Split-Path $wsaOvaPath -leaf)). File Not Found: PRE_VALIDATION_FAILED"
                                                }
                                            }
                                            $allDatacenters = Get-vRSLCMDatacenter
                                            foreach ($datacenter in $allDatacenters) {
                                                Sync-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid -vcenterName (Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenter.datacenterVmid).vcenterName | Out-Null
                                            }
                                        }
                                        
                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring Data Center and vCenter Server in $lcmProductName"
                                            $StatusMsg = New-vRSLCMDatacenter -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -datacenterName $jsonInput.xintDatacenter -location $jsonInput.xintLocation -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg"; $ErrorMsg = $null } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            Start-Sleep 3
                                            $userNameAlias = (Get-vRSLCMLockerPassword | Where-Object {$_.userName -match $jsonInput.vcHostname}).alias
                                            $StatusMsg = New-vRSLCMDatacenterVcenter -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -datacenterName $jsonInput.xintDatacenter -vcenterFqdn $jsonInput.vcfqdn -userLockerAlias $userNameAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg"; $ErrorMsg = $null } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) { 
                                            Show-PowerValidatedSolutionsOutput -message "Importing the $wsaProductName Certificate to $lcmProductName"
                                            $StatusMsg = Import-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -certChainPath $wsaPem -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Adding $wsaProductName Passwords to $lcmProductName"
                                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.globalPasswordAlias -password $jsonInput.globalPassword  -userName $jsonInput.globalUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.rootPasswordAlias -password $jsonInput.rootPassword  -userName $jsonInput.rootUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.adminPasswordAlias -password $jsonInput.adminPassword  -userName $jsonInput.adminUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            $StatusMsg = New-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.configAdminPasswordAlias -password $jsonInput.configAdminPassword  -userName $jsonInput.configAdminUserName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Deploying $wsaProductName Instance Using $lcmProductName"
                                            $commandSwitch = ""
                                            if ($PsBoundParameters.ContainsKey("standard")) {
                                                $commandSwitch = $commandSwitch + " -standard"
                                            }
                                            if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                $commandSwitch = $commandSwitch + " -useContentLibrary -contentLibrary $($jsonInput.contentLibraryName)"
                                            }
                                            $StatusMsg = Invoke-Expression "New-WsaDeployment -server $($jsonInput.sddcManagerFqdn) -user $($jsonInput.sddcManagerUser) -pass $($jsonInput.sddcManagerPass) -workbook $($workbook) -monitor $($commandSwitch) -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg"
                                            if ( $StatusMsg -contains "FAILED") { Show-PowerValidatedSolutionsOutput -type ERROR -message "Deployment of $automationProductName failed"; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            if ((Get-vRSLCMProductNode -environmentName $jsonInput.environmentName -product vidm).Count -gt 1) {
                                                Show-PowerValidatedSolutionsOutput -message "Configure an Anti-Affinity Rule and a Virtual Machine Group for a $wsaProductName Instance"
                                                $StatusMsg = Add-AntiAffinityRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.antiAffinityRuleName -antiAffinityVMs $jsonInput.vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                $StatusMsg = Add-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameWsa -drsGroupVMs $jsonInput.vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            if ($stretchedCluster -eq "Include") {
                                                Show-PowerValidatedSolutionsOutput -message "Adding the $wsaProductName Cluster Appliances to the First Availability Zone VM Group"
                                                $StatusMsg = Add-VmGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -name $jsonInput.drsVmGroupNameAz -vmList $jsonInput.vmList -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg"  } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configure NTP on $wsaProductName Virtual Appliances"
                                            $StatusMsg = Set-WorkspaceOneNtpConfig -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -vrslcmIntegrated -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "Configuring NTP on Workspace ONE Access Instance ($($jsonInput.clusterFqdn): SUCCESSFUL" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message "Configuring NTP on Workspace ONE Access Instance ($($jsonInput.clusterFqdn), already performed: SKIPPED" } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring the Domain and Domain Search Parameters on $wsaProductName"
                                            Show-PowerValidatedSolutionsOutput -type NOTE -message "AUTOMATION TO BE ADDED"
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Configuring an Identity Source for $wsaProductName"
                                            $StatusMsg = Add-WorkspaceOneDirectory -server (Get-VCFWSA).loadBalancerFqdn -user $jsonInput.adminUserName -pass $jsonInput.adminPassword -domain $jsonInput.domainFqdn -baseDnUser $jsonInput.baseUserDn -baseDnGroup $jsonInput.baseGroupDN -bindUserDn $jsonInput.domainBindDn -bindUserPass $jsonInput.domainBindPass -adGroups $jsonInput.adGroups -protocol ldaps -certificate $rootPem -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            $clusterNodes = (Get-vRSLCMProductNode -environmentName $jsonInput.environmentName -product vidm).hostname
                                            if ($clusterNodes.Count -gt 1) {
                                                Show-PowerValidatedSolutionsOutput -message "Adding the $wsaProductName Cluster Nodes as Identity Provider Connectors"
                                                $allNodes = @()
                                                $allNodes += ($clusterNodes -Split ",")[1]
                                                $allNodes += ($clusterNodes -Split ",")[2]
                                                Foreach ($node in $allNodes) {
                                                    Show-PowerValidatedSolutionsOutput -message "Adding Node ($node) as Identity Provider Connector to Workspace Access ONE Instance ($($jsonInput.clusterFqdn))"
                                                    $StatusMsg = Add-WorkspaceOneDirectoryConnector -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.domainFqdn -wsaNode $node -wsaUser $jsonInput.adminUserName -wsaPass $jsonInput.adminPassword -bindUserPass $jsonInput.domainBindPass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                                }
                                            }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Assiging Roles to Active Directory Groups for $wsaProductName"
                                            $wsaSuperAdminRole  = "Super Admin"
                                            $wsaDirAdminRole = "Directory Admin"
                                            $wsaReadOnlyRole = "ReadOnly Admin"
                                            Show-PowerValidatedSolutionsOutput -message "Attempting to Assign the ($wsaSuperAdminRole) Role to ($($jsonInput.wsaAdminGroup))"
                                            $StatusMsg = Add-WorkspaceOneRole -server (Get-VCFWSA).loadBalancerFqdn -user $jsonInput.adminUserName -pass $jsonInput.adminPassword -group $jsonInput.wsaAdminGroup -role $wsaSuperAdminRole -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            Show-PowerValidatedSolutionsOutput -message "Attempting to Assign the ($wsaDirAdminRole) Role to ($($jsonInput.wsaDirectoryAdminGroup))"
                                            $StatusMsg = Add-WorkspaceOneRole -server (Get-VCFWSA).loadBalancerFqdn -user $jsonInput.adminUserName -pass $jsonInput.adminPassword -group $jsonInput.wsaDirectoryAdminGroup -role $wsaDirAdminRole -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                            Show-PowerValidatedSolutionsOutput -message "Attempting to Assign the ($wsaReadOnlyRole) Role to ($($jsonInput.wsaReadOnlyGroup))"
                                            $StatusMsg = Add-WorkspaceOneRole -server (Get-VCFWSA).loadBalancerFqdn -user $jsonInput.adminUserName -pass $jsonInput.adminPassword -group $jsonInput.wsaReadOnlyGroup -role $wsaReadOnlyRole -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }

                                        if (!$failureDetected) {
                                            Show-PowerValidatedSolutionsOutput -message "Assign Roles to Active Directory Groups for $lcmProductName"
                                            Show-PowerValidatedSolutionsOutput -type NOTE -message "AUTOMATION TO BE ADDED"
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        Show-PowerValidatedSolutionsOutput -type ERROR -message "Certificate File (.pem) for Root Certificate Authority ($rootPem): File Not Found"
                    }
                } else {
                    Show-PowerValidatedSolutionsOutput -type ERROR -message "Certificate File (.pem) for $wsaProductName ($wsaPem): File Not Found"
                }
            } else {
                Show-PowerValidatedSolutionsOutput -type ERROR -message "Planning and Preparation Workbook (.xlsx) ($workbook): File Not Found"
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $wsaProductName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-CatchWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-GlobalWsaDeployment

Function Invoke-UndoGlobalWsaDeployment {
    <#
        .SYNOPSIS
        End-to-end removal of Global Workspace ONE Access

        .DESCRIPTION
        The Invoke-UndoGlobalWsaDeployment cmdlet is a single function to remove Global Workspace ONE Access.

        .EXAMPLE
        Invoke-UndoGlobalWsaDeployment -jsonFile .\wsaDeploySpec.json
        This example removes Global Workspace ONE Access using the JSON specification provided.

        .PARAMETER jsonFile
        The fully qualified path to the JSON specification file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$jsonFile
    )

    # Define Reusable Parameters
    $lcmProductName = "VMware Aria Suite Lifecycle"
    $wsaProductName = "Workspace ONE Access"

    Try {
        Show-PowerValidatedSolutionsOutput -type NOTE -message "Starting Removal of $wsaProductName"
        if (Test-Path -Path $jsonFile) {
            $jsonInput = (Get-Content -Path $jsonFile) | ConvertFrom-Json
            if (Test-VCFConnection -server $jsonInput.sddcManagerFqdn) {
                if (Test-VCFAuthentication -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domainType "MANAGEMENT")) {
                        if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $jsonInput.sddcManagerFqdn -username $jsonInput.sddcManagerUser -password $jsonInput.sddcManagerPass)) {
                            if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                                $failureDetected = $false

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Remove Roles for Active Directory Groups in $lcmProductName"
                                    Show-PowerValidatedSolutionsOutput -type NOTE -message "AUTOMATION TO BE ADDED"
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing an Anti-Affinity Rule and a Virtual Machine Group for $wsaProductName Instance"
                                    $StatusMsg = Undo-ClusterGroup -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -drsGroupName $jsonInput.drsGroupNameWsa -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-AntiAffinityRule -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -domain $jsonInput.mgmtSddcDomainName -ruleName $jsonInput.antiAffinityRuleName -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                            foreach ($vm in ($jsonInput.vmList -Split ',')) {
                                                if (Get-VM -name $vm -ErrorAction SilentlyContinue ) {
                                                    Get-VM -name $vm | Stop-VM -RunAsync -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                    Do {$powerState = (Get-VM -name $vm | Select-Object PowerState).PowerState } Until ($powerState -eq "PoweredOff")
                                                    Get-VM -name $vm | Remove-VM -DeletePermanently -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
                                                }
                                            }
                                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                                            Show-PowerValidatedSolutionsOutput -message "Deleting $automationProductName from $lcmProductName"
                                            $StatusMsg = Undo-WsaDeployment -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -environmentName $jsonInput.environmentName -monitor -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                            if ($StatusMsg) { Show-PowerValidatedSolutionsOutput -message $StatusMsg } elseif ($WarnMsg) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ($ErrorMsg) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                        }
                                    }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing Data Center and vCenter Server from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMDatacenter -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -datacenterName $jsonInput.xintDatacenter -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg"; $ErrorMsg = $null } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) { 
                                    Show-PowerValidatedSolutionsOutput -message "Removing the $wsaProductName Certificate from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerCertificate -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -certificateAlias $jsonInput.certificateAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }

                                if (!$failureDetected) {
                                    Show-PowerValidatedSolutionsOutput -message "Removing $wsaProductName Passwords from $lcmProductName"
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.globalPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.rootPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.adminPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                    $StatusMsg = Undo-vRSLCMLockerPassword -server $jsonInput.sddcManagerFqdn -user $jsonInput.sddcManagerUser -pass $jsonInput.sddcManagerPass -alias $jsonInput.configAdminPasswordAlias -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -WarningVariable WarnMsg -ErrorVariable ErrorMsg
                                    if ( $StatusMsg ) { Show-PowerValidatedSolutionsOutput -message "$StatusMsg" } elseif ( $WarnMsg ) { Show-PowerValidatedSolutionsOutput -type WARNING -message $WarnMsg } elseif ( $ErrorMsg ) { Show-PowerValidatedSolutionsOutput -Type ERROR -message $ErrorMsg; $failureDetected = $true }
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Show-PowerValidatedSolutionsOutput -type ERROR -message "JSON Specification file for $wsaProductName ($jsonFile): File Not Found"
        }
    } Catch {
        Debug-CatchWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-UndoGlobalWsaDeployment

Function Export-WsaJsonSpec {
    <#
        .SYNOPSIS
        Create Workspace ONE Access JSON specification.

        .DESCRIPTION
        The Export-WsaJsonSpec cmdlet creates the JSON specification file using the Planning and Preparation workbook
        to deploy Workspace ONE Access using VMware Aria Suite Lifecycle:
        - Validates that the Planning and Preparation is available
        - Validates that network connectivity is available to VMware Aria Suite Lifecycle
        - Makes a connection to the VMware Aria Suite Lifecycle instance and validates that authentication possible
        - Generates the JSON specification file using the Planning and Preparation workbook and details from VMware Aria Suite Lifecycle

        .EXAMPLE
        Export-WsaJsonSpec -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx
        This example creates a JSON deployment specification of Clustered Workspace ONE Access using the Planning and Preparation Workbook

        .EXAMPLE
        Export-WsaJsonSpec -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx -standard
        This example creates a JSON deployment specification of Standard Workspace ONE Access using the Planning and Preparation Workbook

        .EXAMPLE
        Export-WsaJsonSpec -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx -customVersion 3.3.7
        This example creates a JSON deployment specification of Clustered Workspace ONE Access using a custom version and the Planning and Preparation Workbook

        .EXAMPLE
        Export-WsaJsonSpec -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx -useContentLibrary -contentLibrary Operations
        This example creates a JSON deployment specification of Clustered Workspace ONE Access using the Planning and Preparation Workbook and deploying the OVA from a vSphere Content Library.

        .PARAMETER server
        The fully qualified domain name of the VMware Aria Suite Lifecycle instance.

        .PARAMETER user
        The username of the VMware Aria Suite Lifecycle instance.

        .PARAMETER pass
        The password of the VMware Aria Suite Lifecycle instance.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER standard
        Switch to deploy Workspace ONE Access in Standard (Single Node) mode.

        .PARAMETER customVersion
        The version of Workspace ONE Access to deploy.

        .PARAMETER useContentLibrary
        Switch to deploy the Workspace ONE Access OVA from a vSphere Content Library.

        .PARAMETER contentLibrary
        The name of the vSphere Content Library to deploy the Workspace ONE Access OVA from.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$standard,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("workbook")) {
            $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
        } else {
            if (!(Test-Path -Path $workbook)) {
                Write-Error  "Planning and Preparation Workbook (.xlsx) '$workbook' File Not Found"
                Break
            }
        }

        if ($PsBoundParameters.ContainsKey("standard")) { $deploymentType = "Standard (Single Node)" } else { $deploymentType = "Clustered"}
        $pnpWorkbook = Open-ExcelPackage -Path $workbook

        ### Obtain Configuration Information from VMware Aria Suite Lifecycle
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    $vcfVersion = ((Get-VCFManager).version -Split ('\.\d{1}\-\d{8}')) -split '\s+' -match '\S'
                    $jsonSpecFileName = (((Get-VCFWorkloadDomain | Where-Object { $_.type -eq "MANAGEMENT" }).name) + "-" + "wsaDeploymentSpec.json")
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {   
                            if ($wsaCertificate = Get-vRSLCMLockerCertificate | Where-Object { $_.alias -eq $pnpWorkbook.Workbook.Names["xreg_wsa_cert_name"].Value }) {
                                if ($defaultPassword = Get-vRSLCMLockerPassword -alias $pnpWorkbook.Workbook.Names["global_env_admin_password_alias"].Value) { 
                                    if ($configAdminPassword = Get-vRSLCMLockerPassword -alias $pnpWorkbook.Workbook.Names["local_configadmin_password_alias"].Value) { 
                                        if ($wsaPassword = Get-vRSLCMLockerPassword -alias $pnpWorkbook.Workbook.Names["local_admin_password_alias"].Value) {
                                            if ($vcfVersion -ge "4.5.0") {
                                                $vcCredentials = Get-vRSLCMLockerPassword | Where-Object { $_.userName -match (($pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value).Split(".")[0] + "@vsphere.local") }
                                            } else {
                                                $vcCredentials = Get-vRSLCMLockerPassword -alias (($pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value).Split(".")[0] + "-" + $pnpWorkbook.Workbook.Names["mgmt_datacenter"].Value)
                                            }
                                            if ($datacenterName = Get-vRSLCMDatacenter | Where-Object { $_.dataCenterName -eq $pnpWorkbook.Workbook.Names["vrslcm_xreg_dc"].Value }) {
                                                $xintEnvironment = Get-vRSLCMEnvironment | Where-Object { $_.environmentName -eq $pnpWorkbook.Workbook.Names["vrslcm_xreg_env"].Value }
                                                
                                                #### Generate the Workspace ONE Properties Section
                                                if (!$PsBoundParameters.ContainsKey("customVersion")) {
                                                    if ($vcfVersion -eq "4.3.0") { $wsaVersion = "3.3.5" }
                                                    if ($vcfVersion -eq "4.3.1") { $wsaVersion = "3.3.5" }
                                                    if ($vcfVersion -eq "4.4.0") { $wsaVersion = "3.3.6" }
                                                    if ($vcfVersion -eq "4.4.1") { $wsaVersion = "3.3.6" }
                                                    if ($vcfVersion -eq "4.5.0") { $wsaVersion = "3.3.6" }
                                                    if ($vcfVersion -eq "4.5.1") { $wsaVersion = "3.3.7" }
                                                    if ($vcfVersion -eq "4.5.2") { $wsaVersion = "3.3.7" }
                                                    if ($vcfVersion -eq "5.0.0") { $wsaVersion = "3.3.7" }
                                                    if ($vcfVersion -eq "5.1.0") { $wsaVersion = "3.3.7" }
                                                } else {
                                                    $wsaVersion = $customVersion
                                                }

                                                $infrastructurePropertiesObject = @()
                                                $infrastructurePropertiesObject += [pscustomobject]@{
                                                    'acceptEULA'        = "true"
                                                    'enableTelemetry'   = "true"
                                                    'regionName'        = "default"
                                                    'zoneName'          = "default"
                                                    'dataCenterVmid'    = $datacenterName.dataCenterVmid
                                                    'vCenterName'       = ($pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value).Split(".")[0]
                                                    'vCenterHost'       = $pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value
                                                    'vcUsername'        = $vcCredentials.userName
                                                    'vcPassword'        = ("locker:password:" + $($vcCredentials.vmid) + ":" + $($vcCredentials.alias))
                                                    'defaultPassword'   = ("locker:password:" + $($defaultPassword.vmid) + ":" + $($defaultPassword.alias))
                                                    'certificate'       = ("locker:certificate:" + $($wsaCertificate.vmid) + ":" + $($wsaCertificate.alias))
                                                    'cluster'           = ($pnpWorkbook.Workbook.Names["mgmt_datacenter"].Value + "#" + $pnpWorkbook.Workbook.Names["mgmt_cluster"].Value)
                                                    'storage'           = $pnpWorkbook.Workbook.Names["mgmt_vsan_datastore"].Value
                                                    'diskMode'          = "thin"
                                                    'network'           = $pnpWorkbook.Workbook.Names["xreg_seg01_name"].Value
                                                    'masterVidmEnabled' = "false"
                                                    'dns'               = ($pnpWorkbook.Workbook.Names["region_dns1_ip"].Value + "," + $pnpWorkbook.Workbook.Names["region_dns2_ip"].Value)
                                                    'domain'            = $pnpWorkbook.Workbook.Names["region_ad_parent_fqdn"].Value
                                                    'gateway'           = $pnpWorkbook.Workbook.Names["xreg_seg01_gateway_ip"].Value
                                                    'netmask'           = $pnpWorkbook.Workbook.Names["xreg_seg01_mask"].Value
                                                    'searchpath'        = $pnpWorkbook.Workbook.Names["parent_dns_zone"].Value
                                                    'timeSyncMode'      = "ntp"
                                                    'ntp'               = $pnpWorkbook.Workbook.Names["xregion_ntp1_server"].Value
                                                    'vcfProperties'     = '{"vcfEnabled":true,"sddcManagerDetails":[{"sddcManagerHostName":"' + $pnpWorkbook.Workbook.Names["sddc_mgr_fqdn"].Value + '","sddcManagerName":"default","sddcManagerVmid":"default"}]}'
                                                }

                                                $infrastructureObject = @()
                                                $infrastructureObject += [pscustomobject]@{
                                                    'properties'    = ($infrastructurePropertiesObject | Select-Object -Skip 0)
                                                }

                                                ### Generate the Properties Details
                                                if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                                    $contentLibraryItems = ((Get-vRSLCMDatacenterVcenter -datacenterVmid $datacenterName.dataCenterVmid -vcenterName ($pnpWorkbook.Workbook.Names["mgmt_vc_fqdn"].Value).Split(".")[0]).contentLibraries | Where-Object { $_.contentLibraryName -eq $contentLibrary }).contentLibraryItems
                                                    if ($contentLibraryItems) {
                                                        $contentLibraryItemId = ($contentLibraryItems | Where-Object { $_.contentLibraryItemName -match "identity-manager-$wsaVersion" }).contentLibraryItemId
                                                    } else {
                                                        Write-Error "Unable to find vSphere Content Library ($contentLibrary) or Content Library Item in VMware Aria Suite Lifecycle: PRE_VALIDATION_FAILED"
                                                        Break
                                                    }
                                                }
                                                $productPropertiesObject = @()
                                                $productPropertiesObject += [pscustomobject]@{
                                                    'vidmAdminPassword'            = ("locker:password:" + $($wsaPassword.vmid) + ":" + $($wsaPassword.alias))
                                                    'syncGroupMembers'             = $true
                                                    'nodeSize'                     = ($pnpWorkbook.Workbook.Names["xreg_wsa_node_size"].Value).ToLower()
                                                    'defaultConfigurationEmail'    = $pnpWorkbook.Workbook.Names["xreg_configadmin_email"].Value
                                                    'defaultConfigurationUsername' = $pnpWorkbook.Workbook.Names["local_configadmin_username"].Value
                                                    'defaultConfigurationPassword' = ("locker:password:" + $($configAdminPassword.vmid) + ":" + $($configAdminPassword.alias))
                                                    'defaultTenantAlias'           = ""
                                                    'vidmDomainName'               = ""
                                                    'certificate'                  = ("locker:certificate:" + $($wsaCertificate.vmid) + ":" + $($wsaCertificate.alias))
                                                    'contentLibraryItemId'         = $contentLibraryItemId
                                                    'fipsMode'                     = "false"
                                                }

                                                #### Generate Workspace ONE Access Details
                                                if (!$PsBoundParameters.ContainsKey("standard")) {
                                                    $clusterLbProperties = @()
                                                    $clusterLbProperties += [pscustomobject]@{
                                                        'controllerType'        = "NSX_T"
                                                        'hostName'                = $pnpWorkbook.Workbook.Names["xreg_wsa_virtual_fqdn"].Value
                                                        'lockerCertificate'     = ("locker:certificate:" + $($wsaCertificate.vmid) + ":" + $($wsaCertificate.alias))
                                                    }
                                                
                                                    $clusterDelegateObject = @()
                                                    $clusterDelegateObject += [pscustomobject]@{
                                                        'ip' = $pnpWorkbook.Workbook.Names["xreg_wsa_delegate_ip"].Value
                                                    }

                                                    $clusterVipsObject = @()
                                                    $clusterVipsObject += [pscustomobject]@{
                                                        'type'       = "vidm-lb"
                                                        'properties'    = ($clusterLbProperties | Select-Object -Skip 0)
                                                    }
                                                    $clusterVipsObject += [pscustomobject]@{
                                                        'type'       = "vidm-delegate"
                                                        'properties'    = ($clusterDelegateObject | Select-Object -Skip 0)
                                                    }

                                                    $clusterObject = @()
                                                    $clusterObject += [pscustomobject]@{
                                                        'clusterVips'    = $clusterVipsObject
                                                    }
                                                } else {
                                                    $clusterObject = @()
                                                    $clusterObject += [pscustomobject]@{
                                                        'clusterVips'    = @()
                                                    }
                                                }

                                                #### Generate Worspace ONE Access Node Details
                                                $wsaPrimaryProperties = @()
                                                $wsaPrimaryProperties += [pscustomobject]@{
                                                    'hostName' = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_fqdn"].Value
                                                    'vmName'   = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_hostname"].Value
                                                    'ip'       = $pnpWorkbook.Workbook.Names["xreg_wsa_nodea_ip"].Value
                                                }

                                                $wsaSecondary1Properties = @()
                                                $wsaSecondary1Properties += [pscustomobject]@{
                                                    'hostName' = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_fqdn"].Value
                                                    'vmName'   = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_hostname"].Value
                                                    'ip'       = $pnpWorkbook.Workbook.Names["xreg_wsa_nodeb_ip"].Value
                                                }

                                                $wsaSecondary2Properties = @()
                                                $wsaSecondary2Properties += [pscustomobject]@{
                                                    'hostName' = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_fqdn"].Value
                                                    'vmName'   = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_hostname"].Value
                                                    'ip'       = $pnpWorkbook.Workbook.Names["xreg_wsa_nodec_ip"].Value
                                                }

                                                $nodesObject = @()
                                                $nodesobject += [pscustomobject]@{
                                                    'type'       = "vidm-primary"
                                                    'properties'    = ($wsaPrimaryProperties | Select-Object -Skip 0)
                                                }
                                                if (!$PsBoundParameters.ContainsKey("standard")) {
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'       = "vidm-secondary"
                                                        'properties'    = ($wsaSecondary1Properties | Select-Object -Skip 0)
                                                    }
                                                    $nodesobject += [pscustomobject]@{
                                                        'type'       = "vidm-secondary"
                                                        'properties'    = ($wsaSecondary2Properties | Select-Object -Skip 0)
                                                    }
                                                }

                                                $productsObject = @()
                                                $productsObject += [pscustomobject]@{
                                                    'id'         = "vidm"
                                                    'version'    = $wsaVersion
                                                    'properties'    = ($productPropertiesObject  | Select-Object -Skip 0)
                                                    'clusterVIP'    = ($clusterObject  | Select-Object -Skip 0)
                                                    'nodes'      = $nodesObject    
                                                }
                                                
                                                $wsaDeploymentObject = @()
                                                $wsaDeploymentObject += [pscustomobject]@{
                                                    'environmentId'   = "globalenvironment"
                                                    'environmentName' = "globalenvironment"
                                                    'infrastructure'  = ($infrastructureObject  | Select-Object -Skip 0)
                                                    'products'        = $productsObject
                                                } 

                                                $wsaDeploymentObject | ConvertTo-Json -Depth 12 | Out-File -Encoding UTF8 -FilePath $jsonSpecFileName 
                                                Write-Output "Creation of Deployment JSON Specification file for $deploymentType Workspace ONE Access: SUCCESSFUL"
                                            } else {
                                                Write-Error "Datacenter Provided in the Planning and Preparation Workbook '$($pnpWorkbook.Workbook.Names["vrslcm_xreg_dc"].Value)' does not exist, create and retry"
                                            }
                                        } else {
                                            Write-Error "Root Password with alias '$($pnpWorkbook.Workbook.Names["local_admin_password_alias"].Value)' not found in the VMware Aria Suite Lifecycle Locker, add and retry"
                                        }
                                    } else {
                                        Write-Error "Admin Password with alias '$($pnpWorkbook.Workbook.Names["global_env_admin_password_alias"].Value)' not found in the VMware Aria Suite Lifecycle Locker, add and retry"
                                    }
                                } else {
                                    Write-Error "Certificate with alias '$($pnpWorkbook.Workbook.Names["local_configadmin_password_alias"].Value)' not found in the VMware Aria Suite Lifecycle Locker, add and retry"
                                }
                            } else {
                                Write-Error "Certificate with alias '$($pnpWorkbook.Workbook.Names["xreg_wsa_cert_name"].Value)' not found in the VMware Aria Suite Lifecycle Locker, add and retry"
                            }
                        }
                    }
                }
            }
        }
        Close-ExcelPackage $pnpWorkbook -NoSave -ErrorAction SilentlyContinue
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Export-WsaJsonSpec

Function New-WSADeployment {
    <#
        .SYNOPSIS
        Deploy Workspace ONE Access to VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-WSADeployment cmdlet deploys Workspace ONE Access via VMware Aria Suite Lifecycle. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity is available to the SDDC Manager instance
        - Makes a connection to the SDDC Manager instance and validates that authentication possible
        - Validates that Workspace ONE Access has not been deployed in VMware Cloud Foundation aware mode
        - Requests a new deployment of a Workspace ONE Access

        .EXAMPLE
        New-WSADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx
        This example starts a deployment of a clustered Workspace ONE Access using the Planning and Preparation Workbook

        .EXAMPLE
        New-WSADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx -standard
        This example starts a deployment of a standard Workspace ONE Access using the Planning and Preparation Workbook

        .EXAMPLE
        New-WSADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx -customVersion 3.3.7
        This example starts a deployment of Workspace ONE Access using a custom version and the Planning and Preparation Workbook

        .EXAMPLE
        New-WSADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -workbook .\pnp-workbook.xlsx -useContentLibrary -contentLibrary Operations
        This example starts a deployment of a Clustered Workspace ONE Access using the Planning and Preparation Workbook and deploying the OVA from a vSphere Content Library.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER workbook
        The path to the Planning and Preparation Workbook (.xlsx) file.

        .PARAMETER monitor
        Switch to monitor the deployment of Workspace ONE Access.

        .PARAMETER standard
        Switch to deploy Workspace ONE Access in Standard (Single Node) mode.

        .PARAMETER customVersion
        The version of Workspace ONE Access to deploy.

        .PARAMETER useContentLibrary
        Switch to deploy the Workspace ONE Access OVA from a vSphere Content Library.

        .PARAMETER contentLibrary
        The name of the vSphere Content Library to deploy the Workspace ONE Access OVA from.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$workbook,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$standard,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$customVersion,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [Switch]$useContentLibrary,
        [Parameter (Mandatory = $false, ParameterSetName = 'useContentLibrary')] [ValidateNotNullOrEmpty()] [String]$contentLibrary
    )

    if (!$PsBoundParameters.ContainsKey("workbook")) {
        $workbook = Get-ExternalFileName -title "Select the Planning and Preparation Workbook (.xlsx)" -fileType "xlsx" -location "default"
    } else {
        if (!(Test-Path -Path $workbook)) {
            Write-Error  "Planning and Preparation Workbook (.xlsx) '$workbook' File Not Found"
            Break
        }
    }

    if ($PsBoundParameters.ContainsKey("standard")) { $deploymentType = "Standard (Single Node)" } else { $deploymentType = "Clustered" }

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            $commandSwitch = ""
                            if ($PsBoundParameters.ContainsKey("customVersion")) {
                                $commandSwitch = $commandSwitch + " -customVersion $customVersion"
                            }
                            if ($PsBoundParameters.ContainsKey("standard")) {
                                $commandSwitch = $commandSwitch + " -standard"
                            }
                            if ($PsBoundParameters.ContainsKey("useContentLibrary")) {
                                $commandSwitch = $commandSwitch + " -useContentLibrary -contentLibrary $contentLibrary"
                            }
                            Invoke-Expression "Export-WSAJsonSpec -server $server -user $user -pass $pass -workbook $workbook $($commandSwitch) -ErrorAction SilentlyContinue -ErrorVariable ErrorMsg | Out-Null"
                            if (!$ErrorMsg) {
                                $pnpWorkbook = Open-ExcelPackage -Path $workbook
                                $loadBalancerFqdn = $pnpWorkbook.Workbook.Names["xreg_wsa_virtual_fqdn"].Value
                                $loadBalancerIp = $pnpWorkbook.Workbook.Names["xreg_wsa_virtual_ip"].Value
                                if (!(((Get-vRSLCMLoadbalancer -type NSX_T) | Where-Object {$_.loadBalancerDetails -match $loadBalancerFqdn}))) {
                                    New-vRSLCMLoadbalancer -type NSX_T -loadBalancerIp $loadBalancerIp -loadBalancerFqdn $loadBalancerFqdn | Out-Null
                                }
                                $jsonSpecFileName = (((Get-VCFWorkloadDomain | Where-Object {$_.type -eq "MANAGEMENT"}).name) + "-" + "wsaDeploymentSpec.json")
                                $json = (Get-Content -Raw $jsonSpecFileName)
                                $jsonSpec = $json | ConvertFrom-Json
                                if (!(Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $jsonSpec.environmentName})) {
                                    if (Get-vRSLCMLockerPassword -alias $($jsonSpec.products.properties.vidmAdminPassword.Split(":")[3])) {
                                        if (Get-vRSLCMLockerPassword -alias $($jsonSpec.products.properties.defaultConfigurationPassword.Split(":")[3])) {
                                            if (Get-vRSLCMLockerCertificate | Where-Object {$_.alias -Match $($jsonSpec.products.properties.certificate.Split(":")[3])}) {
                                                $newRequest = Add-vRSLCMEnvironment -json $json
                                                if ($newRequest) {
                                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                                        Start-Sleep 10
                                                        Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                                    } else {
                                                        Write-Output "Deployment Request for $deploymentType Workspace ONE Access (Request Ref: $($newRequest.requestId))"
                                                    }
                                                } else {
                                                    Write-Error "Request to deploy $deploymentType Workspace ONE Access failed, check the VMware Aria Suite Lifecycle UI"
                                                }
                                                
                                            } else {
                                                Write-Error "Certificate in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.certificate.Split(":")[3])), does not exist: : PRE_VALIDATED_FAILED"
                                            }
                                        } else {
                                            Write-Error "Password in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.defaultConfigurationPassword.Split(":")[3])), does not exist: : PRE_VALIDATED_FAILED"
                                        }
                                    } else {
                                        Write-Error "Password in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($($jsonSpec.products.properties.vidmAdminPassword.Split(":")[3])), does not exist: : PRE_VALIDATED_FAILED"
                                    }
                                } else {
                                    Write-Warning "$deploymentType Workspace ONE Access in environment ($($jsonSpec.environmentName)) on VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "JSON specification validation: PRE_VALIDATED_FAILED"
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function New-WSADeployment

Function Undo-WSADeployment {
    <#
        .SYNOPSIS
        Remove the Workspace ONE Access from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Undo-WSADeployment cmdlet removes Workspace ONE Access from VMware Aria Suite Lifecycle. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values.
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Validates that the environment exist in VMware Aria Suite Lifecycle
        - Requests a the deletion of Workspace ONE Access from VMware Aria Suite Lifecycle

        .EXAMPLE
        Undo-WSADeployment -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -environmentName globalenvironment
        This example starts a removal of Workspace ONE Access from VMware Aria Suite Lifecycle.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER environmentName
        The Workspace ONE Access Environment Name.

        .PARAMETER monitor
        Monitor the VMware Aria Suite Lifecycle request.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$monitor
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName -and $_.products.id -eq 'vidm'}) {
                                $newRequest = Remove-vRSLCMEnvironment -environmentId (Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName}).environmentId -productId vidm -ErrorAction SilentlyContinue
                                if ($newRequest) {
                                    if ($PsBoundParameters.ContainsKey("monitor")) {
                                        Start-Sleep 10
                                        $status = Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                        if (!(Get-vRSLCMEnvironment | Where-Object {$_.environmentName -eq $environmentName -and $_.products.id -eq 'vidm'})) {
                                            if ($status -match "COMPLETED") {
                                                Write-Output "Removal of Workspace ONE Access from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): SUCCESSFUL"
                                            } else {
                                                Write-Error "Removal of Workspace ONE Access from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Removal of Workspace ONE Access from Environment ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Output "Removal request of Workspace ONE Access Submitted Successfully (Request Ref: $($newRequest.requestId))"
                                    }
                                } else {
                                    Write-Error "Removal request of Workspace ONE Access failed, check the VMware Aria Suite Lifecycle UI: POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Environment with name ($environmentName) in VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)), already removed: SKIPPED"
                            }
                        }
                    }
                } 
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-WSADeployment

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region S H A R E D P O W E R V A L I D A T E D S O L U T I O N S F U N C T I O N S ###########

Function Add-vCenterGlobalPermission {
    <#
        .SYNOPSIS
        Adds a Global Permission to a user or group
        
        .DESCRIPTION
        The Add-vCenterGlobalPermission cmdlets assigns the vCenter Server Global Permission to the user or group provided.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the bind credentials are valid
        - Validates that the domain is present in vCenter Server as an Identity Provider
        - Validates the user or group exists in Active Directory
        - Assigns the user or group to the vCenter Global Permission

        If -localDomain is selected, then AD authentication check is skipped and user/group is checked for in the local directory

        .EXAMPLE
        Add-vCenterGlobalPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -principal gg-kub-admins -role Admin -propagate true -type group
        This example adds the group gg-vc-admins from domain sfo.rainpole.io to the Global Permissions with the Administrator role for vCenter Server instances in the same vCenter Single Sign-On domain as management domain sfo-m01.

        .EXAMPLE
        Add-vCenterGlobalPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-w01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -principal gg-vc-admins -role Admin -propagate true -type group
        This example adds the group gg-vc-admins from domain sfo.rainpole.io to the Global Permissions with the Administrator role for vCenter Server instances in the same vCenter Single Sign-On domain as workload domain sfo-w01.

        .EXAMPLE
        Add-vCenterGlobalPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain vsphere.local -principal svc-sfo-m01-nsx01-sfo-m01-vc01 -role "NSX to vSphere Integration" -propagate true -type user -localdomain
        This example adds the user svc-sfo-m01-nsx01-sfo-m01-vc01@vsphere.local from the vCenter Single Sign-on domain vsphere.local to Global Permissions with the "NSX to vSphere Integration" role for vCenter Server instances in the same vCenter Single Sign-On domain as management domain sfo-m01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The SDDC Manager management or workload domain name.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER domainBindUser
        The Active Directory bind user name.

        .PARAMETER domainBindPass
        The Active Directory bind password.

        .PARAMETER principal
        The user or group name.

        .PARAMETER role
        The role to assign.

        .PARAMETER propagate
        Specifies whether to propagate the permission to child objects.

        .PARAMETER type
        Specifies whether the principal is a user or group.

        .PARAMETER localDomain
        Specifies whether the principal is a user or group in the local directory.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role,
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [String]$propagate,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type,
        [Parameter (Mandatory = $false)] [Switch]$localDomain
    )

    Try {
        if (!$localDomain) {
            $checkAdAuthentication = Test-ADAuthentication -user $domainBindUser -pass $domainBindPass -server $domain -domain $domain -ErrorAction SilentlyContinue
            $securePass = ConvertTo-SecureString -String $domainBindPass -AsPlainText -Force
            $domainCreds = New-Object System.Management.Automation.PSCredential ($domainBindUser, $securePass)
            if (!($checkAdAuthentication[1] -match "Authentication Successful")) {
                Write-Error "Unable to authenticate to Active Directory with user ($domainBindUser) and password ($domainBindPass), check details: PRE_VALIDTION_FAILED"
                Return
            }
        }

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VIRole -Name $role -ErrorAction SilentlyContinue ) {
                                Connect-vSphereMobServer -server $vcfVcenterDetails.fqdn -username $vcfVcenterDetails.ssoAdmin -password $vcfVcenterDetails.ssoAdminPass | Out-Null
                                $roleAssigned = (Get-GlobalPermission | Where-Object {$_.Principal -match $principal})
                                if (!($roleAssigned | Where-Object {$_.Role -eq $role})) {
                                    if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                                        if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                            if (!(Get-IdentitySource | Where-Object { $_.Name -eq $domain })) {
                                                Write-Error "Unable to find Identity Source in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): PRE_VALIDATION_FAILED"
                                            } else {
                                                if ($type -eq "group") {
                                                    if (!$localDomain) {
                                                        $objectCheck = (Get-ADGroup -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal })
                                                        $principal = $domain.ToUpper() + "\" + $principal
                                                    } else {
                                                        $objectCheck = (Get-VIAccount -Group -Domain $domain -server $vcfVcenterDetails.fqdn | Where-Object { $_.Name -eq $principal })
                                                        $principal = $domain.ToUpper() + "\" + $principal
                                                    }
                                                } elseif ($type -eq "user") {
                                                    if (!$localDomain){
                                                        $objectCheck = (Get-ADUser -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal })
                                                        $principal = $domain.ToUpper() + "\" + $principal
                                                    } else {
                                                        $principal = $domain.ToUpper() + "\" + $principal
                                                        $objectCheck = (Get-VIAccount -User -Domain $domain -server $vcfVcenterDetails.fqdn | Where-Object { $_.Name -eq $principal })
                                                    }
                                                }
                                                if ($objectCheck) {
                                                    $roleId = (Get-VIRole -Name $role -Server $vcfVcenterDetails.fqdn | Select-Object -ExpandProperty Id)
                                                    Add-GlobalPermission -principal $principal -roleId $roleId -propagate $propagate -type $type | Out-Null
                                                    $roleAssigned = (Get-GlobalPermission | Where-Object {$_.Principal -match $principal.Split("\")[-1]})
                                                    if ($roleAssigned | Where-Object {$_.Role -eq $role}) {
                                                        Write-Output "Adding Global Permission with Role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal): SUCCESSFUL"
                                                    } else {
                                                        Write-Error "Adding Global Permission with Role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal): POST_VALIDATION_FAILED"
                                                    }
                                                } else {
                                                    if ($localDomain) {
                                                        Write-Error "Unable to find $type ($principal) in Local Domain, create and retry: PRE_VALIDATION_FAILED"
                                                    } else {
                                                        Write-Error "Unable to find $type ($principal) in Active Directory Domain ($domain), create and retry: PRE_VALIDATION_FAILED"
                                                    }
                                                }
                                            }
                                        }
                                        Disconnect-SsoAdminServer -Server $vcfVcenterDetails.fqdn -WarningAction SilentlyContinue
                                    }
                                } else {
                                    Write-Warning "Adding Global Permission with Role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal), already applied: SKIPPED"
                                }
                                Disconnect-vSphereMobServer
                            } else {
                                Write-Error "Unable to find role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)): PRE_VALIDATION_FAILED"
                            }
                            Disconnect-VIServer -Server $vcfVcenterDetails.fqdn -Confirm:$false -Force -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vCenterGlobalPermission

Function Undo-vCenterGlobalPermission {
    <#
        .SYNOPSIS
        Removes a Global Permission to a user or group
        
        .DESCRIPTION
        The Undo-vCenterGlobalPermission cmdlets removes the vCenter Server Global Permission for the user or group provided.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Removes the user or group from the vCenter Global Permission

        If -localDomain is selected, then AD authentication check is skipped and user/group is checked for in the local directory

        .EXAMPLE
        Undo-vCenterGlobalPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -principal gg-vc-admins -type group
        This example removes the group gg-vc-admins from domain sfo.rainpole.io from the Global Permissions for vCenter Server instances in the same vCenter Single Sign-On domain as management domain sfo-m01.

        .EXAMPLE
        Undo-vCenterGlobalPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-w01 -domain vsphere.local -principal testUser -type user -localdomain
        This example removes the user testUser from the vCenter Single Sign-on domain vsphere.local from the Global Permissions for vCenter Server instances in the same vCenter Single Sign-On domain as workload domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The SDDC Manager management or workload domain name.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER principal
        The user or group name.

        .PARAMETER type
        Specifies whether the principal is a user or group.

        .PARAMETER localDomain
        Specifies whether the principal is a user or group in the local directory.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type,
        [Parameter (Mandatory = $false)] [Switch]$localDomain = $false
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            Connect-vSphereMobServer -server $vcfVcenterDetails.fqdn -username $vcfVcenterDetails.ssoAdmin -password $vcfVcenterDetails.ssoAdminPass | Out-Null
                            if (Get-GlobalPermission | Where-Object {$_.Principal -match $principal}) {
                                if ($PsBoundParameters.ContainsKey("domain")) {
                                    Remove-GlobalPermission -principal ($domain.ToUpper()+"\"+$principal) -type $type | Out-Null
                                } else {
                                    Remove-GlobalPermission -principal $principal -type $type | Out-Null
                                }
                                if (!(Get-GlobalPermission | Where-Object {$_.Principal -match $principal})) {
                                    Write-Output "Removing Global Permissions for $type ($principal) in vCenter Server ($($vcfVcenterDetails.vmName)) and vCenter Single Sign-On domain ($($vcfVcenterDetails.ssoDomain)): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing Global Permissions for $type ($principal) in vCenter Server ($($vcfVcenterDetails.vmName)) and vCenter Single Sign-On domain ($($vcfVcenterDetails.ssoDomain)) for $type ($principal): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing Global Permissions for $type ($principal) in vCenter Server ($($vcfVcenterDetails.vmName)), already removed: SKIPPED"
                            }
                            Disconnect-VIServer -Server $vcfVcenterDetails.fqdn -Confirm:$false -Force -WarningAction SilentlyContinue
                            Disconnect-vSphereMobServer
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vCenterGlobalPermission

Function Set-vCenterPermission {
    <#
        .SYNOPSIS
        Sets Permission for user or group in the vCenter Server. This overrides any existing Global Permissions for the user or group in the vCenter Server.

        .DESCRIPTION
        The Set-vCenterPermission cmdlet assigns the Permission/Role to existing user or group in the vCenter Server.
        The user/group must exist in the domain prior to running this cmdlet.

        .EXAMPLE
        Set-vCenterPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain vsphere.local -workloadDomain sfo-m01 -principal svc-sfo-w01-nsx01-sfo-w01-vc01 -role "NoAccess"
        This example assigns NoAccess role to the user svc-sfo-w01-nsx01-sfo-w01-vc01 from domain vsphere.local.

        .EXAMPLE
        Set-vCenterPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo -workloadDomain sfo-m01 -principal gg-vc-admins -role "Admin"
        This example assigns the Admin role to the group gg-vc-admins from domain SFO.

        .EXAMPLE
        Set-vCenterPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo -workloadDomain sfo-m01 -principal sfo-vra-vsphere -role "NoAccess" -folderName "local" -folderType "Datastore"
        This example assigns the NoAccess role to the user svc-vra-vsphere from domain SFO on the datastore folder named "local".
        Note: The functionality is limited to non-nested folders in the default datacenter.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER workloadDomain
        The SDDC Manager workload domain name.

        .PARAMETER principal
        The user or group name.

        .PARAMETER role
        The role to assign.

        .PARAMETER folderName
        The folder name.

        .PARAMETER folderType
        The folder type.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workloadDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role,
        [Parameter (ParameterSetName = 'Folders', Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$folderName,
        [Parameter (ParameterSetName = 'Folders', Mandatory = $false)] [ValidateSet("Datacenter", "Datastore", "HostAndCluster", "Network", "VM")] [String]$folderType
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $workloadDomain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $workloadDomain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        if (Get-SsoPersonUser -Domain $domain -Name $principal -Server $ssoConnectionDetail) {
                                            $principal = $domain.ToUpper() + "\" + $principal
                                            if ($PsBoundParameters.ContainsKey("folderName") -and ($PsBoundParameters.ContainsKey("folderType"))) {
                                                if (($objectCheck = Get-Folder -Name $folderName -Type $folderType -ErrorAction Ignore | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"}).Name) {
                                                    if ($objectCheck = Get-VIPermission -Server $vcfVcenterDetails.fqdn -Principal $principal -Entity (Get-Folder -Name $folderName -Type $folderType | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"})) {
                                                        if (!($objectCheck.Role -eq $role)) {
                                                            New-VIPermission -Server $vcfVcenterDetails.fqdn -Role $role -Principal $principal -Entity (Get-Folder -Name $folderName -Type $folderType | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"}) | Out-Null
                                                            $objectCheck = Get-VIPermission -Server $vcfVcenterDetails.fqdn -Principal $principal -Entity (Get-Folder -Name $folderName -Type $folderType | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"})
                                                            if ($objectCheck.Role -eq $role) {
                                                                Write-Output "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal) on $($folderType.ToLower()) folder ($folderName): SUCCESSFUL"
                                                            } else {
                                                                Write-Error "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal) on $($folderType.ToLower()) folder ($folderName): POST_VALIDATION_FAILED"
                                                            }
                                                        } else {
                                                            Write-Warning "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal) on $($folderType.ToLower()) folder ($folderName), already assigned: SKIPPED"
                                                        }
                                                    } else {
                                                        Write-Error "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal) on $($folderType.ToLower()) folder ($folderName), check folderName and folderType: PRE_VALIDATION_FAILED"
                                                    }
                                                } else {
                                                    Write-Error "Unable to find $($folderType.ToLower()) folder ($folderName) in vCenter Server ($($vcfVcenterDetails.vmName)): PRE_VAILIDATION_FAILED"
                                                }
                                            } else {
                                                if ($folderName -or $folderType) {
                                                    Write-Error "Only one of -folderName or -folderType parameters provided: PRE_VALIDATATION_FAILED"
                                                } else {
                                                    if ($objectCheck = Get-VIPermission -Server $vcfVcenterDetails.fqdn -Principal $principal -Entity (Get-Folder "Datacenters" -Type Datacenter | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"}))  {
                                                        if (!($objectCheck.Role -eq $role)) {
                                                            New-VIPermission -Server $vcfVcenterDetails.fqdn -Role $role -Principal $principal -Entity (Get-Folder "Datacenters" -Type Datacenter | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"}) | Out-Null
                                                            $objectCheck = Get-VIPermission -Server $vcfVcenterDetails.fqdn -Principal $principal -Entity (Get-Folder "Datacenters" -Type Datacenter | Where-Object {$_.Uid -like "*"+$vcfVcenterDetails.fqdn+"*"})
                                                            if ($objectCheck.Role -eq $role) {
                                                                Write-Output "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal): SUCCESSFUL"
                                                            } else {
                                                                Write-Error "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal): POST_VALIDATION_FAILED"
                                                            }
                                                        } else {
                                                            Write-Warning "Assigning role ($role) in vCenter Server ($($vcfVcenterDetails.vmName)) to ($principal), already assigned: SKIPPED"
                                                        }
                                                    }
                                                }
                                            }
                                        } else {
                                            Write-Error "Unable to find ($principal) in vCenter Server ($($vcfVcenterDetails.vmName)): PRE_VAILIDATION_FAILED"
                                        }
                                    }
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Set-vCenterPermission

Function Add-SsoPermission {
    <#
        .SYNOPSIS
        Assign vCenter Single Sign-On Group to user/group.

        .DESCRIPTION
        The Add-SsoPermission cmdlet assigns the vCenter Single Sign-On Role to the user or group provided. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the bind credetials are valid
        - Validates that the domain is present in vCenter Server as an Identity Provider
        - Validates the user or group exists in Active Directory
        - Assigns the user or group to the vCenter Single Sign-On Role

        .EXAMPLE
        Add-SsoPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -principal gg-sso-admins -ssoGroup "Administrators" -type group -source external
        This example adds the group gg-sso-admins from domain sfo.rainpole.io to the Administrators vCenter Single Sign-On Group

        .EXAMPLE
        Add-SsoPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain vsphere.local -principal svc-sfo-m01-nsx01-sfo-m01-vc01 -ssoGroup "License.Administrators" -type user -source local
        This example adds the user svc-sfo-m01-nsx01-sfo-m01-vc01 from domain vspherel.local to the License.Administrators vCenter Single Sign-On Group.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        .

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER domainBindUser
        The Active Directory bind user name.

        .PARAMETER domainBindPass
        The Active Directory bind password.

        .PARAMETER principal
        The user or group name.

        .PARAMETER ssoGroup
        The vCenter Single Sign-On Group to assign.

        .PARAMETER type
        Specifies whether the principal is a user or group.

        .PARAMETER source
        Specifies whether the principal is a user or group in the local directory.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoGroup,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateSet("local", "external")] [String]$source
    )

    Try {
        if ($source -eq "external") {
            $checkAdAuthentication = Test-ADAuthentication -user $domainBindUser -pass $domainBindPass -server $domain -domain $domain -ErrorAction SilentlyContinue
            if ($checkAdAuthentication[1] -match "Authentication Successful") {
                $securePass = ConvertTo-SecureString -String $domainBindPass -AsPlainText -Force
                $domainCreds = New-Object System.Management.Automation.PSCredential ($domainBindUser, $securePass)
                if (Test-VCFConnection -server $server) {
                    if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                        if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $sddcDomain }) {
                            if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                                if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                                    if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                        if ($targetGroup = Get-SsoGroup -Domain $vcfVcenterDetails.ssoDomain -Name $ssoGroup -Server $ssoConnectionDetail) {
                                            if (Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain }) {
                                                if ($type -eq "group") {
                                                    $adObjectCheck = (Get-ADGroup -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal })
                                                    if ($adObjectCheck) {
                                                        if (!(Get-SsoGroup -Group $targetGroup -Name $principal)) {
                                                            $ldapGroup = Get-SsoGroup -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                            $ldapGroup | Add-GroupToSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue
                                                            if (Get-SsoGroup -Group $targetGroup -Name $principal) {
                                                                Write-Output "Assigning SSO Group ($ssoGroup) to $type ($principal) for domain ($domain): SUCCESSFUL"
                                                            } else {  
                                                                Write-Error "Assigning SSO Group ($ssoGroup) to $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                            }
                                                        } else { 
                                                            Write-Warning "Assigning SSO Group ($ssoGroup) to $type ($principal) for domain ($domain), already exists: SKIPPED"
                                                        }
                                                    } else { 
                                                        Write-Error "Unable to find $type ($principal) in Active Directory Domain ($domain), create and retry: PRE_VALIDATION_FAILED"
                                                    }
                                                } elseif ($type -eq "user") {
                                                    $adObjectCheck = (Get-ADUser -Server $domain -Credential $domainCreds -Filter { SamAccountName -eq $principal })
                                                    if ($adObjectCheck) {
                                                        if (!(Get-SsoPersonUser -Group $targetGroup | Where-Object {$_.Name -eq $principal})) {
                                                            $ldapUser = Get-SsoPersonUser -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                            $ldapUser | Add-UserToSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue
                                                            if (Get-SsoPersonUser -Group $targetGroup | Where-Object {$_.Name -eq $principal}) {
                                                                Write-Output "Assigning SSO Group ($ssoGroup) to $type ($principal) for domain ($domain): SUCCESSFUL"
                                                            } else {
                                                                Write-Error "Assigning SSO Group ($ssoGroup) to $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                            }
                                                        } else {
                                                            Write-Warning "Assigning SSO Group ($ssoGroup) to $type ($principal) for domain ($domain), already exists: SKIPPED"
                                                        }
                                                    } else { 
                                                        Write-Error "Unable to find $type ($principal) in Active Directory Domain ($domain), create and retry: PRE_VALIDATION_FAILED"
                                                    }
                                                }
                                            } else {
                                                Write-Error "Unable to find Identity Source in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): PRE_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Error "Unable to find SSO Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ssoGroup): PRE_VALIDATION_FAILED"
                                        }
                                        Disconnect-SsoAdminServer -Server $vcfVcenterDetails.fqdn
                                    }
                                }
                            }
                        } else {
                            Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                        }
                    }
                }
            } else {
                Write-Error "Unable to authenticate to Active Directory with user ($domainBindUser) and password ($domainBindPass), check details: PRE_VALIDATION_FAILED"
            }
        } elseif ($source -eq "local") {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                        if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if ($targetGroup = Get-SsoGroup -Domain $vcfVcenterDetails.ssoDomain -Name $ssoGroup -Server $ssoConnectionDetail) {
                                    if (Get-IdentitySource | Where-Object { $_.Name -eq $domain }) {
                                        if ($type -eq "group") {
                                            if (!(Get-SsoGroup -Group $targetGroup -Name $principal -Server $ssoConnectionDetail)) {
                                                $ldapGroup = Get-SsoGroup -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                $ldapGroup | Add-GroupToSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue
                                                if (Get-SsoGroup -Group $targetGroup -Name $principal -Server $ssoConnectionDetail) {
                                                    Write-Output "Assigning SSO Group ($ssoGroup) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal) for domain ($domain): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Assigning SSO On Group ($ssoGroup) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Warning "Assigning SSO Group ($ssoGroup) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal) for domain ($domain).already exists: SKIPPED"
                                            }
                                        } elseif ($type -eq "user") {
                                            if (!(Get-SsoPersonUser -Group $targetGroup -Server $ssoConnectionDetail | Where-Object {$_.Name -eq $principal})) {
                                                $ldapUser = Get-SsoPersonUser -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                $ldapUser | Add-UserToSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue
                                                if (Get-SsoPersonUser -Group $targetGroup -Server $ssoConnectionDetail| Where-Object {$_.Name -eq $principal}) {
                                                    Write-Output "Assigning SSO Group ($ssoGroup) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal) for domain ($domain): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Assigning SSO Group ($ssoGroup) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Warning "Assigning SSO Group ($ssoGroup) in vCenter Server ($($vcfVcenterDetails.vmName)) to $type ($principal) for domain ($domain), already exists: SKIPPED"
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to find Identity Source in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find SSO Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ssoGroup): PRE_VALIDATION_FAILED"
                                }
                                Disconnect-SsoAdminServer -Server $vcfVcenterDetails.fqdn
                            }
                        }
                    }
                }   
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-SsoPermission

Function Undo-SsoPermission {
    <#
        .SYNOPSIS
        Remove user/group from vCenter Single Sign-On Group.

        .DESCRIPTION
        The Undo-SsoPermission cmdlet removes the user or group provided from vCenter Single Sign-On Role. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the domain is present in vCenter Server as an Identity Provider
        - Removes the user or group from the vCenter Single Sign-On Role

        .EXAMPLE
        Undo-SsoPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain sfo.rainpole.io -principal gg-sso-admins -ssoGroup "Administrators" -type group -source external
        This example removes the group gg-sso-admins in domain sfo.rainpole.io from the Administrators vCenter Single Sign-On Group

        .EXAMPLE
        Undo-SsoPermission -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -domain vsphere.local -principal svc-sfo-m01-nsx01-sfo-m01-vc01 -ssoGroup "LicenseService.Administrators" -type user -source local
        This example removes the user svc-sfo-m01-nsx01-sfo-m01-vc01 in domain vspherel.local from the LicenseService.Administrators vCenter Single Sign-On Group.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
        The VI Workload Domain name.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER principal
        The user or group name.

        .PARAMETER ssoGroup
        The vCenter Single Sign-On Group to assign.

        .PARAMETER type
        Specifies whether the principal is a user or group.

        .PARAMETER source
        Specifies whether the principal is a user or group in the local directory.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoGroup,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateSet("local", "external")] [String]$source
    )

    Try {
        if ($source -eq "external") {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $sddcDomain }) {
                        if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                            if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                                if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                    if ($targetGroup = Get-SsoGroup -Domain $vcfVcenterDetails.ssoDomain -Name $ssoGroup -Server $ssoConnectionDetail) {
                                        if (Get-IdentitySource -Server $ssoConnectionDetail | Where-Object { $_.Name -eq $domain }) {
                                            if ($type -eq "group") {
                                                if (Get-SsoGroup -Group $targetGroup -Name $principal) {
                                                    $ldapGroup = Get-SsoGroup -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                    $ldapGroup | Remove-GroupFromSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue | Out-Null
                                                    if (!(Get-SsoGroup -Group $targetGroup -Name $principal)) {
                                                        Write-Output "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): SUCCESSFUL"
                                                    } else {
                                                        Write-Error "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                    }
                                                } else { 
                                                    Write-Warning "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain), already removed: SKIPPED"
                                                }
                                            } elseif ($type -eq "user") {
                                                if (Get-SsoPersonUser -Group $targetGroup | Where-Object {$_.Name -eq $principal}) {
                                                    $ldapUser = Get-SsoPersonUser -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                    $ldapUser | Remove-UserFromSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue | Out-Null
                                                    if (!(Get-SsoPersonUser -Group $targetGroup | Where-Object {$_.Name -eq $principal})) {
                                                        Write-Output "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): SUCCESSFUL"
                                                    } else {
                                                        Write-Error "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                    }
                                                } else {
                                                    Write-Warning "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain), already exists: SKIPPED"
                                                }
                                            }
                                        } else {
                                            Write-Warning "Unable to find Identity Source in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): SKIPPED"
                                        }
                                    } else {
                                        Write-Error "Unable to find SSO Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ssoGroup): PRE_VALIDATION_FAILED"
                                    }
                                    Disconnect-SsoAdminServer -Server $vcfVcenterDetails.fqdn
                                }
                            }
                        }
                    } else {
                        Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                    }
                }
            }
        } elseif ($source -eq "local") {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                        if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if ($targetGroup = Get-SsoGroup -Domain $vcfVcenterDetails.ssoDomain -Name $ssoGroup -Server $ssoConnectionDetail) {
                                    if (Get-IdentitySource | Where-Object { $_.Name -eq $domain }) {
                                        if ($type -eq "group") {
                                            if (Get-SsoGroup -Group $targetGroup -Name $principal -Server $ssoConnectionDetail) {
                                                $ldapGroup = Get-SsoGroup -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                $ldapGroup | Remove-GroupFromSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue
                                                if (!(Get-SsoGroup -Group $targetGroup -Name $principal -Server $ssoConnectionDetail)) {
                                                    Write-Output "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Removing SSO On Group ($ssoGroup) for $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Warning "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain), already removed: SKIPPED"
                                            }
                                        } elseif ($type -eq "user") {
                                            if (Get-SsoPersonUser -Group $targetGroup -Server $ssoConnectionDetail | Where-Object {$_.Name -eq $principal}) {
                                                $ldapUser = Get-SsoPersonUser -Domain $domain -Name $principal -Server $ssoConnectionDetail
                                                $ldapUser | Remove-UserFromSsoGroup -TargetGroup $targetGroup -ErrorAction SilentlyContinue
                                                if (!(Get-SsoPersonUser -Group $targetGroup -Server $ssoConnectionDetail| Where-Object {$_.Name -eq $principal})) {
                                                    Write-Output "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): SUCCESSFUL"
                                                } else {
                                                    Write-Error "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain): POST_VALIDATION_FAILED"
                                                }
                                            } else {
                                                Write-Warning "Removing SSO Group ($ssoGroup) for $type ($principal) for domain ($domain), already removed: SKIPPED"
                                            }
                                        }
                                    } else {
                                        Write-Error "Unable to find Identity Source in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($domain): PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "Unable to find SSO Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ssoGroup): PRE_VALIDATION_FAILED"
                                }
                                Disconnect-SsoAdminServer -Server $vcfVcenterDetails.fqdn
                            }
                        }
                    }
                }   
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-SsoPermission

Function Add-SsoUser {
    <#
        .SYNOPSIS
        Assign vCenter Single Sign-On Group to user/group.

        .DESCRIPTION
        The Add-SsoUser cmdlet adds a user to the vCenter Single Sign-On domain The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to Management Domain vCenter Server
        - Validates that the user does not exist
        - Adds the user to the vCenter Single Sign-On domain

        .EXAMPLE
        Add-SsoUser -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -ssoUser svc-vrslcm-vsphere-sfo-m01-vc01 -ssoPass VMw@re1!VMw@re1!
        This example adds the user svc-vrslcm-vsphere-sfo-m01-vc01 to the vCenter Single Sign-On domain vsphere.local.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER ssoUser
        The vCenter Single Sign-On user name.

        .PARAMETER ssoPass
        The vCenter Single Sign-On user password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-SSOConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-SSOAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (!(Get-SsoPersonUser -Domain vsphere.local -Name $ssoUser -Server $ssoConnectionDetail)) {
                                New-SsoPersonUser -UserName $ssoUser -Password $ssoPass -Server $ssoConnectionDetail | Out-Null
                                if (Get-SsoPersonUser -Domain vsphere.local -Name $ssoUser -Server $ssoConnectionDetail) {
                                    Write-Output "Adding New Single Sign-On User to vCenter Server ($($vcfVcenterDetails.vmName)) named ($ssoUser): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding New Single Sign-On User to vCenter Server ($($vcfVcenterDetails.vmName)) named ($ssoUser): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding New Single Sign-On User to vCenter Server ($($vcfVcenterDetails.vmName)) named ($ssoUser), already exists: SKIPPED"
                            }
                            Disconnect-SsoAdminServer $vcfVcenterDetails.fqdn -WarningAction SilentlyContinue
                        }
                    }
                }                             
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-SsoUser

Function Add-vSphereRole {
    <#
        .SYNOPSIS
        Add a vSphere role.

        .DESCRIPTION
        The Add-vSphereRole cmdlet creates a role in vCenter Server. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Assigns permissions to the role based on the template file provided

        .EXAMPLE
        Add-vSphereRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -roleName "NSX to vSphere Integration" -template .\vSphereRoles\nsx-vsphere-integration.role
        This example adds the "NSX to vSphere Integration" role in the management domain vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
.

        .PARAMETER roleName
        The name of the role to create.

        .PARAMETER template
        The template file to use for the role.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$roleName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$template
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("template")) {
            $template = Get-ExternalFileName -title "Select the vSphere role template (.role)" -fileType "role" -location "C:\Program Files\WindowsPowerShell\Modules\PowerValidatedSolutions\vSphereRoles"
        } else {
            if (!(Test-Path -Path $template)) {
                Write-Error  "vSphere Role Template '$template' File Not Found"
                Break
            }
        }

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $roleContent = Get-Content -Path $template
                            if (!(Get-VIRole -Server $vcfVcenterDetails.fqdn | Where-Object { $_.Name -eq $roleName })) {
                                New-VIRole -Name $roleName -Server $vcfVcenterDetails.fqdn | Out-Null
                                if (Get-VIRole -Server $vcfVcenterDetails.fqdn | Where-Object { $_.Name -eq $roleName }) {
                                    Foreach ($privilege in $roleContent) {
                                        if (-not ($privilege -eq $null -or $privilege -eq "")) {
                                            Set-VIRole -Server $vcfVcenterDetails.fqdn -Role $roleName -AddPrivilege (Get-VIPrivilege -ID $privilege) -Confirm:$False -ErrorAction SilentlyContinue | Out-Null
                                        }
                                    }
                                    Write-Output "Creating a new role in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($roleName): SUCCESSFUL"
                                } else {
                                    Write-Error "Creating a new role in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($roleName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Creating a new role in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($roleName), already exists: SKIPPED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-vSphereRole

Function Undo-vSphereRole {
    <#
        .SYNOPSIS
        Remove a vSphere role.

        .DESCRIPTION
        The Undo-vSphereRole cmdlet removes a role from vCenter Server. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Verifies if the role exists and if it does removes it

        .EXAMPLE
        Undo-vSphereRole -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -sddcDomain sfo-m01 -roleName "NSX to vSphere Integration"
        This example removes the "NSX to vSphere Integration" role from the management domain vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER sddcDomain
.

        .PARAMETER roleName
        The name of the role to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sddcDomain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$roleName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $sddcDomain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VIRole -Server $vcfVcenterDetails.fqdn | Where-Object { $_.Name -eq $roleName }) {
                                Remove-VIRole -Role $roleName -Server $vcfVcenterDetails.fqdn -Force -Confirm:$false | Out-Null
                                if (!(Get-VIRole -Server $vcfVcenterDetails.fqdn | Where-Object { $_.Name -eq $roleName })) {
                                    Write-Output "Removing a role from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($roleName): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing a role from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($roleName): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing a role from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($roleName), already exists: SKIPPED"
                            }
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-vSphereRole

Function Add-VMFolder {
    <#
        .SYNOPSIS
        Create a VM Folder.

        .DESCRIPTION
        The Add-VMFolder cmdlet creates a VM and Template folder. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that the Workload Domain exists in the SDDC Manager inventory
        - Retrives the details of the vCenter Server for the Workload Domain provided
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the VM and Template folder is not present in the vCenter Server inventory
        - Creates VM and Template folder the folder in the vCenter Server inventory

        .EXAMPLE
        Add-VMFolder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -foldername "myFolder"
        This example shows how to create the folder myFolder within the VMware Cloud Foundation domain sfo-m01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER folderName
        The name of the folder to create.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$folderName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                $datacenter = (Get-Datacenter -Cluster $cluster -Server $vcfVcenterDetails.fqdn).Name
                                if (Get-Folder -Name $folderName -Server $vcfVcenterDetails.fqdn -WarningAction SilentlyContinue -ErrorAction Ignore) {
                                    Write-Warning "Adding VM and Template Folder to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($folderName), already exists: SKIPPED"
                                } else {
                                    (Get-View -Server $vcfVcenterDetails.fqdn (Get-View -Server $vcfVcenterDetails.fqdn -viewtype datacenter -filter @{"name" = [String]$datacenter }).vmfolder).CreateFolder($folderName) | Out-Null
                                    if ((Get-Folder -Name $folderName -Server $vcfVcenterDetails.fqdn -WarningAction SilentlyContinue -ErrorAction Ignore)) {
                                        Write-Output  "Adding VM and Template Folder to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($folderName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding VM and Template Folder to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($folderName): POST_VALIDATION_FAILED"
                                    }
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-VMFolder

Function Add-StorageFolder {
    <#
        .SYNOPSIS
        Create a Storage Folder.

        .DESCRIPTION
        The Add-StorageFolder cmdlet creates a Storage folder. The cmdlet connects to SDDC Manager using the -server,
        -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that the Workload Domain exists in the SDDC Manager inventory
        - Retrives the details of the vCenter Server for the Workload Domain provided
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the Storage folder is not present in the vCenter Server inventory
        - Creates the Storage folder in the vCenter Server inventory

        .EXAMPLE
        Add-StorageFolder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -foldername "myStorageFolder"
        This example shows how to create the folder myStorageFolder within the VMware Cloud Foundation domain sfo-m01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER folderName
        The name of the folder to create.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$folderName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                $datacenter = (Get-Datacenter -Cluster $cluster -Server $vcfVcenterDetails.fqdn).Name
                                if (Get-Folder -Name $folderName -Server $vcfVcenterDetails.fqdn -WarningAction SilentlyContinue -ErrorAction Ignore) {
                                    Write-Warning "Adding Storage Folder to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($folderName), already exists: SKIPPED"
                                } else {
                                    (Get-View -Server $vcfVcenterDetails.fqdn (Get-View -Server $vcfVcenterDetails.fqdn -viewtype datacenter -filter @{"name" = [String]$datacenter }).datastorefolder).CreateFolder($folderName) | Out-Null
                                    if ((Get-Folder -Name $folderName -Server $vcfVcenterDetails.fqdn -WarningAction SilentlyContinue -ErrorAction Ignore)) {
                                        Write-Output  "Adding Storage Folder to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($folderName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding Storage Folder to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($folderName): POST_VALIDATION_FAILED"
                                    }
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-StorageFolder

Function Undo-VMFolder {
    <#
        .SYNOPSIS
        Remove a VM Folder.

        .DESCRIPTION
        The Undo-VMFolder cmdlet removes a VM and Template folder. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that the Workload Domain exists in the SDDC Manager inventory
        - Retrives the details of the vCenter Server for the Workload Domain provided
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the VM and Template folder is present in the vCenter Server inventory
        - Removes the VM and Template folder from the vCenter Server inventory

        .EXAMPLE
        Undo-VMFolder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -foldername "myFolder" -folderType VM
        This example shows how to remove the folder myFolder within the VMware Cloud Foundation domain sfo-m01

        .EXAMPLE
        Undo-VMFolder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -foldername "myFolder" -folderType Datastore
        This example shows how to remove the storage folder myStorageFolder within the VMware Cloud Foundation domain sfo-m01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER folderName
        The name of the folder to remove.

        .PARAMETER folderType
        The type of folder to remove. Valid values are Datacenter, VM, Network, HostAndCluster, and Datastore.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$folderName,
        [Parameter (Mandatory = $true)] [ValidateSet("Datacenter", "VM", "Network", "HostAndCluster", "Datastore")] [String]$folderType
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (!(Get-Folder -Name $folderName -Type $folderType -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore)) {
                                    Write-Warning "Removing Folder Type ($folderType) from vCenter Server ($($vcfVcenterDetails.fqdn)) with name ($folderName), folder does not exist: SKIPPED"
                                } else {
                                    if (!(Get-Folder -Name $folderName | Get-VM)) {
                                        Get-Folder -Name $folderName -Type $folderType -Server $vcfVcenterDetails.fqdn | Remove-Folder -Confirm:$false -ErrorAction Ignore
                                        if (!(Get-Folder -Name $folderName -Type $folderType -Server $vcfVcenterDetails.fqdn -ErrorAction Ignore)) {
                                            Write-Output  "Removing Folder Type ($folderType) from vCenter Server ($($vcfVcenterDetails.fqdn)) with name ($folderName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Removing Folder Type ($folderType) from vCenter Server ($($vcfVcenterDetails.fqdn)) with name ($folderName): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "Removing Folder Type ($folderType) from vCenter Server ($($vcfVcenterDetails.fqdn)) with name ($folderName), contains VMs: PRE_VALIDATION_FAILURE"
                                    }
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-VMFolder

Function Add-ResourcePool {
    <#
        .SYNOPSIS
        Create a resource pool.

        .DESCRIPTION
        The Add-ResourcePool cmdlet creates a resource pool. The cmdlet connects to SDDC Manager using the -server, -user, and -password values
        to retrive the vCenter Server details from the SDDC Manager inventory and then:
        - Connects to the vCenter Server
        - Verifies that the resource pool has not already been created
        - Creates the resource pool

        .EXAMPLE
        Add-ResourcePool -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -resourcePoolName "sfo-w01-cl01-rp-workload"
        This example shows how to create the folder myFolder within the VMware Cloud Foundation domain sfo-m01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER resourcePoolName
        The name of the resource pool to create.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$resourcePoolName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (!(Get-ResourcePool -Server $vcfVcenterDetails.fqdn | Where-Object {$_.Name -eq $resourcePoolName})) {
                                    New-ResourcePool -Name $resourcePoolName -Location $cluster -Server $vcfVcenterDetails.fqdn | Out-Null
                                    if (Get-ResourcePool -Server $vcfVcenterDetails.fqdn | Where-Object {$_.Name -eq $resourcePoolName}) {
                                        Write-Output "Adding Resource Pool to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding Resource Pool to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName): FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding Resource Pool to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName), already exists: SKIPPED"
                                }
                                Disconnect-VIServer -Server $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-ResourcePool

Function Undo-ResourcePool {
    <#
        .SYNOPSIS
        Remove a resource pool.

        .DESCRIPTION
        The Undo-ResourcePool cmdlet removes a resource pool. The cmdlet connects to SDDC Manager using the -server, -user, and -password values
        to retrive the vCenter Server details from the SDDC Manager inventory and then:
        - Connects to the vCenter Server
        - Verifies that the resource pool exists in the vCenter Server inventory
        - Removes the resource pool

        .EXAMPLE
        Undo-ResourcePool -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -resourcePoolName "sfo-w01-cl01-rp-workload"
        This example shows how to create the folder myFolder within the VMware Cloud Foundation domain sfo-m01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER resourcePoolName
        The name of the resource pool to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$resourcePoolName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                if (Get-ResourcePool -Server $vcenter.fqdn | Where-Object {$_.Name -eq $resourcePoolName}) {
                                    if (!(Get-ResourcePool -Name $resourcePoolName | Get-VM)) {
                                        Remove-ResourcePool -ResourcePool $resourcePoolName -Server $vcenter.fqdn -Confirm:$false | Out-Null
                                        if (!(Get-ResourcePool -Server $vcenter.fqdn | Where-Object {$_.Name -eq $resourcePoolName})) {
                                            Write-Output "Removing Resource Pool from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Removing Resource Pool from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName): POST_VALIDATION_FAILURE"
                                        }
                                    } else {
                                        Write-Error "Removing Resource Pool from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName), contains VMs: PRE_VALIDATION_FAILURE"
                                    }
                                } else {
                                    Write-Warning "Removing Resource Pool from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($resourcePoolName), does not exist: SKIPPED"
                                }
                                Disconnect-VIServer -Server $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-ResourcePool

Function Add-AntiAffinityRule {
    <#
        .SYNOPSIS
        Creates a vSphere Anti-Affinity rule.

        .DESCRIPTION
        The Add-AntiAffinityRule cmdlet creates a vSphere Anti-Affinity rule. The cmdlet connects to SDDC Manager using
        the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the anti-affinity rule has not already been created in the vCenter Server inventory
        - Creates the anti-affinity rule in the vCenter Server inventory

        .EXAMPLE
        Add-AntiAffinityRule -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -ruleName sfo-m01-anti-affinity-rule-wsa -antiAffinityVMs "xreg-wsa01a,xreg-wsa01b,xreg-wsa01c"
        This example shows how to create a vSphere Anti-Affinity rule in the vCenter Server of the sfo-m01 workload domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER ruleName
        The name of the anti-affinity rule to create.

        .PARAMETER antiAffinityVMs
        The comma separated list of VMs to add to the anti-affinity rule.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$ruleName,
        [Parameter (Mandatory = $true)] [String]$antiAffinityVMs
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (!(Get-Cluster -Name $cluster | Get-DrsRule | Where-Object {$_.Name -eq $ruleName})) {
                                    $vmNames = $antiAffinityVMs.split(",")
                                    $vms = foreach ($name in $vmNames) { Get-VM -name $name -ErrorAction SilentlyContinue }
                                    New-DrsRule -Cluster $cluster -Name $ruleName -VM $vms -KeepTogether $false -Enabled $true | Out-Null
                                    if ((Get-Cluster -Name $cluster | Get-DrsRule | Where-Object {$_.Name -eq $ruleName})) {
                                        Write-Output "Adding Anti-Affinity Rule to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding Anti-Affinity Rule to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding Anti-Affinity Rule to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName), already exists: SKIPPED" 
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-AntiAffinityRule

Function Undo-AntiAffinityRule {
    <#
        .SYNOPSIS
        Removes a vSphere Anti-Affinity rule.

        .DESCRIPTION
        The Undo-AntiAffinityRule cmdlet removes a vSphere Anti-Affinity rule. The cmdlet connects to SDDC Manager using
        the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the anti-affinity rule has not already been removed from the vCenter Server inventory
        - Removes the anti-affinity rule from the vCenter Server inventory

        .EXAMPLE
        Undo-AntiAffinityRule -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -ruleName sfo-m01-anti-affinity-rule-wsa
        This example shows how to create a vSphere Anti-Affinity rule in the vCenter Server of the sfo-m01 workload domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER Domain
        The VMware Cloud Foundation domain name.

        .PARAMETER ruleName
        The name of the anti-affinity rule to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$ruleName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (Get-Cluster -Name $cluster | Get-DrsRule | Where-Object {$_.Name -eq $ruleName}) {
                                    Remove-DrsRule -Rule (Get-Cluster -Name $cluster | Get-DrsRule | Where-Object {$_.Name -eq $ruleName}) -Confirm:$false | Out-Null
                                    if (!(Get-Cluster -Name $cluster | Get-DrsRule | Where-Object {$_.Name -eq $ruleName})) {
                                        Write-Output "Removing Anti-Affinity Rule from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing Anti-Affinity Rule from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing Anti-Affinity Rule from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName), already removed: SKIPPED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-AntiAffinityRule

Function Add-ClusterGroup {
    <#
    .SYNOPSIS
        Creates a vSphere DRS Cluster Group.

        .DESCRIPTION
        The Add-ClusterGroup cmdlet creates a vSphere DRS Cluster Group. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that that the vSphere DRS Cluster Group does not already exist in the vCenter Server inventory
        - Creates the vSphere DRS Cluster Group in the vCenter Server inventory

        .EXAMPLE
        Add-ClusterGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -drsGroupName "xint-vm-group-wsa" -drsGroupVMs "xreg-wsa01a,xreg-wsa01b,xreg-wsa01c"
        This example shows how to create a vSphere DRS Cluster group in the vCenter Server of the sfo-m01 workload domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER drsGroupName
        The name of the vSphere DRS Cluster Group to create.

        .PARAMETER drsGroupVMs
        The list of VMs to add to the vSphere DRS Cluster Group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$drsGroupName,
        [Parameter (Mandatory = $true)] [String]$drsGroupVMs
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (!(Get-Cluster -Name $cluster | Get-DrsClusterGroup | Where-Object {$_.Name -eq $drsGroupName})) {
                                    $vmNames = $drsGroupVMs.split(",")
                                    $vms = foreach ($name in $vmNames) { Get-VM -name $name -ErrorAction SilentlyContinue }
                                    New-DrsClusterGroup -Cluster $cluster -VM $vms -Name $drsGroupName | Out-Null
                                    if (Get-Cluster -Name $cluster | Get-DrsClusterGroup | Where-Object {$_.Name -eq $drsGroupName}) {
                                        Write-Output "Adding vSphere DRS Group to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Adding vSphere DRS Group to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Adding vSphere DRS Group to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName), already exists: SKIPPED"
                                    
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-ClusterGroup

Function Undo-ClusterGroup {
    <#
        .SYNOPSIS
        Removes a vSphere DRS Cluster Group.

        .DESCRIPTION
        The Undo-ClusterGroup cmdlet removes the vSphere DRS Cluster Group. The cmdlet connects to SDDC Manager using the
        -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that that the vSphere DRS Cluster Group exist in the vCenter Server inventory
        - Removes the vSphere DRS Cluster Group in the vCenter Server inventory

        .EXAMPLE
        Undo-ClusterGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -drsGroupName "sfo-m01-vm-group-wsa"
        This example shows how to delete a vSphere DRS Cluster group from the vCenter Server of the sfo-m01 workload domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER drsGroupName
        The name of the vSphere DRS Cluster Group to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$drsGroupName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (!(Get-DrsVmToVmGroup -cluster $cluster | Where-Object {$_.DependsOnVmGroup -eq $drsGroupName})) {
                                    if ((Get-Cluster -Name $cluster | Get-DrsClusterGroup | Where-Object {$_.Name -eq $drsGroupName})) {
                                        Remove-DrsClusterGroup -DrsClusterGroup $drsGroupName -Server $($vcfVcenterDetails.fqdn) -Confirm:$false | Out-Null
                                        if (!(Get-Cluster -Name $cluster | Get-DrsClusterGroup | Where-Object {$_.Name -eq $drsGroupName})) {
                                            Write-Output "Removing vSphere DRS Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName): SUCCESSFUL"
                                        } else {
                                            Write-Error "Removing vSphere DRS Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Removing vSphere DRS Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName), already removed: SKIPPED"
                                        
                                    }
                                } else {
                                    Write-Error "Unable to remove vSphere DRS Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($drsGroupName), in use by VM to VM Group: PRE_VALIDATION_FAILED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-ClusterGroup

Function Add-VmStartupRule {
    <#
        .SYNOPSIS
        Creates a VM to VM DRS rule.

        .DESCRIPTION
        The Add-VmStartupRule cmdlet creates a vSphere DRS Virtual Machine to Virtual Machine startup rule. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that that the Virtual Machine to Virtual Machine startup rule does not already exist in the vCenter Server inventory
        - Creates the vSphere DRS Virtual Machine to Virtual Machine startup rule in the vCenter Server inventory

        .EXAMPLE
        Add-VmStartupRule -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -ruleName vm-vm-rule-wsa-vra -vmGroup sfo-m01-vm-group-wsa -dependOnVmGroup sfo-m01-vm-group-vra
        This example shows how to create a vSphere DRS Cluster group in the vCenter Server of the sfo-m01 workload domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER ruleName
        The name of the vSphere DRS Virtual Machine to Virtual Machine startup rule to create.

        .PARAMETER vmGroup
        The name of the vSphere DRS Group (VM Group to start first).

        .PARAMETER dependOnVmGroup
        The name of the vSphere DRS Group (VM Group to start after dependency).
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$ruleName,
        [Parameter (Mandatory = $true)] [String]$vmGroup,
        [Parameter (Mandatory = $true)] [String]$dependOnVmGroup
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (Get-Cluster -Name $cluster | Get-DrsClusterGroup | Where-Object {$_.Name -eq $vmGroup}) {
                                    if (Get-Cluster -Name $cluster | Get-DrsClusterGroup | Where-Object {$_.Name -eq $dependOnVmGroup}) {
                                        if (!(Get-DrsVmToVmGroup -Cluster $cluster -Name $ruleName)) {
                                            Add-DrsVmToVmGroup -name $ruleName -vmGroup $vmGroup -dependOnVmGroup $dependOnVmGroup -Enabled -cluster $cluster | Out-Null
                                            Start-Sleep 5
                                            if (Get-DrsVmToVmGroup -Cluster $cluster -Name $ruleName) {
                                                Write-Output "Adding vSphere DRS VM to VM Group to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): SUCCESSFUL"
                                            } else {
                                                Write-Error "Adding vSphere DRS VM to VM Group to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): POST_VALIDATION_FAILED"
                                            }
                                        } else {
                                            Write-Warning "Adding vSphere DRS VM to VM Group to vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName), already exists: SKIPPED"
                                        }
                                    } else {
                                        Write-Error "vSphere DRS Group (VM Group to Start After) in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($dependOnVmGroup), does not exist: PRE_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Error "vSphere DRS Group (VM Group to Start First) in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($vmGroup), does not exist: PRE_VALIDATION_FAILED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-VmStartupRule

Function Undo-VmStartupRule {
    <#
        .SYNOPSIS
        Remove a VM to VM DRS rule.

        .DESCRIPTION
        The Undo-VmStartupRule cmdlet removes a vSphere DRS Virtual Machine to Virtual Machine startup rule. The cmdlet
        connects to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that that the Virtual Machine to Virtual Machine startup rule has not already been removed from the vCenter Server inventory
        - Removes the vSphere DRS Virtual Machine to Virtual Machine startup rule from the vCenter Server inventory

        .EXAMPLE
        Undo-VmStartupRule -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -ruleName vm-vm-rule-wsa-vrli
        This example shows how to remove a vSphere DRS Cluster group from the vCenter Server of the sfo-m01 workload domain.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER ruleName
        The name of the vSphere DRS Virtual Machine to Virtual Machine startup rule to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$ruleName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                        if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                            if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                                $cluster = (Get-VCFCluster | Where-Object { $_.id -eq ((Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }).clusters.id) }).Name
                                if (Get-DrsVmToVmGroup -Cluster $cluster -Name $ruleName) {
                                    Remove-DrsVmToVmGroup -name $ruleName -cluster $cluster | Out-Null
                                    Start-Sleep 3
                                    if (!(Get-DrsVmToVmGroup -Cluster $cluster -Name $ruleName)) {
                                        Write-Output "Removing vSphere DRS VM to VM Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): SUCCESSFUL"
                                    } else {
                                        Write-Error "Removing vSphere DRS VM to VM Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Removing vSphere DRS VM to VM Group from vCenter Server ($($vcfVcenterDetails.fqdn)) named ($ruleName), already removed: SKIPPED"
                                }
                                Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-VmStartupRule

Function Move-VMtoFolder {
    <#
        .SYNOPSIS
        Moves VMs to a folder.

        .DESCRIPTION
        The Move-VMtoFolder cmdlet moves the Virtual Machines to a folder. The cmdlet connects to SDDC Manager using
        the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Retrives the details of the vCenter Server for the Workload Domain provided
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates the virtual machine exists in the vCenter Server inventory
        - Moves the virtual machines provided in the -vmlist parameter

        .EXAMPLE
        Move-VMtoFolder -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -vmList "xreg-wsa01a,xreg-wsa01b,xreg-wsa01c" -folder xinst-m01-fd-wsa
        This example shows how to move a list of virtual machines to a new folder.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER vmList
        The list of virtual machines to move to the folder.

        .PARAMETER folder
        The folder to move the virtual machines to.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server,
        [Parameter (Mandatory = $true)] [String]$user,
        [Parameter (Mandatory = $true)] [String]$pass,
        [Parameter (Mandatory = $true)] [String]$domain,
        [Parameter (Mandatory = $true)] [String]$vmList,
        [Parameter (Mandatory = $true)] [String]$folder
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain -ErrorAction SilentlyContinue) {
                    Connect-VIServer -Server $vcenter.fqdn -User $vcenter.ssoAdmin -pass $vcenter.ssoAdminPass | Out-Null
                    if ($DefaultVIServer.Name -eq $($vcenter.fqdn)) {
                        if (Get-Folder | Where-Object {$_.Name -eq $folder}) {
                            $vmNames = $vmList.split(",")
                            foreach ($vm in $vmNames) { 
                                if (Get-VM -Name $vm -ErrorAction SilentlyContinue) {
                                    Get-VM -Name $vm | Move-VM -InventoryLocation (Get-Folder | Where-Object {$_.Name -eq $folder}) | Out-Null
                                    Write-Output "Relocating Virtual Machine in vCenter Server ($($vcenter.fqdn)) named ($vm) to folder ($folder): SUCCESSFUL"
                                } else {
                                    Write-Error "Relocating Virtual Machines in vCenter Server ($($vcenter.fqdn)) named ($vm) to folder ($folder), Vitual Machine not found: SKIPPED"
                                }
                            }
                        } else {
                            Write-Error "Relocating Virtual Machine in vCenter Server ($($vcenter.fqdn)) folder ($folder), Folder not found: PRE_VALIDATION_FAILED"
                        }
                        Disconnect-VIServer $vcenter.fqdn -Confirm:$false -WarningAction SilentlyContinue
                    } else {
                        Write-Error "Unable to connect to vCenter Server ($($vcenter.fqdn)): PRE_VALIDATION_FAILED"
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Move-VMtoFolder

Function Add-VdsPortGroup {
    <#
        .SYNOPSIS
        Create vSphere Distributed port group.

        .DESCRIPTION
        The Add-VdsPortGroup cmdlet creates a vSphere Distributed port groups in vCenter Server. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible the SDDC Manager instance
        - Validates that network connectivity and authentication is possible the vCenter Server instance
        - Creates a vSphere Distributed port group in vCenter Server

        .EXAMPLE
        Add-VdsPortGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -portgroup sfo-m01-cl01-vds01-pg-vrms -vlan 2619
        This example creates a vSphere Distributed port group for VLAN ID 2619 named sfo-m01-cl01-vds01-pg-vrms in vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER portgroup
        The name of the vSphere Distributed port group to create.

        .PARAMETER vlan
        The VLAN ID to assign to the vSphere Distributed port group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$portgroup,
        [Parameter (Mandatory = $true)] [ValidateRange(0,4094)] [Int]$vlan
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (!(Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)})) {
                                $createVDPortGroup = New-VDPortGroup -Server $vcfVcenterDetails.fqdn -VDSwitch (Get-VDSwitch -Server $vcfVcenterDetails.fqdn).Name -Name $portgroup -VlanId $vlan -ErrorAction Stop
                                $createVDPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -LoadBalancingPolicy LoadBalanceLoadBased | Out-Null
                                if (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {($_.Name -eq $portgroup)}) {
                                    Write-Output "Creating vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($($portgroup)): SUCCESSFUL"
                                } else {
                                    Write-Error "Creating vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($($portgroup)): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Creating vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($($portgroup)), already exists: SKIPPED"
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-VdsPortGroup

Function Undo-VdsPortGroup {
    <#
        .SYNOPSIS
        Removes vSphere Distributed port group.

        .DESCRIPTION
        The Undo-VdsPortGroup cmdlet removes a vSphere Distributed port groups in vCenter Server. The cmdlet connects
        to SDDC Manager using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible the SDDC Manager instance
        - Validates that network connectivity and authentication is possible the vCenter Server instance
        - Removes the vSphere Distributed port group in vCenter Server

        .EXAMPLE
        Undo-VdsPortGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -portgroup sfo-m01-cl01-vds01-pg-vrms
        This example removes the vSphere Distributed port group named sfo-m01-cl01-vds01-pg-vrms from vCenter Server.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The SDDC Manager domain.

        .PARAMETER portgroup
        The name of the vSphere Distributed port group to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$portgroup
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            if (Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {$_.Name -eq $portgroup}) {
                                Remove-VDPortGroup -Server $vcfVcenterDetails.fqdn -VDPortGroup $portGroup -Confirm:$false -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null         
                                if (!(Get-VDPortGroup -Server $vcfVcenterDetails.fqdn | Where-Object {$_.Name -eq $portgroup})) {
                                    Write-Output "Removing vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($($portgroup)): SUCCESSFUL"
                                } else {
                                    Write-Error "Removing vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($($portgroup)): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Removing vSphere Distributed Port Group in vCenter Server ($($vcfVcenterDetails.fqdn)) named ($($portgroup)), dosen't exist: SKIPPED"
                            }
                            Disconnect-VIServer * -Force -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-VdsPortGroup

Function Import-vRSLCMLockerCertificate {
    <#
        .SYNOPSIS
        Add a certificate to the VMware Aria Suite Lifecycle locker.

        .DESCRIPTION
        The Import-vRSLCMLockerCertificate cmdlet imports a PEM encoded chain file to the VMware Aria Suite Lifecycle
        Manager Locker. The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the certificate is not present in the VMware Aria Suite Lifecycle locker
        - Imports the certificate chain to the VMware Aria Suite Lifecycle locker

        .EXAMPLE
        Import-vRSLCMLockerCertificate -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -certificateAlias "xint-vrops01" -certificatePassphrase "VMw@re1!"
        This example adds a certificate to the VMware Aria Suite Lifecycle locker.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER certificateAlias
        The alias of the certificate to add to the VMware Aria Suite Lifecycle locker.

        .PARAMETER certificatePassphrase
        The passphrase of the certificate to add to the VMware Aria Suite Lifecycle locker.

        .PARAMETER certChainPath
        The path to the certificate chain file to add to the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateAlias,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificatePassphrase,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certChainPath
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("certChainPath")) {
            $certChainPath = Get-ExternalFileName -title "Select the Certificate Chain PEM File (.pem)" -fileType "pem" -location "default"
        } else {
            if (!(Test-Path -Path $certChainPath)) {
                Write-Error  "Certificate Chain '$certChainPath' File Not Found"
                Break
            }
        }

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (!(Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $certificateAlias})) {
                                if ($PsBoundParameters.ContainsKey("certificatePassphrase")) {
                                    Add-vRSLCMLockerCertificate -vrslcmFQDN $vcfVrslcmDetails.fqdn -certificateAlias $certificateAlias -certificatePassphrase $certificatePassphrase -certChainPath $certChainPath | Out-Null
                                } else {
                                    Add-vRSLCMLockerCertificate -vrslcmFQDN $vcfVrslcmDetails.fqdn -certificateAlias $certificateAlias -certChainPath $certChainPath | Out-Null
                                }
                                if ((Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $certificateAlias})) {
                                    Write-Output "Importing Certificate to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($certificateAlias): SUCCESSFUL"
                                } else {
                                    Write-Error "Importing Certificate to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($certificateAlias): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Importing Certificate to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($certificateAlias), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Import-vRSLCMLockerCertificate

Function Undo-vRSLCMLockerCertificate {
    <#
        .SYNOPSIS
        Remove a certificate from the VMware Aria Suite Lifecycle locker.

        .DESCRIPTION
        The Undo-vRSLCMLockerCertificate cmdlet removes a certificate from the VMware Aria Suite Lifecycle locker.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the certificate is present in the VMware Aria Suite Lifecycle locker
        - Removes the certificate from VMware Aria Suite Lifecycle locker

        .EXAMPLE
        Undo-vRSLCMLockerCertificate -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -certificateAlias "xint-vrops01"
        This example removes a certificate with an alias of 'xint-vrops01' from the VMware Aria Suite Lifecycle locker.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER certificateAlias
        The alias of the certificate to remove from the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateAlias
    )

    Try {

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $certificateAlias}) {
                                Remove-vRSLCMLockerCertificate -vmid (Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $certificateAlias}).vmid | Out-Null
                                if ((Get-vRSLCMLockerCertificate | Where-Object {$_.alias -eq $certificateAlias})) {
                                    Write-Error "Removing Certificate from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($certificateAlias): POST_VALIDATION_FAILED"
                                } else {
                                    Write-Output "Removing Certificate from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($certificateAlias): SUCCESSFUL"
                                }
                            } else {
                                Write-Warning "Removing Certificate from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($certificateAlias), does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Undo-vRSLCMLockerCertificate

Function New-vRSLCMLockerPassword {
    <#
        .SYNOPSIS
        Add a password to the VMware Aria Suite Lifecycle locker Locker.

        .DESCRIPTION
        The New-vRSLCMLockerPassword cmdlet adds a password to the VMware Aria Suite Lifecycle locker.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the password is not present in the VMware Aria Suite Lifecycle locker
        - Adds the password to the VMware Aria Suite Lifecycle locker

        .EXAMPLE
        New-vRSLCMLockerPassword -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alias xint-vrops01-admin -password VMw@re1! -description "VMware Aria Operations Admin" -userName xint-vrops01-admin
        This example adds a password with an alias of 'xint-vrops01-admin' to the VMware Aria Suite Lifecycle locker.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER alias
        The alias of the password to add to the VMware Aria Suite Lifecycle locker.

        .PARAMETER password
        The password to add to the VMware Aria Suite Lifecycle locker.

        .PARAMETER description
        The description of the password to add to the VMware Aria Suite Lifecycle locker.

        .PARAMETER userName
        The username of the password to add to the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$description,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userName
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (!(Get-vRSLCMLockerPassword -alias $alias)) {
                                if ($PsBoundParameters.ContainsKey("description")) {
                                    $lockerPassword = Add-vRSLCMLockerPassword -alias $alias -password $password -description $description -userName $userName
                                } else {
                                    $lockerPassword = Add-vRSLCMLockerPassword -alias $alias -password $password -userName $userName
                                }
                                if ((Get-vRSLCMLockerPassword -alias $alias)) {
                                    Write-Output "Adding Password to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding Password to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Warning "Adding Password to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMLockerPassword

Function Undo-vRSLCMLockerPassword {
    <#
        .SYNOPSIS
        Remove a password from the VMware Aria Suite Lifecycle locker.

        .DESCRIPTION
        The Undo-vRSLCMLockerPassword cmdlet removes a password from the Aria Suite Lifecycle locker.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the password is present in the VMware Aria Suite Lifecycle locker
        - Removes the password from the VMware Aria Suite Lifecycle locker

        .EXAMPLE
        Undo-vRSLCMLockerPassword -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alias xint-vrops01-admin
        This example removes a password with an alias of 'xint-vrops01-admin' from the VMware Aria Suite Lifecycle locker.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER alias
        The alias of the password to remove from the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMLockerPassword -alias $alias) {
                                Remove-vRSLCMLockerPassword -vmid (Get-vRSLCMLockerPassword -alias $alias).vmid | Out-Null
                                if ((Get-vRSLCMLockerPassword -alias $alias)) {
                                    Write-Error "Removing Password from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): POST_VALIDATION_FAILED"
                                } else {
                                    Write-Output "Removing Password from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): SUCCESSFUL"
                                }
                            } else {
                                Write-Warning "Removing Password from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias), does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Undo-vRSLCMLockerPassword

Function New-vRSLCMLockerLicense {
    <#
        .SYNOPSIS
        Add a license to the VMware Aria Suite Lifecycle locker.

        .DESCRIPTION
        The New-vRSLCMLockerLicense cmdlet adds a license to the Aria Suite Lifecycle locker.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - CValidates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the license is not present in the VMware Aria Suite Lifecycle locker
        - Adds the license to the VMware Aria Suite Lifecycle locker

        .EXAMPLE
        New-vRSLCMLockerLicense -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alias "VMware Aria Automation" -license "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
        This example adds a license with an alias of 'VMware Aria Automation' to the VMware Aria Suite Lifecycle locker.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER alias
        The alias of the license to add to the VMware Aria Suite Lifecycle locker.

        .PARAMETER license
        The license key to add to the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$license
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (!(Get-vRSLCMLockerLicense | Where-Object {$_.key -eq $license})) {
                                if (!(Get-vRSLCMLockerLicense | Where-Object {$_.alias -eq $alias})) {
                                    $newRequest = Add-vRSLCMLockerLicense -alias $alias -license $license
                                    Start-Sleep 3
                                    $status = Watch-vRSLCMRequest -vmid $($newRequest.requestId)
                                    if ($status -match "COMPLETED") {
                                        if ((Get-vRSLCMLockerLicense | Where-Object {$_.key -eq $license})) {
                                            Write-Output "Adding License to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding License to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Error "$status"
                                    }
                                } else {
                                    Write-Warning "Adding License to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias), already exists: SKIPPED"
                                }
                            } else {
                                Write-Warning "Adding License to the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with license ($license), already exists: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMLockerLicense

Function Undo-vRSLCMLockerLicense {
    <#
        .SYNOPSIS
        Remove a license to the VMware Aria Suite Lifecycle locker.

        .DESCRIPTION
        The Undo-vRSLCMLockerLicense cmdlet removes a license from the VMware Aria Suite Lifecycle locker.
        The cmdlet connects to SDDC Manager using the -server, -user, and -password values then:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to VMware Aria Suite Lifecycle
        - Verifies that the license is present in the VMware Aria Suite Lifecycle locker
        - Removes the license to the VMware Aria Suite Lifecycle locker

        .EXAMPLE
        Undo-vRSLCMLockerLicense -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -alias "VMware Aria Automation"
        This example removes a license with an alias of 'VMware Aria Automation' from the VMware Aria Suite Lifecycle locker.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER alias
        The alias of the license to remove from the VMware Aria Suite Lifecycle locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVrslcmDetails = Get-vRSLCMServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-vRSLCMConnection -server $vcfVrslcmDetails.fqdn) {
                        if (Test-vRSLCMAuthentication -server $vcfVrslcmDetails.fqdn -user $vcfVrslcmDetails.adminUser -pass $vcfVrslcmDetails.adminPass) {
                            if (Get-vRSLCMLockerLicense | Where-Object {$_.alias -eq $alias}) {
                                Remove-vRSLCMLockerLicense -vmid (Get-vRSLCMLockerLicense | Where-Object {$_.alias -eq $alias}).vmid | Out-Null
                                if (Get-vRSLCMLockerLicense | Where-Object {$_.key -eq $license}) {
                                    Write-Error "Removing License from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): POST_VALIDATION_FAILED"
                                } else {
                                    Write-Output "Removing License from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias): SUCCESSFUL"
                                }
                            } else {
                                Write-Warning "Removing License from the VMware Aria Suite Lifecycle ($($vcfVrslcmDetails.fqdn)) Locker with alias ($alias), does not exist: SKIPPED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Undo-vRSLCMLockerLicense

Function Add-VmGroup {
    <#
        .SYNOPSIS
        Add a VM Group.

        .DESCRIPTION
        The Add-VmGroup cmdlet adds a Virtual Machine to an existing VM Group. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Validates that the the VM Group provided exists and that its a VM Group not a VM Host Group
        - Adds the Virtual Machines provided using -vmList

        .EXAMPLE
        Add-VmGroup -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -name "sfo-m01_primary-az-vmgroup" -vmList "xint-vra01a,xint-vra01b,xint-vra01c"
        This example adds the VMware Aria Automation cluster VMs to the VM Group called primary_az_vmgroup.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The Active Directory Domain name.

        .PARAMETER name
        The VM Group name.

        .PARAMETER vmList
        The Virtual Machines to add to the VM Group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmList
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($vcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain) {
                    Connect-VIServer -Server $vcenter.fqdn -User $vcenter.ssoAdmin -Pass $vcenter.ssoAdminPass | Out-Null
                    if ($DefaultVIServer.Name -eq $($vcenter.fqdn)) {
                        $vmGroupExists = Get-DrsClusterGroup -Server $vcenter.fqdn -Name $name -ErrorAction Ignore
                        if ($vmGroupExists.GroupType -eq "VMGroup") {
                            $vmNames = $vmList.split(",")
                            foreach ($vm in $vmNames) { Set-DrsClusterGroup -VM $vm -Server $vcenter.fqdn -DrsClusterGroup (Get-DrsClusterGroup | Where-Object {$_.Name -eq $name} -WarningAction SilentlyContinue -ErrorAction Ignore) -Add | Out-Null }
                            Write-Output "Adding Virtual Machines ($vmList) to VM/Host Group in vCenter Server ($($vcenter.fqdn)) named ($name): SUCCESSFUL"
                        } else {
                            Write-Error "Adding Virtual Machines ($vmList) to VM/Host Group in vCenter Server ($($vcenter.fqdn)) named ($name), does not exist or not a VM Group: POST_VALIDATION_FAILED"
                        }
                    } else {
                        Write-Error "Unable to connect to vCenter Server ($($vcenter.fqdn)): PRE_VALIDATION_FAILED"
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-VmGroup

Function Add-WorkspaceOneDirectoryGroup {
    <#
        .SYNOPSIS
        Adds Active Directory Group to sync in Workspace ONE Access Appliance.

        .DESCRIPTION
        The Add-WorkspaceOneDirectoryGroup cmdlet adds an Active Directory Group to sync in Workspace ONE Access Appliance
        - Validates that network connectivity and authentication is possible to Workspace ONE Access
        - Adds Active Directory Groups to Workspace ONE Access

        .EXAMPLE
        Add-WorkspaceOneDirectoryGroup -server sfo-wsa01.sfo.rainpole.io -user admin -pass VMw@re1! -domain sfo.rainpole.io -bindUser svc-vsphere-ad -bindPass VMw@re1! -baseDnGroup "ou=Security Groups,dc=sfo,dc=rainpole,dc=io" -adGroups "gg-vrli-admins","gg-vrli-users","gg-vrli-viewers"
        This example adds Active Directory groups to Workspace ONE Access directory.

        .PARAMETER server
        The Workspace ONE Access Appliance FQDN or IP Address.

        .PARAMETER user
        The Workspace ONE Access Appliance admin user.

        .PARAMETER pass
        The Workspace ONE Access Appliance admin password.

        .PARAMETER domain
        The Active Directory Domain name.

        .PARAMETER bindUser
        The Active Directory Domain user with read access to the domain.

        .PARAMETER bindPass
        The Active Directory Domain user password.

        .PARAMETER baseDnGroup
        The Active Directory Domain base DN for groups.

        .PARAMETER adGroups
        The Active Directory Domain groups to sync.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDnGroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$adGroups
    )

    Try {
        if (Test-WSAConnection -server $server) {
            if (Test-WSAAuthentication -server $server -user $user -pass $pass) {
                if ((Test-ADAuthentication -user $bindUser -pass $bindPass -server $domain -domain $domain) -match "AD Authentication Successful") {
                    if (Get-WSADirectory | Where-Object { ($_.name -eq $domain) }) {
                        $configuredGroups = New-Object System.Collections.Generic.List[System.Object]
                        $allGroups = New-Object System.Collections.Generic.List[System.Object]
                        $existingGroupList = Get-WSAGroup | Where-Object {$_.displayName -Match $domain} | Select-Object displayName
                        foreach ($existingGroup in $existingGroupList) {
                            $groupName = ($existingGroup.displayname.Split("@"))[0]
                            $configuredGroups.Add($groupName)
                            $allGroups.Add($groupName)
                        }                    
                        $missingGroups = Compare-Object $adGroups $configuredGroups |  Where-Object { $_.SideIndicator -eq '<=' } | Foreach-Object { $_.InputObject }
                        foreach ($newGroup in $missingGroups) {
                            $allGroups.Add($newGroup)
                        }
                        $allGroups.ToArray() | Out-Null

                        $mappedGroupObject = @()
                        foreach ($group in $allGroups) {
                            $adGroupDetails = Get-ADPrincipalGuid -domain $domain -user $bindUser -pass $bindPass -principal $group
                            if ($adGroupDetails) {
                                $groupsObject = @()
                                $groupsObject += [pscustomobject]@{
                                    'horizonName' = $adGroupDetails.Name
                                    'dn'          = $adGroupDetails.DistinguishedName
                                    'objectGuid'  = $adGroupDetails.ObjectGuid
                                    'groupBaseDN' = $baseDnGroup
                                    'source'      = "DIRECTORY"
                                }
                                $mappedGroupObject += [pscustomobject]@{
                                    'mappedGroup' = ($groupsObject | Select-Object -Skip 0)
                                    'selected'    = $true
                                }
                            } else {
                                Write-Error "Group $group is not available in Active Directory Domain"
                            }
                        }
                        $mappedGroupObjectData = @()
                        $mappedGroupObjectData += [pscustomobject]@{
                            'mappedGroupData' = $mappedGroupObject
                            'selected'        = $false
                        }
                        $identityGroupObject = @()
                        $identityGroupObject += [pscustomobject]@{
                            $baseDnGroup = ($mappedGroupObjectData | Select-Object -Skip 0)
                        }
                        $adGroupObject = @()
                        $adGroupObject += [pscustomobject]@{
                            'identityGroupInfo'         = ($identityGroupObject | Select-Object -Skip 0)
                            'excludeNestedGroupMembers' = $false
                        }
                        $adGroupJson = $adGroupObject | ConvertTo-Json -Depth 10 

                        $adGroupJson | Out-File -Encoding UTF8 -FilePath .\adGroups.json

                        Set-WSADirectoryGroup -directoryId (Get-WSADirectory | Where-Object { ($_.name -eq $domain) }).directoryId -json $adGroupJson | Out-Null
                        Start-WSADirectorySync -directoryId (Get-WSADirectory | Where-Object { ($_.name -eq $domain) }).directoryId | Out-Null
                        Remove-Item .\adGroups.json -Force -Confirm:$false
                        Write-Output "Adding Active Directory Groups in Workspace ONE Access ($server): SUCCESSFUL"
                    } else {
                        Write-Error "Active Directory Domain ($domain) does not exist, check details and try again: PRE_VALIDATION_FAILED"
                    }
                } else {
                    Write-Error "Domain User ($bindUser) Authentication Failed: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-WorkspaceOneDirectoryGroup

Function Undo-WorkspaceOneDirectoryGroup {
    <#
        .SYNOPSIS
        Removes Active Directory Group from Workspace ONE Access.

        .DESCRIPTION
        The Undo-WorkspaceOneDirectoryGroup cmdlet removes an Active Directory Group from Workspace ONE Access.
        - Validates that network connectivity and authentication is possible to Workspace ONE Access
        - Remove Active Directory Groups from Workspace ONE Access

        .EXAMPLE
        Undo-WorkspaceOneDirectoryGroup -server sfo-wsa01.sfo.rainpole.io -user admin -pass VMw@re1! -domain sfo.rainpole.io -bindUser svc-vsphere-ad -bindPass VMw@re1! -baseDnGroup "ou=Security Groups,dc=sfo,dc=rainpole,dc=io" -adGroups "gg-vrli-admins","gg-vrli-users","gg-vrli-viewers"
        This example removes Active Directory groups from Workspace ONE Access directory.

        .PARAMETER server
        The Workspace ONE Access Appliance FQDN or IP Address.

        .PARAMETER user
        The Workspace ONE Access Appliance administrator username.

        .PARAMETER pass
        The Workspace ONE Access Appliance administrator password.

        .PARAMETER domain
        The Active Directory Domain name.

        .PARAMETER bindUser
        The Active Directory Domain user account to bind to.

        .PARAMETER bindPass
        The Active Directory Domain user account password.

        .PARAMETER baseDnGroup
        The Active Directory Domain base DN for groups.

        .PARAMETER adGroups
        The Active Directory Domain groups to remove from Workspace ONE Access.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDnGroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$adGroups
    )

    Try {
        if (Test-WSAConnection -server $server) {
            if (Test-WSAAuthentication -server $server -user $user -pass $pass) {
                if ((Test-ADAuthentication -user $bindUser -pass $bindPass -server $domain -domain $domain) -match "AD Authentication Successful") {
                    if (Get-WSADirectory | Where-Object { ($_.name -eq $domain) }) {
                        $configuredGroups = New-Object System.Collections.Generic.List[System.Object]
                        $allGroups = New-Object System.Collections.Generic.List[System.Object]
                        $existingGroupList = Get-WSAGroup | Where-Object {$_.displayName -Match $domain} | Select-Object displayName
                        foreach ($existingGroup in $existingGroupList) {
                            $groupName = ($existingGroup.displayname.Split("@"))[0]
                            $configuredGroups.Add($groupName)
                        }                    
                        $requiredGroups = Compare-Object $adGroups $configuredGroups | Foreach-Object { $_.InputObject } #| Where-Object { $_.SideIndicator -eq '==' } | Foreach-Object { $_.InputObject }
                        foreach ($newGroup in $requiredGroups) {
                            $allGroups.Add($newGroup)
                        }
                        $allGroups.ToArray() | Out-Null
                        $mappedGroupObject = @()
                        foreach ($group in $allGroups) {
                            $adGroupDetails = Get-ADPrincipalGuid -domain $domain -user $bindUser -pass $bindPass -principal $group
                            if ($adGroupDetails) {
                                $groupsObject = @()
                                $groupsObject += [pscustomobject]@{
                                    'horizonName' = $adGroupDetails.Name
                                    'dn'          = $adGroupDetails.DistinguishedName
                                    'objectGuid'  = $adGroupDetails.ObjectGuid
                                    'groupBaseDN' = $baseDnGroup
                                    'source'      = "DIRECTORY"
                                }
                                $mappedGroupObject += [pscustomobject]@{
                                    'mappedGroup' = ($groupsObject | Select-Object -Skip 0)
                                    'selected'    = $true
                                }
                            } else {
                                Write-Error "Group $group is not available in Active Directory Domain"
                            }
                        }
                        $mappedGroupObjectData = @()
                        $mappedGroupObjectData += [pscustomobject]@{
                            'mappedGroupData' = $mappedGroupObject
                            'selected'        = $false
                        }
                        $identityGroupObject = @()
                        $identityGroupObject += [pscustomobject]@{
                            $baseDnGroup = ($mappedGroupObjectData | Select-Object -Skip 0)
                        }
                        $adGroupObject = @()
                        $adGroupObject += [pscustomobject]@{
                            'identityGroupInfo'         = ($identityGroupObject | Select-Object -Skip 0)
                            'excludeNestedGroupMembers' = $false
                        }
                        $adGroupJson = $adGroupObject | ConvertTo-Json -Depth 10 
                        $adGroupJson | Out-File -Encoding UTF8 -FilePath .\adGroups.json
                        Set-WSADirectoryGroup -directoryId (Get-WSADirectory | Where-Object { ($_.name -eq $domain) }).directoryId -json $adGroupJson | Out-Null
                        Start-WSADirectorySync -directoryId (Get-WSADirectory | Where-Object { ($_.name -eq $domain) }).directoryId | Out-Null
                        Remove-Item .\adGroups.json -Force -Confirm:$false
                        Write-Output "Removing Active Directory Groups in Workspace ONE Access ($server): SUCCESSFUL"
                    } else {
                        Write-Error "Active Directory Domain ($domain) does not exist, check details and try again: PRE_VALIDATION_FAILED"
                    }
                } else {
                    Write-Error "Domain User ($bindUser) Authentication Failed: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-WorkspaceOneDirectoryGroup

Function Add-WorkspaceOneDirectoryConnector {
    <#
        .SYNOPSIS
        Adds a connector to the directory in Workspace ONE Access Appliance.

        .DESCRIPTION
        The Add-WorkspaceOneDirectoryConnector cmdlet adds a connector to the directory in Workspace ONE Access Appliance

        .EXAMPLE
        Add-WorkspaceOneDirectoryConnector -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo.rainpole.io -wsaNode xint-wsa01b.rainpole.io -wsaUser admin -wsaPass VMw@re1! -bindUserPass VMw@re1!
        This example adds Active Directory groups to Workspace ONE Access directory.

        .PARAMETER server
        The Workspace ONE Access FQDN.

        .PARAMETER user
        The Workspace ONE Access Administrator username.

        .PARAMETER pass
        The Workspace ONE Access Administrator password.

        .PARAMETER domain
        The Active Directory domain name.

        .PARAMETER wsaNode
        The Workspace ONE Access Connector node name.

        .PARAMETER wsaUser
        The Workspace ONE Access Connector Administrator username.

        .PARAMETER wsaPass
        The Workspace ONE Access Connector Administrator password.

        .PARAMETER bindUserPass
        The Active Directory Bind User password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaNode,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUserPass
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfWsaDetails = Get-WSAServerDetail -fqdn $server -username $user -password $pass)) {
                    if (Test-WSAConnection -server $vcfWsaDetails.loadBalancerFqdn) {
                        if (Test-WSAAuthentication -server $vcfWsaDetails.loadBalancerFqdn -user $wsaUser -pass $wsaPass) { 
                            if ($directoryId = (Get-WSADirectory | Where-Object {$_.name -eq $domain}).directoryId) {
                                if (Get-WSAConnector | Where-Object {$_.host -eq $wsaNode}) {
                                    if (!(Get-WSADirectory -directoryId $directoryId -connector | Where-Object {$_.host -eq $wsaNode})) {
                                        Add-WSAConnector -wsaNode $wsaNode -domain $domain -bindUserPass $bindUserPass | Out-Null
                                        if (Get-WSADirectory -directoryId $directoryId -connector | Where-Object {$_.host -eq $wsaNode}) {
                                            Write-Output "Adding Connector to Directory ($domain) in Workspace ONE Access ($($vcfWsaDetails.loadBalancerFqdn)) named ($wsaNode): SUCCESSFUL"
                                        } else {
                                            Write-Error "Adding Connector to Directory ($domain) in Workspace ONE Access ($($vcfWsaDetails.loadBalancerFqdn)) named ($wsaNode): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Adding Connector to Directory ($domain) in Workspace ONE Access ($($vcfWsaDetails.loadBalancerFqdn)) named ($wsaNode), already exists: SKIPPED"
                                    }
                                } else {
                                    Write-Error "Unable to find node in Workspace ONE Access ($($vcfWsaDetails.loadBalancerFqdn)) named ($wsaNode): PRE_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Unable to find Active Directory domain in Workspace ONE Access ($($vcfWsaDetails.loadBalancerFqdn)) named ($domain): PRE_VALIDATION_FAILED"
                            }
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-WorkspaceOneDirectoryConnector

Function Update-SddcDeployedFlavor {
    <#
        .SYNOPSIS
        Add a Validated Solution tag.

        .DESCRIPTION
        The Update-SddcDeployedFlavor cmdlet adds a Validated Solution tag to the vCenter Server Advanced Setting
        `config.SDDC.Deployed.Flavor`. The cmdlet connects to SDDC Manager using the -server, -user, and -password
        values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to vCenter Server
        - Adds a Validated Solution tag to the vCenter Server Advanced Setting `config.SDDC.Deployed.Flavor`

        .EXAMPLE
        Update-SddcDeployedFlavor -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -vvsTag IAM
        This example adds the IAM tag to the `config.SDDC.Deployed.Flavor` vCenter Server Advanced Setting.

        .PARAMETER server
        The vCenter Server FQDN.

        .PARAMETER user
        The vCenter Server SSO Administrator username.

        .PARAMETER pass
        The vCenter Server SSO Administrator password.

        .PARAMETER vvsTag
        The Validated Solution tag to be added to the vCenter Server Advanced Setting `config.SDDC.Deployed.Flavor`.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateSet("IAM","DRI","ILA","IOM","PCA","PDR","ALB")] [String]$vvsTag
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType MANAGEMENT)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $advancedSetting = Get-AdvancedSetting -Name "config.SDDC.Deployed.Flavor" -Entity $vcfVcenterDetails.fqdn -Server $vcfVcenterDetails.fqdn
                            [Array]$flavours = $advancedSetting.Value -Split ", "
                            $newFlavours = New-Object System.Collections.Generic.List[System.Object]
                            Foreach ($flavour in $flavours) {
                                if (!($flavour -eq $vvsTag)) {
                                    $newFlavours += $flavour
                                }
                            }
                            $newFlavours += $vvsTag
                            $newFlavours = $newFlavours | Sort-Object
                            [String]$updatedFlavour = $newFlavours -Join ", " 
                            Set-AdvancedSetting -AdvancedSetting $advancedSetting -Value $updatedFlavour -Confirm:$false | Out-Null
                            Disconnect-VIServer -Server $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue | Out-Null
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Update-SddcDeployedFlavor

Function Invoke-VcenterCommand {
    <#
        .SYNOPSIS
        Invoke a command line operation on vCenter Server.

        .DESCRIPTION
        The Invoke-VcenterCommand cmdlet allows you to invoke any command line operation on a vCenter Server managed
        by SDDC Manager

        .EXAMPLE
        Invoke-VcenterCommand -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -command "ip -s -s neigh flush all"
        This example invokes the command to flush the ARP table for the vCenter Server of a given workload domain.

        .PARAMETER server
        The vCenter Server FQDN.

        .PARAMETER user
        The vCenter Server SSO Administrator username.

        .PARAMETER pass
        The vCenter Server SSO Administrator password.

        .PARAMETER domain
        The vCenter Server SSO Administrator domain.

        .PARAMETER command
        The command to be executed on the vCenter Server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$command
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domainType "MANAGEMENT")) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $workloadDomainVcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain
                            $output = Invoke-VMScript -VM $workloadDomainVcenter.vmName -ScriptText $command -GuestUser $workloadDomainVcenter.root -GuestPassword $workloadDomainVcenter.rootPass -Server $vcfVcenterDetails.fqdn
                            Write-Output ""; Write-Output "Executing command ($command) on vCenter Server ($($workloadDomainVcenter.fqdn))"
                            Write-Output ""; Write-Output "$output"
                            Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                        }
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Invoke-VcenterCommand

Function Import-ContentLibraryItem {
    <#
        .SYNOPSIS
        Import an item to a content library

        .DESCRIPTION
        The Import-ContentLibraryItem cmdlet imports an item into the content library
        .EXAMPLE
        Import-ContentLibraryItem -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -contentLibrary Operations -file <file_name>
        This example configures Private Cloud Automation using the JSON specification provided.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$contentLibrary,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$file
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (($vcfVcenterDetails = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain)) {
                    if (Test-VsphereConnection -server $($vcfVcenterDetails.fqdn)) {
                        if (Test-VsphereAuthentication -server $vcfVcenterDetails.fqdn -user $vcfVcenterDetails.ssoAdmin -pass $vcfVcenterDetails.ssoAdminPass) {
                            $templateName = (Get-ChildItem -file $file).basename
                            if (Get-ContentLibrary -Name $contentLibrary -ErrorAction SilentlyContinue -WarningAction SilentlyContinue) {
                                if (!(Get-ContentLibraryItem | Where-Object {$_.ContentLibrary -match $contentLibrary -and $_.Name -eq $templateName})) {
                                    New-ContentLibraryItem -ContentLibrary $contentLibrary -Name $templateName -Files $file | Out-Null
                                    if (Get-ContentLibraryItem | Where-Object {$_.ContentLibrary -match $contentLibrary -and $_.Name -eq $templateName}) {
                                        Write-Output "Importing ($templateName) to Content Library ($contentLibrary) for Workload Domain ($domain): SUCCESSFUL"
                                    } else {
                                        Write-Error "Importing ($templateName) to Content Library ($contentLibrary) for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Importing ($templateName) to Content Library ($contentLibrary) for Workload Domain ($domain), already exists: SKIPPED"
                                }
                            } else {
                                Write-Error "Unable to find Content Library ($contentLibrary) in vCenter Server ($($vcfVcenterDetails.fqdn)): PRE_VALIDATION_FAILED"
                            }
                        }
                        Disconnect-VIServer $vcfVcenterDetails.fqdn -Confirm:$false -WarningAction SilentlyContinue
                    }
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Import-ContentLibraryItem

Function Add-NsxtPrincipalIdentity {
    <#
        .SYNOPSIS
        Add a principal identity to NSX Manager.

        .DESCRIPTION
        The Add-NsxtPrincipalIdentity cmdlet adds a principal identity to NSX Manager. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Adds a principal identity to NSX Manager.

        .EXAMPLE
        Add-NsxtPrincipalIdentity -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -principalId svc-iom-sfo-m01-nsx01 -role enterprise_admin
        This example adds a principal identity to NSX Manager

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload Domain.

        .PARAMETER principalId
        The name of the principal identity to create.

        .PARAMETER role
        The role to assign to the principal identity.

        .PARAMETER outputPath
        The location where the certificate files should be created.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principalId,
        [Parameter (Mandatory = $true)] [ValidateSet("lb_admin", "security_engineer", "vpn_admin", "network_op", "netx_partner_admin", "gi_partner_admin", "security_op", "network_engineer", "lb_auditor", "auditor", "enterprise_admin")] [String]$role,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$outputPath
    )

    Try {
        $command = 'openssl version'
        if ((Invoke-Expression -Command "& $command 2>&1") -match "OpenSSL") {
            if (Test-VCFConnection -server $server) {
                if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                    if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                        if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                            if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                                if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                    if (!(Get-NsxtPrincipalIdentity -name $principalId)) {
                                        if ($PsBoundParameters.ContainsKey("outputPath")) {
                                            $certificateName = $outputPath + ($($vcfNsxDetails.fqdn)).Split('.')[-0]
                                        } else {
                                            $certificateName = ($($vcfNsxDetails.fqdn)).Split('.')[-0]
                                        }
                                        $command = 'openssl req -newkey rsa:2048 -sha256 -x509 -days 365 -subj "/CN='+ $($vcfNsxDetails.fqdn) +'" -extensions usr_cert -nodes -keyout '+ $certificateName +'.key -out '+ $certificateName +'.cer'
                                        Invoke-Expression -Command "& $command 2>&1 | Out-Null"
                                        New-NsxtPrincipalIdentity -name $principalId -nodeId $($vcfNsxDetails.fqdn) -role $role -certificateData ($certificateName +'.cer') | Out-Null
                                        if (Get-NsxtPrincipalIdentity -name $principalId) {
                                            Write-Output "Creating Principal Identity ($principalId) in NSX for Workload Domain ($domain): SUCCESSFUL"
                                        } else {
                                            Write-Error "Creating Principal Identity ($principalId) in NSX for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                        }
                                    } else {
                                        Write-Warning "Creating Principal Identity ($principalId) in NSX for Workload Domain ($domain), already exists: SKIPPED"
                                    }
                                }
                            }
                        }
                    } else {
                        Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                    }
                }
            }
        } else {
            Write-Error "Unable to find OpenSSL on the local machine: PRE_VALIDATION_FAILED"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-NsxtPrincipalIdentity

Function Undo-NsxtPrincipalIdentity {
    <#
        .SYNOPSIS
        Remove a principal identity from NSX Manager.

        .DESCRIPTION
        The Undo-NsxtPrincipalIdentity cmdlet removes a principal identity from NSX Manager. The cmdlet connects to SDDC Manager
        using the -server, -user, and -password values:
        - Validates that network connectivity and authentication is possible to SDDC Manager
        - Validates that network connectivity and authentication is possible to NSX Manager
        - Removes a principal identity from NSX Manager.

        .EXAMPLE
        Undo-NsxtPrincipalIdentity -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-m01 -principalId svc-iom-sfo-m01-nsx01
        This example removes a principal identity from NSX Manager

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domain
        The name of the workload Domain.

        .PARAMETER principalId
        The name of the principal identity to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principalId
    )

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object {$_.name -eq $domain}) {
                    if (($vcfNsxDetails = Get-NsxtServerDetail -fqdn $server -username $user -password $pass -domain $domain)) {
                        if (Test-NSXTConnection -server $vcfNsxDetails.fqdn) {
                            if (Test-NSXTAuthentication -server $vcfNsxDetails.fqdn -user $vcfNsxDetails.adminUser -pass $vcfNsxDetails.adminPass) {
                                if (Get-NsxtPrincipalIdentity -name $principalId) {
                                    Remove-NsxtPrincipalIdentity -principalId (Get-NsxtPrincipalIdentity -name $principalId).id | Out-Null
                                    if (!(Get-NsxtPrincipalIdentity -name $principalId)) {
                                        Write-Output "Deleting Principal Identity ($principalId) in NSX for Workload Domain ($domain): SUCCESSFUL"
                                    } else {
                                        Write-Error "Deleting Principal Identity ($principalId) in NSX for Workload Domain ($domain): POST_VALIDATION_FAILED"
                                    }
                                } else {
                                    Write-Warning "Deleting Principal Identity ($principalId) in NSX for Workload Domain ($domain), does not exist: SKIPPED"
                                }
                            }
                        }
                    }
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Undo-NsxtPrincipalIdentity

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################

#######################################################################################################################
#Region S U P P O R T I N G F U N C T I O N S ###########

###################################################################################
#Region Begin Active Directory Functions ######

Function Test-ADAuthentication {
    <#
        .SYNOPSIS
        Test authetication against Active Directory.

        .DESCRIPTION
        The Test-ADAuthentication cmdlet tests the credentials provided against Active Directory domain

        .EXAMPLE
        Test-ADAuthentication -user svc-vsphere-ad -pass VMw@re1! -server sfo.rainpole.io -domain sfo.rainpole.io
        This example check that the svc-vsphere-ad user can authenticate to the sfo.rainpole.io domain.

        .PARAMETER user
        The Active Directory Domain user account to bind to.

        .PARAMETER pass
        The Active Directory Domain user account password.

        .PARAMETER server
        The Active Directory Domain FQDN.

        .PARAMETER domain
        The Active Directory Domain name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [String]$server,
        [Parameter (Mandatory = $false)] [String]$domain = $env:USERDOMAIN
    )

    Try {
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $contextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain
        $argumentList = New-Object -TypeName "System.Collections.ArrayList"
        $null = $argumentList.Add($contextType)
        $null = $argumentList.Add($domain)
        if ($null -ne $server) {
            $argumentList.Add($server)
        }
        $principalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $argumentList -ErrorAction SilentlyContinue
        if ($null -eq $principalContext) {
            Write-Error "$domain\$user - AD Authentication Failed"
        }
        if ($principalContext.ValidateCredentials($user, $pass)) {
            Write-Output "$domain\$user - AD Authentication Successful"
        } else {
            Write-Error "$domain\$user - AD Authentication Failed"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Test-ADAuthentication

Function Get-ADPrincipalGuid {
    <#
        .SYNOPSIS
        Get principal GUID details.

        .DESCRIPTION
        The Get-ADPrincipalGuid cmdlet retrieves the GUID details for an active directory user or group Active Directory domain

        .EXAMPLE
        Get-ADPrincipalGuid -domain sfo.rainpole.io -user svc-vsphere-ad -pass VMw@re1! -principal gg-sso-admin
        This example retrieves the details for th gg-sso-admin domain.

        .PARAMETER domain
        The Active Directory Domain name.

        .PARAMETER user
        The Active Directory Domain user account to bind to.

        .PARAMETER pass
        The Active Directory Domain user account password.

        .PARAMETER principal
        The Active Directory Domain user or group name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal
    )

    Try {
        $checkAdAuthentication = Test-ADAuthentication -user $user -pass $pass -server $domain -domain $domain
        if ($checkAdAuthentication -contains "2") {
            $securePassword = ConvertTo-SecureString -String $pass -AsPlainText -Force
            $creds = New-Object System.Management.Automation.PSCredential ($user, $securePassword)
            $nsxAdminGroupObject = (Get-ADGroup -Server $domain -Credential $creds -Filter { SamAccountName -eq $principal })
            $nsxAdminGroupObject
        } else {
            Write-Error "Domain User $user Authentication Failed"
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-ADPrincipalGuid

#EndRegion End Active Directory Functions ######
###################################################################################

###################################################################################
#Region Begin Cloud Foundation Functions ######

Function Get-vCenterServerDetail {
    <#
        .SYNOPSIS
        Get vCenter Server details from SDDC Manager.

        .DESCRIPTION
        The Get-vCenterServerDetail cmdlet retrieves the VM hostname, FQDN, root and vCenter Single Sign-On credentials
        of a vCenter Server for a given Workload Domain.

        .EXAMPLE
        Get-vCenterServerDetail -server sfo-vcf01.sfo.rainpole.io -user admin@local -pass VMw@re1!VMw@re1! -domainType MANAGEMENT
        This example retrieves the vCenter Server details for the Workload Domain with a type of MANAGEMENT

        .EXAMPLE
        Get-vCenterServerDetail -server sfo-vcf01.sfo.rainpole.io -user admin@local -pass VMw@re1!VMw@re1! -domain sfo-w01
        This example retrieves the vCenter Server details for the Workload Domain sfo-w01.

        .PARAMETER server
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER user
        The username to authenticate to the SDDC Manager.

        .PARAMETER pass
        The password to authenticate to the SDDC Manager.

        .PARAMETER domainType
        The Workload Domain type.

        .PARAMETER domain
        The name of the workload domain to run against.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$server,
        [Parameter (Mandatory = $false)] [String]$user,
        [Parameter (Mandatory = $false)] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateSet("MANAGEMENT", "VI")][String]$domainType,
        [Parameter (Mandatory = $false)] [String]$domain
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("user") -or (!$PsBoundParameters.ContainsKey("pass"))) {
            # Request Credentials
            $creds = Get-Credential
            $user = $creds.UserName.ToString()
            $pass = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("server")) {
            $server = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if ($PsBoundParameters.ContainsKey("domainType")) {
                    # Dynamically build vCenter Server details based on Workload Domain type
                    $vcfWorkloadDomainDetails = Get-VCFWorkloadDomain | Where-Object { $_.type -eq $domainType }
                }
                if ($PsBoundParameters.ContainsKey("domain")) {
                    # Dynamically build vCenter Server details based on Workload Domain name
                    $vcfWorkloadDomainDetails = Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }
                }
                if ($vcfWorkloadDomainDetails) {
                    #$vcfDetail = Get-VCFManager
                    $vcfDetail = Get-VCFRelease -domainId $vcfWorkloadDomainDetails.id
                    $vcenterServerDetails = Get-VCFvCenter | Where-Object { $_.id -eq $($vcfWorkloadDomainDetails.vcenters.id) }
                    $vcenterCredentialDetails = Get-VCFCredential | Where-Object { $_.resource.resourceId -eq $($vcenterServerDetails.id) }
                    if ( ($vcfDetail.version).Split("-")[0] -ge "4.5.0.0") {
                        $pscCredentialDetails = Get-VCFCredential | Where-Object { $_.resource.resourceType -eq "PSC" -and ($_.username).Split('@')[-1] -eq $vcfWorkloadDomainDetails.ssoName }
                        $ssoDomainName = $vcfWorkloadDomainDetails.ssoName
                    } else {
                        $pscCredentialDetails = Get-VCFCredential | Where-Object { $_.resource.resourceType -eq "PSC" }
                        $ssoDomainName = ((Get-VCFCredential | Where-Object { $_.resource.resourceType -eq "PSC" }).username).Split("@")[-1]
                    }
                    $vcenterServer = New-Object -TypeName psobject
                    $vcenterServer | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $vcenterServerDetails.fqdn
                    $vcenterServer | Add-Member -notepropertyname 'vmName' -notepropertyvalue $vcenterServerDetails.fqdn.Split(".")[0]
                    $vcenterServer | Add-Member -notepropertyname 'ssoDomain' -notepropertyvalue $ssoDomainName
                    
                    if ( ($vcfDetail.version).Split("-")[0] -ge "4.1.0.0") {
                        $vcenterServer | Add-Member -notepropertyname 'ssoAdmin' -notepropertyvalue ($pscCredentialDetails | Where-Object { ($_.credentialType -eq "SSO" -and $_.accountType -eq "SYSTEM") }).username
                        $vcenterServer | Add-Member -notepropertyname 'ssoAdminPass' -notepropertyvalue ($pscCredentialDetails | Where-Object { ($_.credentialType -eq "SSO" -and $_.accountType -eq "SYSTEM") }).password
                    } else {
                        $vcenterServer | Add-Member -notepropertyname 'ssoAdmin' -notepropertyvalue ($pscCredentialDetails | Where-Object { ($_.credentialType -eq "SSO" -and $_.accountType -eq "USER") }).username
                        $vcenterServer | Add-Member -notepropertyname 'ssoAdminPass' -notepropertyvalue ($pscCredentialDetails | Where-Object { ($_.credentialType -eq "SSO" -and $_.accountType -eq "USER") }).password
                    }
                    $vcenterServer | Add-Member -notepropertyname 'root' -notepropertyvalue ($vcenterCredentialDetails | Where-Object { ($_.credentialType -eq "SSH" -and $_.accountType -eq "USER") }).username
                    $vcenterServer | Add-Member -notepropertyname 'rootPass' -notepropertyvalue ($vcenterCredentialDetails | Where-Object { ($_.credentialType -eq "SSH" -and $_.accountType -eq "USER") }).password
                    $vcenterServer
                } else {
                    Write-Error "Unable to find Workload Domain type or domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vCenterServerDetail

Function Get-NsxtServerDetail {
    <#
        .SYNOPSIS
        Get NSX details from SDDC Manager.

        .DESCRIPTION
        The Get-NsxtServerDetail cmdlet retrieves the FQDN, root and admin credentials of NSX for a given
        Workload Domain.

        .EXAMPLE
        Get-NsxtServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1! -domainType MANAGEMENT
        This example retrieves the vCenter Server details for the Workload Domain with a type of MANAGEMENT

        .EXAMPLE
        Get-NsxtServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1! -domain sfo-w01
        This example retrieves the vCenter Server details for the Workload Domain sfo-w01.

        .PARAMETER fqdn
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER username
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.

        .PARAMETER domainType
        The Workload Domain type.

        .PARAMETER domain
        The name of the workload domain to run against.

        .PARAMETER listNodes
        List NSX nodes.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password,
        [Parameter (Mandatory = $false)] [String]$domain,
        [Parameter( Mandatory = $false)] [ValidateSet("MANAGEMENT", "VI")] [String]$domainType,
        [Parameter (Mandatory = $false)] [switch]$listNodes = $false
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $fqdn) {
            if (Test-VCFAuthentication -server $fqdn -user $username -pass $password) {
                if ($PsBoundParameters.ContainsKey("domainType")) {
                    # Dynamically build NSX details based on the Workload Domain type
                    $vcfWorkloadDomainDetails = Get-VCFWorkloadDomain | Where-Object { $_.type -eq $domainType }
                }
                if ($PsBoundParameters.ContainsKey("domain")) {
                    # Dynamically build NSX details based on the Workload Domain name
                    $vcfWorkloadDomainDetails = Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }
                }
                if ($vcfWorkloadDomainDetails) {
                    $nsxtServerDetails = Get-VCFNsxtcluster | Where-Object { $_.id -eq $($vcfWorkloadDomainDetails.nsxtCluster.id) }
                    $nsxtCreds = Get-VCFCredential | Where-Object { $_.resource.resourceId -eq $($nsxtServerDetails.id) }

                    $nsxtCluster = New-Object -TypeName PSCustomObject
                    $nsxtCluster | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $nsxtServerDetails.vipFqdn
                    $nsxtCluster | Add-Member -notepropertyname 'adminUser' -notepropertyvalue ($nsxtCreds | Where-Object { ($_.credentialType -eq "API" -and $_.accountType -eq "SYSTEM" -and $_.resource.domainName -eq $vcfWorkloadDomainDetails.name) }).username 
                    $nsxtCluster | Add-Member -notepropertyname 'adminPass' -notepropertyvalue ($nsxtCreds | Where-Object { ($_.credentialType -eq "API" -and $_.accountType -eq "SYSTEM" -and $_.resource.domainName -eq $vcfWorkloadDomainDetails.name) }).password
                    $nsxtCluster | Add-Member -notepropertyname 'rootUser' -notepropertyvalue ($nsxtCreds | Where-Object { ($_.credentialType -eq "SSH" -and $_.accountType -eq "SYSTEM" -and $_.resource.domainName -eq $vcfWorkloadDomainDetails.name) }).username
                    $nsxtCluster | Add-Member -notepropertyname 'rootPass' -notepropertyvalue ($nsxtCreds | Where-Object { ($_.credentialType -eq "SSH" -and $_.accountType -eq "SYSTEM" -and $_.resource.domainName -eq $vcfWorkloadDomainDetails.name) }).password
                    if ($listNodes) {
                        $nsxtCluster | Add-Member -notepropertyname 'nodes' -notepropertyvalue $nsxtServerDetails.nodes
                    }
                    $nsxtCluster
                } else {
                    Write-Error "Unable to find Workload Domain type or domain named ($domain) in the inventory of SDDC Manager ($fqdn): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-NsxtServerDetail

Function Get-vRSLCMServerDetail {
    <#
        .SYNOPSIS
        Get VMware Aria Suite Lifecycle details from SDDC Manager.

        .DESCRIPTION
        The Get-vRSLCMServerDetai cmdlet retrieves the FQDN, root and admin credentials of VMware Aria Suite Lifecycle
        Manager from SDDC Manager.

        .EXAMPLE
        Get-vRSLCMServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1!
        This example retrieves the VMware Aria Suite Lifecycle details from SDDC Manager.

        .PARAMETER fqdn
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER username
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $fqdn) {
            if (Test-VCFAuthentication -server $fqdn -user $username -pass $password) {
                if (Get-VCFvRSLCM) {
                    # Get VMware Aria Suite Lifecycle Details
                    $vRSLCMFQDN = Get-VCFvRSLCM
                    $vRSLCMCreds = Get-VCFCredential -resourceName $vRSLCMFQDN.fqdn
                    $vrslcmDetails = New-Object -TypeName PSCustomObject
                    $vrslcmDetails | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $vRSLCMFQDN.fqdn
                    $vrslcmDetails | Add-Member -notepropertyname 'hostname' -notepropertyvalue $vRSLCMFQDN.fqdn.Split('.')[0]
                    $vrslcmDetails | Add-Member -notepropertyname 'adminUser' -notepropertyvalue ($vRSLCMCreds | Where-Object { ($_.credentialType -eq "API" -and $_.accountType -eq "SYSTEM") }).username
                    $vrslcmDetails | Add-Member -notepropertyname 'adminPass' -notepropertyvalue ($vRSLCMCreds | Where-Object { ($_.credentialType -eq "API" -and $_.accountType -eq "SYSTEM") }).password
                    $vrslcmDetails | Add-Member -notepropertyname 'rootUser' -notepropertyvalue ($vRSLCMCreds | Where-Object { ($_.credentialType -eq "SSH" -and $_.accountType -eq "SYSTEM") }).username
                    $vrslcmDetails | Add-Member -notepropertyname 'rootPassword' -notepropertyvalue ($vRSLCMCreds | Where-Object { ($_.credentialType -eq "SSH" -and $_.accountType -eq "SYSTEM") }).password
                    $vrslcmDetails
                } else {
                    Write-Error "Unable to obtain VMware Aria Suite Lifecycle details from SDDC Manager ($fqdn), check deployment status: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vRSLCMServerDetail

Function Get-WSAServerDetail {
    <#
        .SYNOPSIS
        Get Workspace ONE Access details from SDDC Manager.

        .DESCRIPTION
        The Get-WSAServerDetail cmdlet retrieves the FQDN, Virtual IP and Node IP Addresses of Workspace ONE Access
        from SDDC Manager.

        .EXAMPLE
        Get-WSAServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1!
        This example retrieves the Workspace ONE Access details from SDDC Manager.

        .PARAMETER fqdn
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER username
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $fqdn) {
            if (Test-VCFAuthentication -server $fqdn -user $username -pass $password) {
                if (Get-VCFWSA) {
                    $vcfWsaDetails = Get-VCFWSA
                    $wsaCreds = Get-VCFCredential -resourceName $vcfWsaDetails.loadBalancerFqdn
                    $wsaDetails = New-Object -TypeName PSCustomObject
                    $wsaDetails | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $vcfWsaDetails.nodes.fqdn
                    $wsaDetails | Add-Member -notepropertyname 'loadBalancerIpAddress' -notepropertyvalue $vcfWsaDetails.loadBalancerIpAddress
                    $wsaDetails | Add-Member -notepropertyname 'loadBalancerFqdn' -notepropertyvalue $vcfWsaDetails.loadBalancerFqdn
                    $wsaDetails | Add-Member -notepropertyname 'nodeCount' -notepropertyvalue ($vcfWsaDetails).nodes.Count
                    $wsaDetails | Add-Member -notepropertyname 'node1IpAddress' -notepropertyvalue $vcfWsaDetails.nodes.ipAddress[0]
                    $wsaDetails | Add-Member -notepropertyname 'node2IpAddress' -notepropertyvalue $vcfWsaDetails.nodes.ipAddress[1]
                    $wsaDetails | Add-Member -notepropertyname 'node3IpAddress' -notepropertyvalue $vcfWsaDetails.nodes.ipAddress[2]
                    $wsaDetails | Add-Member -notepropertyname 'adminUser' -notepropertyvalue $wsaCreds.username
                    $wsaDetails | Add-Member -notepropertyname 'adminPass' -notepropertyvalue $wsaCreds.password
                    $wsaDetails
                } else {
                    Write-Error "Unable to obtain Workspace ONE Access details from SDDC Manager ($fqdn), check deployment status: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-WSAServerDetail

Function Get-vRAServerDetail {
    <#
        .SYNOPSIS
        Get VMware Aria Automation details from SDDC Manager.

        .DESCRIPTION
        The Get-vRAServerDetail cmdlet retrieves the FQDN, Virtual IP and Node IP Addresses of VMware Aria Automation
        from SDDC Manager.

        .EXAMPLE
        Get-vRAServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1!
        This example retrieves the VMware Aria Automation details from SDDC Manager.

        .PARAMETER fqdn
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER username
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $fqdn) {
            if (Test-VCFAuthentication -server $fqdn -user $username -pass $password) {
                if (Get-VCFvRA) {
                    $vcfVraDetails = Get-VCFvRA
                    $vraCreds = Get-VCFCredential -resourceName $vcfVraDetails.loadBalancerFqdn
                    $vraDetails = New-Object -TypeName PSCustomObject
                    $vraDetails | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $vcfVraDetails.nodes.fqdn
                    $vraDetails | Add-Member -notepropertyname 'loadBalancerIpAddress' -notepropertyvalue $vcfVraDetails.loadBalancerIpAddress
                    $vraDetails | Add-Member -notepropertyname 'loadBalancerFqdn' -notepropertyvalue $vcfVraDetails.loadBalancerFqdn
                    $vraDetails | Add-Member -notepropertyname 'node1IpAddress' -notepropertyvalue $vcfVraDetails.nodes.ipAddress[0]
                    $vraDetails | Add-Member -notepropertyname 'node2IpAddress' -notepropertyvalue $vcfVraDetails.nodes.ipAddress[1]
                    $vraDetails | Add-Member -notepropertyname 'node3IpAddress' -notepropertyvalue $vcfVraDetails.nodes.ipAddress[2]
                    $vraDetails
                } else {
                    Write-Error "Unable to obtain VMware Aria Automation details from SDDC Manager ($fqdn), check deployment status: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vRAServerDetail

Function Get-vROPsServerDetail {
    <#
        .SYNOPSIS
        Get VMware Aria Operations details from SDDC Manager.

        .DESCRIPTION
        The Get-vROPsServerDetail cmdlet retrieves the admin user, FQDN, Virtual IP and Node IP Addresses of
        VMware Aria Operations from SDDC Manager.

        .EXAMPLE
        Get-vROPsServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1!
        This example retrieves the VMware Aria Operations details from SDDC Manager.

        .PARAMETER fqdn
        The fully qualified domain name of the SDDC Manager.

        .PARAMETER username
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $fqdn) {
            if (Test-VCFAuthentication -server $fqdn -user $username -pass $password) {
                if (Get-VCFvROPS) {
                    $vcfVropsDetails = Get-VCFvROPs
                    $vropsCreds = Get-VCFCredential -resourceName $vcfVropsDetails.loadBalancerFqdn
                    $vropsDetails = New-Object -TypeName PSCustomObject
                    $vropsDetails | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $vcfVropsDetails.nodes.fqdn
                    $vropsDetails | Add-Member -notepropertyname 'loadBalancerIpAddress' -notepropertyvalue $vcfVropsDetails.loadBalancerIp
                    $vropsDetails | Add-Member -notepropertyname 'loadBalancerFqdn' -notepropertyvalue $vcfVropsDetails.loadBalancerFqdn
                    $vropsNode1FQDN = $vcfVropsDetails.nodes.fqdn[0]
                    $vropsNode1IP = [System.Net.Dns]::GetHostAddresses("$vropsNode1FQDN").IPAddressToString
                    $vropsDetails | Add-Member -notepropertyname 'node1IpAddress' -notepropertyvalue $vropsNode1IP
                    $vropsNode2FQDN = $vcfVropsDetails.nodes.fqdn[1]
                    $vropsNode2IP = [System.Net.Dns]::GetHostAddresses("$vropsNode2FQDN").IPAddressToString
                    $vropsDetails | Add-Member -notepropertyname 'node2IpAddress' -notepropertyvalue $vropsNode2IP
                    $vropsNode3FQDN = $vcfVropsDetails.nodes.fqdn[2]
                    $vropsNode3IP = [System.Net.Dns]::GetHostAddresses("$vropsNode3FQDN").IPAddressToString
                    $vropsDetails | Add-Member -notepropertyname 'node3IpAddress' -notepropertyvalue $vropsNode3IP
                    $vropsDetails | Add-Member -notepropertyname 'adminUser' -notepropertyvalue $vropsCreds.username
                    $vropsDetails | Add-Member -notepropertyname 'adminPass' -notepropertyvalue $vropsCreds.password
                    $vropsDetails
                } else {
                    Write-Error "Unable to obtain VMware Aria Operations details from SDDC Manager ($fqdn), check deployment status: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vROPsServerDetail

Function Get-vRLIServerDetail {
    <#
        .SYNOPSIS
        Get VMware Aria Operations for Logs details from SDDC Manager.

        .DESCRIPTION
        The Get-vRLIServerDetail cmdlet retrieves the admin user, FQDN, Virtual IP and Node IP Addresses of VMware
        Aria Operations for Logs from SDDC Manager.

        .EXAMPLE
        Get-vRLIServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1!
        This example retrieves the VMware Aria Operations for Logs details from SDDC Manager.

        .PARAMETER fqdn
        The vCenter Server FQDN.

        .PARAMETER username
        The username to authenticate to the SDDC Manager.

        .PARAMETER password
        The password to authenticate to the SDDC Manager.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "SDDC Manager access token not found. Please enter the SDDC Manager FQDN, e.g., sfo-vcf01.sfo.rainpole.io"
        }

        if (Test-VCFConnection -server $fqdn) {
            if (Test-VCFAuthentication -server $fqdn -user $username -pass $password) {
                if (Get-VCFvRLI) {
                    $vrliVcfDetail = Get-VCFvRLI
                    $vrliCreds = Get-VCFCredential -resourceName $vrliVcfDetail.loadBalancerFqdn
                    $vrliDetail = New-Object -TypeName PSCustomObject
                    $vrliDetail | Add-Member -notepropertyname 'fqdn' -notepropertyvalue $vrliVcfDetail.loadBalancerFqdn
                    $vrliDetail | Add-Member -notepropertyname 'loadBalancerIpAddress' -notepropertyvalue $vrliVcfDetail.loadBalancerIpAddress
                    $vrliDetail | Add-Member -notepropertyname 'node1IpAddress' -notepropertyvalue $vrliVcfDetail.nodes.ipAddress[0]
                    $vrliDetail | Add-Member -notepropertyname 'node2IpAddress' -notepropertyvalue $vrliVcfDetail.nodes.ipAddress[1]
                    $vrliDetail | Add-Member -notepropertyname 'node3IpAddress' -notepropertyvalue $vrliVcfDetail.nodes.ipAddress[2]
                    $vrliDetail | Add-Member -notepropertyname 'node1Fqdn' -notepropertyvalue $vrliVcfDetail.nodes.fqdn[0]
                    $vrliDetail | Add-Member -notepropertyname 'node2Fqdn' -notepropertyvalue $vrliVcfDetail.nodes.fqdn[1]
                    $vrliDetail | Add-Member -notepropertyname 'node3Fqdn' -notepropertyvalue $vrliVcfDetail.nodes.fqdn[2]
                    $vrliDetail | Add-Member -notepropertyname 'adminUser' -notepropertyvalue $vrliCreds.username
                    $vrliDetail | Add-Member -notepropertyname 'adminPass' -notepropertyvalue $vrliCreds.password
                    $vrliDetail
                } else {
                    Write-Error "Unable to obtain VMware Aria Operations for Logs details from SDDC Manager ($fqdn), check deployment status: PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vRLIServerDetail

Function Get-VCFDnsSearchDomain {
    <#
        .SYNOPSIS
        Get the search domains configured in an SDDC Manager appliance.

        .DESCRIPTION
        The Get-VCFDnsSearchDomain cmdlet gets the search domains configured in an SDDC Manager appliance

        .EXAMPLE
        Get-VCFDnsSearchDomain -sddcManagerVmName sfo-vcf01 -sddcManagerRootPass VMw@re1!
        This example gets all search domains configured in an SDDC Manager appliance.

        .PARAMETER sddcManagerVmName
        The SDDC Manager appliance name.

        .PARAMETER sddcManagerRootPass
        The root password to authenticate to SDDC Manager appliance..
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$sddcManagerVmName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$sddcManagerRootPass
    )

    Try {
        $scriptCommand = "cat /etc/resolv.conf"
        Try {
            $output = Invoke-VMScript -VM $sddcManagerVmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $sddcManagerRootPass -Server $vcfVcenterDetails.fqdn -ErrorAction Stop
        } Catch {
            if ($_.Exception -match "Failed to authenticate with the guest operating system") {
                $PSCmdlet.ThrowTerminatingError(
                    [System.Management.Automation.ErrorRecord]::new(
                        ([System.Security.Authentication.InvalidCredentialException]"Retrieving DNS search domains from SDDC Manager - invalid credentials: PRE_VALIDATION_FAILED"),
                        'Invoke-VMScript',
                        [System.Management.Automation.ErrorCategory]::AuthenticationError,
                        ""
                    )
                )
            } elseif ($_.Exception -match "Value cannot be found for the mandatory parameter VM" -or $_.Exception -match "Could not find VirtualMachine with name") {
                $PSCmdlet.ThrowTerminatingError(
                    [System.Management.Automation.ErrorRecord]::new(
                        ([System.Management.Automation.ItemNotFoundException]"Retrieving DNS search domains from SDDC Manager - invalid SDDC Manager appliance name: PRE_VALIDATION_FAILED"),
                        'Invoke-VMScript',
                        [System.Management.Automation.ErrorCategory]::InvalidArgument,
                        ""
                    )
                )
            }
        }
        $outputArray = ($output.Scriptoutput.Split("`r`n") | Where-Object {$_ -match "search" -and $_ -notmatch "search domains"}).Split(" ")
        $searchDomains = @()
        foreach ($item in $outputArray) {
            if ($item -notmatch "search") {
                $searchDomains += $item
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }

    if ($searchDomains) {
        return $searchDomains
    } else {
        Write-Error "Unable to locate any DNS search domains on ($sddcManagerVmName) : POST_VALIDATION_FAILED"
    }

}
Export-ModuleMember -Function Get-VCFDnsSearchDomain

#EndRegion End Cloud Foundation Functions ######
###################################################################################

###################################################################################
#Region Begin vSphere API Endpoint Functions ######

Function Request-vSphereApiToken {
    <#
        .SYNOPSIS
        Request an authentication token for the vSphere REST API.

        .DESCRIPTION
        The Request-vSphereApiToken cmdlet requests an authentication token for the vSphere REST API

        use -admin to set the Admin token for vCenter Server Management Interface
        .EXAMPLE
        Request-vSphereApiToken -Fqdn sfo-w01-vc01.sfo.rainpole.io -Username administrator@vsphere.local -Password VMw@re1!
        This example requests a vSphere REST API authentication token for user administrator@vsphere.local from vCenter Server sfo-w01-vc01.sfo.rainpole.io

        .EXAMPLE
        Get-vCenterServerDetail -Server sfo-vcf01.sfo.rainpole.io -User administrator@vsphere.local -Pass VMw@re1! -Domain sfo-w01 | Request-vSphereApiToken
        This example requests a vSphere REST API authentication token for user administrator@vsphere.local from the vCenter Server that manages VI workload domain sfo-w01.

        .PARAMETER Fqdn
        The vCenter Server FQDN.

        .PARAMETER Username
        The vCenter Server administrator username.

        .PARAMETER Password
        The vCenter Server administrator password.

        .PARAMETER Admin
        Use the Admin token for vCenter Server Management Interface.

        .PARAMETER InputObject
        The vCenter Server object.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$admin,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [ValidateNotNullOrEmpty()] [psobject]$inputObject
    )

    if ($inputObject) {
        $username = $inputObject.ssoAdmin
        $password = $inputObject.ssoAdminPass
        $fqdn = $inputObject.fqdn
        $sddcManager = (Get-VCFManager).fqdn
    } else {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "vCenter Server FQDN not found. Please enter a value, e.g., sfo-m01-vc01.sfo.rainpole.io"
        }
    }

    Try {
        $vcAuthHeaders = createvCenterAuthHeader($username, $password)
        $Global:vcApiServer = $fqdn
        $Global:vcApiAdminServer = $fqdn + ":5480"

        # Perform the vCenter REST API call to authenticate and retrieve the session token
        if ($PsBoundParameters.ContainsKey("admin")) {
            $uri = "https://$vcApiAdminServer/rest/com/vmware/cis/session"
            if ($PSEdition -eq 'Core') {
                $vcApiAdminSession = (Invoke-WebRequest -Method 'POST' -Uri $uri -Headers $vcAuthHeaders -UseBasicParsing -SkipCertificateCheck | ConvertFrom-Json).Value
            } else {
                $vcApiAdminSession = (Invoke-WebRequest -Method 'POST' -Uri $uri -Headers $vcAuthHeaders -UseBasicParsing | ConvertFrom-Json).Value
            }
        } else {
            $uri = "https://$vcApiServer/rest/com/vmware/cis/session"
            if ($PSEdition -eq 'Core') {
                $vcApiSession = (Invoke-WebRequest -Method 'POST' -URI $uri -Headers $vcAuthHeaders -UseBasicParsing -SkipCertificateCheck | ConvertFrom-Json).Value
            } else {
                $vcApiSession = (Invoke-WebRequest -Method 'POST' -URI $uri -Headers $vcAuthHeaders -UseBasicParsing | ConvertFrom-Json).Value
            }
        }

        # Use the session token to build the header used from here on
        $Global:vcApiHeaders = @{"vmware-api-session-id" = $vcApiSession }
        $vcApiHeaders.Add("Content-Type", "application/json")

        # Use the session token to build the header for admin interface used from here on
        if ($admin) {
            $Global:vcApiAdminHeaders = @{"vmware-api-session-id" = $vcApiAdminSession }
            $vcApiAdminHeaders.Add("Content-Type", "application/json")
        }

        # Validate credentials by executing an API call
        $newUri = "https://$vcApiServer/api/appliance/system/version"
        $oldUri = "https://$vcApiServer/rest/appliance/system/version"

        # Checking against the vCenter API
        # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        if ($PSEdition -eq 'Core') {
            Try {
                $response = Invoke-RestMethod -Method GET -Uri $newUri -Headers $vcApiHeaders -SkipCertificateCheck
                if ($response) {
                    $responseSplit = $response.version.Split(".")
                    $global:vCenterApi = $responseSplit[0..2] -join ""
                }
            } Catch {
                $errorStatus = $_.Exception.Response.StatusCode
            }
            if ($errorStatus -eq "NotFound") {
                $response = Invoke-RestMethod -Method GET -Uri $oldUri -Headers $vcApiHeaders -SkipCertificateCheck
                $responseSplit = $response.value.version.Split(".")
                $global:vCenterApi = $responseSplit[0..2] -join ""
            }
        } else {
            Try {
                $response = Invoke-RestMethod -Method GET -Uri $newUri -Headers $vcApiHeaders

                if ($response) {
                    $responseSplit = $response.version.Split(".")
                    $global:vCenterApi = $responseSplit[0..2] -join ""
                }
            } Catch {
                $errorStatus = $_.Exception.Response.StatusCode
            }
            if ($errorStatus -eq "NotFound") {
                $response = Invoke-RestMethod -Method GET -Uri $oldUri -Headers $vcApiHeaders
                $responseSplit = $response.value.version.Split(".")
                $global:vCenterApi = $responseSplit[0..2] -join ""
            }
        }
        if ($response) {
            if ($inputObject) {
                Write-Output "Successfully Requested New API Token for vCenter Server $vcApiServer via SDDC Manager $sddcManager"
            } else {
                Write-Output "Successfully Requested New API Token for vCenter Server $vcApiServer"
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-vSphereApiToken

Function Request-VcenterApiToken {
    <#
        .SYNOPSIS
        Request an authentication token for the vCenter Server REST API.

        .DESCRIPTION
        The Request-VcenterApiToken cmdlet requests an authentication token for the vCenter Server REST API

        .EXAMPLE
        Request-VcenterApiToken -fqdn sfo-m01-vc01.sfo.rainpole.io -username administrator@vsphere.local -password VMw@re1!
        This example requests a vCenter Server REST API authentication token for user administrator@vsphere.local from vCenter Server sfo-w01-vc01.sfo.rainpole.io.

        .PARAMETER fqdn
        The vCenter Server FQDN.

        .PARAMETER username
        The vCenter Server administrator username.

        .PARAMETER password
        The vCenter Server administrator password.

        .PARAMETER skipCertificateCheck
        Skip SSL certificate check.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$skipCertificateCheck
    )

    if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
        # Request Credentials
        $creds = Get-Credential
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }
    if (!$PsBoundParameters.ContainsKey("fqdn")) {
        $fqdn = Read-Host "vCenter Server FQDN not found. Please enter a value, e.g., sfo-m01-vc01.sfo.rainpole.io"
    }
    if ($PsBoundParameters.ContainsKey("skipCertificateCheck")) {
        if (-not("placeholder" -as [type])) {
            add-type -TypeDefinition @"
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public static class Placeholder {
    public static bool ReturnTrue(object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors) { return true; }

    public static RemoteCertificateValidationCallback GetDelegate() {
        return new RemoteCertificateValidationCallback(Placeholder.ReturnTrue);
    }
}
"@

        } 
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = [placeholder]::GetDelegate()
    }

    Try {
        Remove-Item variable:vcenterApiSession -Force -Confirm:$false -ErrorAction Ignore
        Remove-Item variable:vcenterApiHeaders -Force -Confirm:$false -ErrorAction Ignore
        Remove-Item variable:response -Force -Confirm:$false -ErrorAction Ignore
        Remove-Item variable:errorStatus -Force -Confirm:$false -ErrorAction Ignore
        $Global:vcenterAuthHeaders = createvCenterAuthHeader ($username, $password)
        $Global:vcenterApiServer = $fqdn

        Try {
            $uri = "https://$vcenterApiServer/api/session" # Perform the vCenter REST API call to authenticate and retrieve the session token
            if ($PSEdition -eq "Core") {
                $response = Invoke-WebRequest -Method 'POST' -Uri $uri -Headers $vcenterAuthHeaders -UseBasicParsing -SkipCertificateCheck
            } else {
                $response = Invoke-WebRequest -Method 'POST' -Uri $uri -Headers $vcenterAuthHeaders -UseBasicParsing
            }
        } Catch {
            $errorStatus = $_.Exception
        }
        if ($response.StatusCode -eq '201') {
            $vcenterApiSession = $response | ConvertFrom-Json
        } elseif ($response.StatusCode -eq '201') {
            $vcenterApiSession = ($response | ConvertFrom-Json).Value
        }
        if ($vcenterApiSession) {
            $Global:vcenterApiHeaders = @{"vmware-api-session-id" = $vcenterApiSession } # Use the session token to build the header used from here on
            $vcenterApiHeaders.Add("Content-Type", "application/json")
            Write-Output "Successfully Requested New API Session Token for vCenter Server: $vcenterApiServer"
        }
        if ($errorStatus -match "401") {
            Write-Warning "Unable to Obtain an API Session Token from vCenter Server: $vcenterApiServer (401 Unauthorized)"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-VcenterApiToken

Function Connect-vSphereMobServer {
    <#
        .SYNOPSIS
        Connect to the vSphere Managed Object Browser (MOB)
        
        .DESCRIPTION
        The Connect-vSphereMobServer cmdlet is used to connect to the vSphere Managed Object Browser (MOB)
        
        .EXAMPLE
        Connect-vSphereMobServer -server sfo-m01-vc01.sfo.rainpole.io -username administrator@vsphere.local -password VMw@re1!.

        .PARAMETER server
        The vCenter Server FQDN.

        .PARAMETER username
        The vCenter Server administrator username.

        .PARAMETER password
        The vCenter Server administrator password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $password
    )

    Try {
        $securePassword = ConvertTo-SecureString $password -AsPlainText -Force
        $credential = New-Object System.Management.Automation.PSCredential($username, $securePassword)
        $Global:DefaultMobServer = @{
            Server               = $server
            Credential           = $credential
            skipCertificateCheck = $true
        }
        $uri = "https://$($Global:DefaultMobServer.Server)/invsvc/mob3/?moid=authorizationService&" + "method=AuthorizationService.GetRoles"
        $params = @{
            Uri             = $uri
            SessionVariable = "mobSession"
            Credential      = $Global:DefaultMobServer.Credential
            Method          = "GET"
        }
        $response = Invoke-WebRequest @params -UseBasicParsing
        if ($response.StatusCode -eq 200) {
            $null = $response -match 'name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"'
            $Global:DefaultMobServer.SessionNonce = $matches[1]
            $Global:DefaultMobServer.WebSession = $mobSession
            Write-Output "Connected to vSphere MOB Server ($($Global:DefaultMobServer.Server))"
        } else {
            Throw "Failed to login to vSphere MOB Server ($($Global:DefaultMobServer.Server))"
        } 
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Connect-vSphereMobServer

Function Disconnect-vSphereMobServer {
    <#
        .SYNOPSIS
        Disconnects from the vSphere Managed Object Browser (MOB)
        
        .DESCRIPTION
        The Disconnect-vSphereMobServer cmdlet is used to disconnect from the vSphere Managed Object Browser (MOB)
        
        .EXAMPLE
        Disconnect-vSphereMobServer.
    #>


    Try {
        $uri = "https://$($Global:DefaultMobServer.Server)/invsvc/mob3/logout"
        $response = Invoke-WebRequest -Method GET -Uri $uri -WebSession $Global:DefaultMobServer.WebSession -UseBasicParsing
        $Global:DefaultMobServer.Server = $null
        $Global:DefaultMobServer.WebSession = $null
        $Global:DefaultMobServer.SessionOnce = $null
        if ($response.StatusCode -eq 200) {
            Write-Verbose "Disconnect from vSphere MOB Server ($($Global:DefaultMobServer.Server))"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Disconnect-vSphereMobServer

Function Get-VCVersion {
    <#
        .SYNOPSIS
        Get the version.

        .DESCRIPTION
        The Get-VCVersion cmdlet gets the version of the vCenter Server

        .EXAMPLE
        Get-VCVersion
        This example gets the version of the vCenter Server.
    #>


    Try {
        $uri = "https://$vcApiServer/api/appliance/system/version"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vcApiHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VCVersion

Function Get-VCConfigurationNTP {
    <#
        .SYNOPSIS
        Get NTP configuration.

        .DESCRIPTION
        The Get-VCConfigurationNTP cmdlet gets the NTP configuration of vCenter Server

        .EXAMPLE
        Get-VCConfigurationNTP
        This example gets the NTP configuration of the vCenter Server.
    #>


    Try {
        $uri = "https://$vcApiServer/api/appliance/ntp"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vcApiHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VCConfigurationNTP

Function Get-VCConfigurationDNS {
    <#
        .SYNOPSIS
        Get DNS configuration.

        .DESCRIPTION
        The Get-VCConfigurationDNS cmdlet gets the DNS configuration of vCenter Server

        .EXAMPLE
        Get-VCConfigurationDNS
        This example gets the DNS configuration of the vCenter Server.
    #>


    Try {
        $uri = "https://$vcApiServer/api/appliance/networking/dns/servers"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vcApiHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VCConfigurationDNS

Function Get-VcenterPasswordExpiration {
    <#
    .SYNOPSIS
        Retrieve the global password expiration policy.

        .DESCRIPTION
        The Get-VcenterPasswordExpiration cmdlet retrieves the global password expiration policy for local users of vCenter Server

        .EXAMPLE
        Get-VcenterPasswordExpiration
        This example retrieves the global password expiration policy of the vCenter Server.
    #>


    Try {
        $uri = "https://$vcApiServer/api/appliance/local-accounts/global-policy"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vcApiHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VcenterPasswordExpiration

Function Set-VcenterPasswordExpiration {
    <#
        .SYNOPSIS
        Configure the global password expiration policy.

        .DESCRIPTION
        The Set-VCPasswordPolicy cmdlet configures the global password expiration policy for the vCenter Server

        .EXAMPLE
        Set-VcenterPasswordExpiration -maxDays 999 -minDays 0 -warnDays 14
        This example configures the global password policy of the vCenter Server.

        .PARAMETER maxDays
        The maximum number of days before a password expires.

        .PARAMETER minDays
        The minimum number of days before a password expires.

        .PARAMETER warnDays
        The number of days before a password expires that a warning is issued.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$maxDays,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$minDays,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$warnDays
    )

    Try {
        if ($vcApiHeaders) {
            $uri = "https://$vcApiServer/api/appliance/local-accounts/global-policy"
            $body = '{ "max_days": ' + $maxDays + ', "min_days": ' + $minDays + ', "warn_days": ' + $warnDays + ' }'
            Invoke-RestMethod -Method PUT -Uri $uri -Headers $vcApiHeaders -Body $body
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-VcenterPasswordExpiration

Function Get-VcenterRootPasswordExpiration {
    <#
        .SYNOPSIS
        Retrieve the root user password expiration policy.

        .DESCRIPTION
        The Get-VcenterRootPasswordExpiration cmdlet retrieves the root user password expiration policy from vCenter Server

        .EXAMPLE
        Get-VcenterRootPasswordExpiration
        This example retrieves the root user password expiration policy from vCenter Server.
    #>


    Try {
        if ($vcApiHeaders) {
            $uri = "https://$vcApiServer/rest/appliance/local-accounts/root"
            (Invoke-RestMethod -Method GET -Uri $uri -Headers $vcApiHeaders).Value
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VcenterRootPasswordExpiration

Function Set-VcenterRootPasswordExpiration {
    <#
        .SYNOPSIS
        Set the vcenter password expiry date.

        .DESCRIPTION
        The Set-VcenterRootPasswordExpiration cmdlet configures password expiration settings for the vCenter Server root account

        .EXAMPLE
        Set-VcenterRootPasswordExpiration -email "admin@rainpole.io" -maxDays 999 -warnDays 14
        This example configures the configures password expiration settings for the vCenter Server root account

        .EXAMPLE
        Set-VcenterRootPasswordExpiration -neverexpire
        This example configures the configures password expiration settings for the vCenter Server root account to never expire.

        .PARAMETER email
        The email address to send password expiration notifications to.

        .PARAMETER maxDays
        The maximum number of days before a password expires.

        .PARAMETER warnDays
        The number of days before a password expires that a warning is issued.

        .PARAMETER neverexpire
        Set the password to never expire.
    #>


    Param (
        [Parameter (Mandatory = $false, ParameterSetName = 'expire')] [ValidateNotNullOrEmpty()] [String]$email,
        [Parameter (Mandatory = $false, ParameterSetName = 'expire')] [ValidateNotNullOrEmpty()] [String]$maxDays,
        [Parameter (Mandatory = $false, ParameterSetName = 'expire')] [ValidateNotNullOrEmpty()] [String]$warnDays,
        [Parameter (Mandatory = $false, ParameterSetName = 'neverexpire')] [ValidateNotNullOrEmpty()] [Switch]$neverexpire
    )

    Try {
        if ($PsBoundParameters.ContainsKey("neverexpire")) {
            $body = '{"config":{"password_expires": false}}'
        } else {
            
            $body = '{"config":{"password_expires": true, "email": "' + $email + '", "max_days_between_password_change": "' + $maxDays + '", "warn_days_before_password_expiration": "' + $warnDays + '"}}'
        }
        $uri = "https://$vcApiServer/rest/appliance/local-accounts/root"
        Invoke-RestMethod -Method PATCH -Uri $uri -Headers $vcApiHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-VcenterRootPasswordExpiration

Function Get-LocalUserPasswordExpiration {
    <#
        .SYNOPSIS
        Retrieve the password expiration policy for a local user.

        .DESCRIPTION
        The Get-LocalUserPasswordExpiration cmdlets retrieves the password expiration policy for a local user/

        .EXAMPLE
        Get-LocalUserPasswordExpiration -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1! -localUser root
        This example retrieves the password expiration policy for the root user on vCenter Server sfo-w01-vc01.

        .EXAMPLE
        Get-LocalUserPasswordExpiration -vmName sfo-w01-nsx01a -guestUser root -guestPassword VMw@re1!VMw@re1! -localUser admin
        This example retrieves the password expiration policy for the admin user on NSX Manager sfo-w01-nsx01a.

        .EXAMPLE
        Get-LocalUserPasswordExpiration -vmName sfo-vcf01 -guestUser root -guestPassword VMw@re1! -localUser vcf
        This example retrieves the password expiration policy for the vcf user on SDDC Manager sfo-vcf01.

        .EXAMPLE
        Get-LocalUserPasswordExpiration -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -localUser sshuser
        This example retrieves the password expiration policy for the sshuser user on Workspace ONE Access sfo-sfo01.

        .EXAMPLE
        Get-LocalUserPasswordExpiration -vmName xint-vrni01a -guestUser console -guestPassword VMw@re1! -localUser support -sudo
        This example retrieves the password expiration policy for the support user on VMware Aria Operations for Networks xint-vrni01a.

        .PARAMETER vmName
        The virtual machine name.

        .PARAMETER guestUser
        The guest user name.

        .PARAMETER guestPassword
        The guest user password.

        .PARAMETER localUser
        The local user name.

        .PARAMETER sudo
        Use sudo to run the command.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$localUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$sudo
    )

    Try {
        $passwordExpirationObject = New-Object System.Collections.ArrayList
        $scriptCommand = 'chage --list '
        $scriptCommand += "$localUser"
        if ($sudo) { $scriptCommand = 'sudo ' + $scriptCommand }
        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser $guestUser -GuestPassword $guestPassword
        $formatOutput = ($output.ScriptOutput -split '\r?\n').Trim()
        $formatOutput = $formatOutput -replace '(^\s+|\s+$)', '' -replace '\s+', ' '
        foreach ($line in $formatOutput) {
            $settingObject = New-Object -TypeName psobject
            $settingObject | Add-Member -notepropertyname "Setting" -notepropertyvalue ($line -Split (':').Trim())[-0]
            $settingObject | Add-Member -notepropertyname "Value" -notepropertyvalue ($line -Split (':').Trim())[-1]
            $passwordExpirationObject += $settingObject
        }
        Return $passwordExpirationObject
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-LocalUserPasswordExpiration

Function Set-LocalUserPasswordExpiration {
    <#
        .SYNOPSIS
        Configure the password expiration policy for a local user.

        .DESCRIPTION
        The Set-LocalUserPasswordExpiration cmdlets retrieves the password expiration policy for a local user.

        .EXAMPLE
        Set-LocalUserPasswordExpiration -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1! -localUser root -minDays 0 -maxDays 999 -warnDays 14
        This example configures the password expiration policy for the root user on vCenter Server sfo-w01-vc01.

        .EXAMPLE
        Set-LocalUserPasswordExpiration -vmName sfo-w01-nsx01a -guestUser root -guestPassword VMw@re1!VMw@re1! -localUser admin -minDays 0 -maxDays 999 -warnDays 14
        This example configures the password expiration policy for the admin user on NSX Manager sfo-w01-nsx01a.

        .EXAMPLE
        Set-LocalUserPasswordExpiration -vmName sfo-vcf01 -guestUser root -guestPassword VMw@re1! -localUser vcf -minDays 0 -maxDays 999 -warnDays 14
        This example configures the password expiration policy for the vcf user on SDDC Manager sfo-vcf01.

        .EXAMPLE
        Set-LocalUserPasswordExpiration -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -localUser sshuser -minDays 0 -maxDays 999 -warnDays 14
        This example configures the password expiration policy for the sshuser user on Workspace ONE Access sfo-wsa01.

        .EXAMPLE
        Set-LocalUserPasswordExpiration -vmName xint-vrni01a -guestUser console -guestPassword VMw@re1! -localUser support -minDays 0 -maxDays 999 -warnDays 14 -sudo
        This example configures the password expiration policy for the support user on VMware Aria Operations for Networks xint-vrni01a.

        .PARAMETER vmName
        The virtual machine name.

        .PARAMETER guestUser
        The guest user name.

        .PARAMETER guestPassword
        The guest user password.

        .PARAMETER localUser
        The local user name.

        .PARAMETER minDays
        The minimum number of days before a password expires.

        .PARAMETER maxDays
        The maximum number of days before a password expires.

        .PARAMETER warnDays
        The number of days before a password expires that a warning is issued.

        .PARAMETER sudo
        Use sudo to run the command.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$localUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$minDays,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$maxDays,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$warnDays,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$sudo
    )

    Try {
        $scriptCommand = "chage --maxdays $maxDays "
        if ($PsBoundParameters.ContainsKey("minDays")) {
            $minDaysCommand = "--mindays $minDays "
            $scriptCommand += $minDaysCommand
        }
        if ($PsBoundParameters.ContainsKey("minDays")) {
            $warnDaysCommand = "--warndays $warnDays "
            $scriptCommand += $warnDaysCommand
        }
        $scriptCommand += "$localUser"
        if ($sudo) { $scriptCommand = 'sudo ' + $scriptCommand }
        Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser $guestUser -GuestPassword $guestPassword | Out-Null
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-LocalUserPasswordExpiration

Function Get-LocalPasswordComplexity {
    <#
        .SYNOPSIS
        Get password complexity for local users.

        .DESCRIPTION
        The Get-LocalPasswordComplexity cmdlets retrieves the password complexity for local users

        .EXAMPLE
        Get-LocalPasswordComplexity -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1!
        This example retrieves the vCenter Server sfo-w01-vc01 password complexity

        .EXAMPLE
        Get-LocalPasswordComplexity -vmName sfo-w01-nsx01a -guestUser root -guestPassword VMw@re1!VMw@re1! -nsx
        This example retrieves the NSX Manager sfo-w01-nsx01a password complexity

        .EXAMPLE
        Get-LocalPasswordComplexity -vmName sfo-vcf01 -guestUser root -guestPassword VMw@re1!
        This example retrieves the SDDC Manager sfo-vcf01 password complexity

        .EXAMPLE
        Get-LocalPasswordComplexity -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1!
        This example retrieves the Workspace ONE Access sfo-wsa01 password complexity

        .EXAMPLE
        Get-LocalPasswordComplexity -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -drift -product wsaLocal -reportPath "F:\Reporting" -policyFile "passwordPolicyConfig.json"
        This example retrieves the Workspace ONE Access sfo-wsa01 password complexity and checks the configuration drift using the provided configuration JSON

        .EXAMPLE
        Get-LocalPasswordComplexity -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -drift -product wsaLocal
        This example retrieves the Workspace ONE Access sfo-wsa01 password complexity and compares the configuration against the product defaults.

        .PARAMETER vmName
        The virtual machine name.

        .PARAMETER guestUser
        The guest user name.

        .PARAMETER guestPassword
        The guest user password.

        .PARAMETER nsx
        The NSX Manager flag.

        .PARAMETER drift
        The configuration drift flag.

        .PARAMETER product
        The product name.

        .PARAMETER version
        The product version.

        .PARAMETER reportPath
        The report path.

        .PARAMETER policyFile
        The policy file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestPassword,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$nsx,
        [Parameter (Mandatory = $false, ParameterSetName = 'drift')] [ValidateSet('sddcManager', 'vcenterServerLocal', 'nsxManager', 'nsxEdge', 'wsaLocal')] [String]$product,
        [Parameter (Mandatory = $false, ParameterSetName = 'drift')] [ValidateNotNullOrEmpty()] [Switch]$drift,
        [Parameter (Mandatory = $false, ParameterSetName = 'drift')] [ValidateNotNullOrEmpty()] [String]$version,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$reportPath,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$policyFile
    )

    if ($PsBoundParameters.ContainsKey('drift')) { 
        if ($PsBoundParameters.ContainsKey('policyFile')) { 
            $command = "(Get-PasswordPolicyConfig -version $version -reportPath $reportPath -policyFile $policyFile).$product.passwordComplexity"
        } else {
            $command = "(Get-PasswordPolicyConfig -version $version).$product.passwordComplexity"
        }
        $requiredConfig = Invoke-Expression $command
    }

    Try {
        if ($PsBoundParameters.ContainsKey("nsx")) {
            $scriptCommand = "cat /etc/pam.d/common-password"
        } else {
            $scriptCommand = "cat /etc/pam.d/system-password"
        }
        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser $guestUser -GuestPassword $guestPassword -Confirm:$false
        if ([regex]::Matches($output.ScriptOutput, 'minlen=[-]?[0-9]+')) { $minLen = (([regex]::Matches($output.ScriptOutput, 'minlen=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'lcredit=[-]?[0-9]+')) { $minLowercase = (([regex]::Matches($output.ScriptOutput, 'lcredit=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'ucredit=[-]?[0-9]+')) { $minUppercase = (([regex]::Matches($output.ScriptOutput, 'ucredit=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'dcredit=[-]?[0-9]+')) { $minNumerical = (([regex]::Matches($output.ScriptOutput, 'dcredit=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'ocredit=[-]?[0-9]+')) { $minSpecial = (([regex]::Matches($output.ScriptOutput, 'ocredit=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'minclass=[-]?[0-9]+')) { $minClass = (([regex]::Matches($output.ScriptOutput, 'minclass=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'difok=[-]?[0-9]+')) { $minUnique = (([regex]::Matches($output.ScriptOutput, 'difok=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'maxsequence=[-]?[0-9]+')) { $maxSequence = (([regex]::Matches($output.ScriptOutput, 'maxsequence=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'remember=[-]?[0-9]+')) { $history = (([regex]::Matches($output.ScriptOutput, 'remember=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'retry=[-]?[0-9]+')) { $retry = (([regex]::Matches($output.ScriptOutput, 'retry=[-]?[0-9]+').Value) -Split ('='))[-1] }

        $passwordComplexityObject = New-Object -TypeName psobject
        $passwordComplexityObject | Add-Member -notepropertyname "System" -notepropertyvalue $vmName
        if ($minLen) { $passwordComplexityObject | Add-Member -notepropertyname "Min Length" -notepropertyvalue $(if ($drift) { if ($minLen -ne $requiredConfig.minLength) { "$($minLen) [ $($requiredConfig.minLength) ]" } else { "$($minLen)" } } else { "$($minLen)" }) }
        if ($minLowercase) { $passwordComplexityObject | Add-Member -notepropertyname "Min Lowercase" -notepropertyvalue $(if ($drift) { if ($minLowercase -ne $requiredConfig.minLowercase) { "$($minLowercase) [ $($requiredConfig.minLowercase) ]" } else { "$($minLowercase)" } } else { "$($minLowercase)" }) }
        if ($minUppercase) { $passwordComplexityObject | Add-Member -notepropertyname "Min Uppercase" -notepropertyvalue $(if ($drift) { if ($minUppercase -ne $requiredConfig.minUppercase) { "$($minUppercase) [ $($requiredConfig.minUppercase) ]" } else { "$($minUppercase)" } } else { "$($minUppercase)" }) }
        if ($minNumerical) { $passwordComplexityObject | Add-Member -notepropertyname "Min Numerical" -notepropertyvalue $(if ($drift) { if ($minNumerical -ne $requiredConfig.minNumerical) { "$($minNumerical) [ $($requiredConfig.minNumerical) ]" } else { "$($minNumerical)" } } else { "$($minNumerical)" }) }
        if ($minSpecial) { $passwordComplexityObject | Add-Member -notepropertyname "Min Special" -notepropertyvalue $(if ($drift) { if ($minSpecial -ne $requiredConfig.minSpecial) { "$($minSpecial) [ $($requiredConfig.minSpecial) ]" } else { "$($minSpecial)" } } else { "$($minSpecial)" }) }
        if ($minUnique) { $passwordComplexityObject | Add-Member -notepropertyname "Min Unique" -notepropertyvalue $(if ($drift) { if ($minUnique -ne $requiredConfig.minUnique) { "$($minUnique) [ $($requiredConfig.minUnique) ]" } else { "$($minUnique)" } } else { "$($minUnique)" }) }
        if ($minClass) { $passwordComplexityObject | Add-Member -notepropertyname "Min Classes" -notepropertyvalue $(if ($drift) { if ($minClass -ne $requiredConfig.minClass) { "$($minClass) [ $($requiredConfig.minClass) ]" } else { "$($minClass)" } } else { "$($minClass)" }) }
        if ($maxSequence) { $passwordComplexityObject | Add-Member -notepropertyname "Max Sequence" -notepropertyvalue $(if ($drift) { if ($maxSequence -ne $requiredConfig.maxSequence) { "$($maxSequence) [ $($requiredConfig.maxSequence) ]" } else { "$($maxSequence)" } } else { "$($maxSequence)" }) }
        if ($history) { $passwordComplexityObject | Add-Member -notepropertyname "History" -notepropertyvalue $(if ($drift) { if ($history -ne $requiredConfig.history) { "$($history) [ $($requiredConfig.history) ]" } else { "$($history)" } } else { "$($history)" }) }
        if ($retry) { $passwordComplexityObject | Add-Member -notepropertyname "Max Retries" -notepropertyvalue $(if ($drift) { if ($retry -ne $requiredConfig.retries) { "$($retry) [ $($requiredConfig.retries) ]" } else { "$($retry)" } } else { "$($retry)" }) }
        Return $passwordComplexityObject
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-LocalPasswordComplexity

Function Set-LocalPasswordComplexity {
    <#
        .SYNOPSIS
        Configure password complexity for local users.

        .DESCRIPTION
        The Set-LocalPasswordComplexity cmdlets configures the password complexity local users

        .EXAMPLE
        Set-LocalPasswordComplexity -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1! -minLength 7 -uppercase 1 -lowercase 1 -numerical 1 -special 1 -unique 5 -history 3
        This example updates the vCenter Server sfo-w01-vc01 with new values for each element

        .EXAMPLE
        Set-LocalPasswordComplexity -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1! -minLength 6 -uppercase "-1" -lowercase "-1" -numerical "-1" -special "-1" -unique 4 -history 5
        This example updates the vCenter Server sfo-w01-vc01 with the default values

        .EXAMPLE
        Set-LocalPasswordComplexity -vmName sfo-w01-nsx01a -guestUser root -guestPassword VMw@re1!VMw@re1! -nsx -minLength 15 -uppercase "-1" -lowercase "-1" -numerical "-1" -special "-1" -unique 0 -history 5
        This example updates the NSX Manager sfo-w01-nsx01a with the values.

        .PARAMETER vmName
        The virtual machine name.

        .PARAMETER guestUser
        The guest user name.

        .PARAMETER guestPassword
        The guest user password.

        .PARAMETER minLength
        The minimum number of characters in a password.

        .PARAMETER uppercase
        The maximum number of uppercase characters in a password.

        .PARAMETER lowercase
        The maximum number of lowercase characters in a password.

        .PARAMETER numerical
        The maximum number of numerical characters in a password.

        .PARAMETER special
        The maximum number of special characters in a password.

        .PARAMETER unique
        The minimum number of unique characters in a password.

        .PARAMETER history
        The number of passwords to remember.

        .PARAMETER retry
        The number of retries.

        .PARAMETER class
        The minimum number of character classes.

        .PARAMETER sequence
        The maximum number of repeated characters.

        .PARAMETER nsx
        The NSX Manager flag.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$minLength,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$uppercase,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$lowercase,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$numerical,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$special,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$unique,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$history,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$retry,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$class,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$sequence,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$nsx
    )

    Try {
        $scriptCommand = "sed -E -i.bak '"
        if ($PsBoundParameters.ContainsKey("minLength")) {
            # minlen = Minimum password length (default = 6)
            $minLengthCommand = "s/minlen=[-]?[0-9]+/minlen=$minLength/"
            $scriptCommand += $minLengthCommand
        }
        if ($PsBoundParameters.ContainsKey("uppercase")) {
            # ucredit = Maximum number of uppercase characters that will generate a credit (default = -1)
            $uppercaseCommand = ";s/ucredit=[-]?[0-9]+/ucredit=$uppercase/"
            $scriptCommand += $uppercaseCommand
        }
        if ($PsBoundParameters.ContainsKey("lowercase")) {
            # lcredit = Maximum number of lowercase characters that will generate a credit (default = -1)
            $lowercaseCommand = ";s/lcredit=[-]?[0-9]+/lcredit=$lowercase/"
            $scriptCommand += $lowercaseCommand
        }
        if ($PsBoundParameters.ContainsKey("numerical")) {
            # dcredit = Maximum number of digits that will generate a credit (default = -1)
            $numericalCommand = ";s/dcredit=[-]?[0-9]+/dcredit=$numerical/"
            $scriptCommand += $numericalCommand
        }
        if ($PsBoundParameters.ContainsKey("special")) {
            # ocredit = Maximum number of other characters that will generate a credit (default = -1)
            $specialCommand = ";s/ocredit=[-]?[0-9]+/ocredit=$special/"
            $scriptCommand += $specialCommand
        }
        if ($PsBoundParameters.ContainsKey("unique")) {
            # difok = Minimum number of characters that must be different from the old password (default = 4)
            $uniqueCommand = ";s/difok=[-]?[0-9]+/difok=$unique/"
            $scriptCommand += $uniqueCommand
        }
        if ($PsBoundParameters.ContainsKey("history")) {
            # remember = Maximum number of passwords the system remembers (default = 5)
            $historyCommand = ";s/remember=[-]?[0-9]+/remember=$history/"
            $scriptCommand += $historyCommand
        }
        if ($PsBoundParameters.ContainsKey("retry")) {
            # retry = Maximum number of retries (default = 3)
            $retryCommand = ";s/retry=[-]?[0-9]+/retry=$retry/"
            $scriptCommand += $retryCommand
        }
        if ($PsBoundParameters.ContainsKey("class")) {
            # minclass = Minimum number of character types that must be used (i.e., uppercase, lowercase, digits, other) (default = 4)
            $minClassCommand = ";s/minclass=[-]?[0-9]+/minclass=$class/"
            $scriptCommand += $minClassCommand
        }
        if ($PsBoundParameters.ContainsKey("sequence")) {
            # maxsequence = Maximum number of times a single character may be repeated (default = 0)
            $maxSequenceCommand = ";s/maxsequence=[-]?[0-9]+/maxsequence=$sequence/"
            $scriptCommand += $maxSequenceCommand
        }
        if ($PsBoundParameters.ContainsKey("nsx")) {
            $scriptCommand += "' /etc/pam.d/common-password"
        } else {
            $scriptCommand += "' /etc/pam.d/system-password"
        }
        Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser $guestUser -GuestPassword $guestPassword -Confirm:$false | Out-Null
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-LocalPasswordComplexity

Function Get-LocalAccountLockout {
    <#
        .SYNOPSIS
        Get account lockout policy for local users.

        .DESCRIPTION
        The Get-LocalAccountLockout cmdlets retrieves the account lockout for local users

        .EXAMPLE
        Get-LocalAccountLockout -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1! -product vcenterServerLocal
        This example retrieves the vCenter Server sfo-w01-vc01 account lockout policy

        .EXAMPLE
        Get-LocalAccountLockout -vmName sfo-vcf01 -guestUser root -guestPassword VMw@re1! -product sddcManager
        This example retrieves the SDDC Manager sfo-vcf01 account lockout policy

        .EXAMPLE
        Get-LocalAccountLockout -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -product wsaLocal
        This example retrieves the Workspace ONE Access sfo-wsa01 account lockout policy

        .EXAMPLE
        Get-LocalAccountLockout -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -product wsaLocal -drift -reportPath "F:\Reporting" -policyFile "passwordPolicyConfig.json"
        This example retrieves the Workspace ONE Access sfo-wsa01 account lockout policy and checks the configuration drift using the provided configuration JSON

        Get-LocalAccountLockout -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -product wsaLocal -drift
        This example retrieves the Workspace ONE Access sfo-wsa01 account lockout policy and compares the configuration against the product defaults.

        .PARAMETER vmName
        The virtual machine name.

        .PARAMETER guestUser
        The guest user name.

        .PARAMETER guestPassword
        The guest user password.

        .PARAMETER product
        The product name.

        .PARAMETER drift
        The configuration drift flag.

        .PARAMETER version
        The product version.

        .PARAMETER reportPath
        The report path.

        .PARAMETER policyFile
        The policy file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestPassword,
        [Parameter (Mandatory = $true)] [ValidateSet('sddcManager', 'vcenterServerLocal', 'nsxManager', 'nsxEdge', 'wsaLocal')] [String]$product,
        [Parameter (Mandatory = $false, ParameterSetName = 'drift')] [ValidateNotNullOrEmpty()] [Switch]$drift,
        [Parameter (Mandatory = $false, ParameterSetName = 'drift')] [ValidateNotNullOrEmpty()] [String]$version,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$reportPath,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$policyFile
    )

    if ($PsBoundParameters.ContainsKey('drift')) { 
        if ($PsBoundParameters.ContainsKey('policyFile')) { 
            $command = "(Get-PasswordPolicyConfig -version $version -reportPath $reportPath -policyFile $policyFile).$product.accountLockout"
        } else {
            $command = "(Get-PasswordPolicyConfig -version $version).$product.accountLockout"
        }
        $requiredConfig = Invoke-Expression $command
    }

    Try {

        $scriptCommand = "cat /etc/pam.d/system-auth"
        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser $guestUser -GuestPassword $guestPassword -Confirm:$false
        if ([regex]::Matches($output.ScriptOutput, 'deny=[-]?[0-9]+')) { $failures = (([regex]::Matches($output.ScriptOutput, 'deny=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, ' unlock_time=[-]?[0-9]+')) { $unlockInterval = (([regex]::Matches($output.ScriptOutput, ' unlock_time=[-]?[0-9]+').Value) -Split ('='))[-1] }
        if ([regex]::Matches($output.ScriptOutput, 'root_unlock_time=[-]?[0-9]+')) { $rootUnlockInterval = (([regex]::Matches($output.ScriptOutput, 'root_unlock_time=[-]?[0-9]+').Value) -Split ('='))[-1] }
        $accountLockoutObject = New-Object -TypeName psobject
        $accountLockoutObject | Add-Member -notepropertyname "System" -notepropertyvalue $vmName
        if ($failures) {$accountLockoutObject | Add-Member -notepropertyname "Max Failures" -notepropertyvalue $(if ($drift) { if ($failures -ne $requiredConfig.maxFailures) { "$($failures) [ $($requiredConfig.maxFailures) ]" } else { "$($failures)" }} else { "$($failures)" })}
        if ($unlockInterval) {$accountLockoutObject | Add-Member -notepropertyname "Unlock Interval (sec)" -notepropertyvalue $(if ($drift) { if ($unlockInterval -ne $requiredConfig.unlockInterval) { "$($unlockInterval) [ $($requiredConfig.unlockInterval) ]" } else { "$($unlockInterval)" }} else { "$($unlockInterval)" })}
        if ($rootUnlockInterval) {$accountLockoutObject | Add-Member -notepropertyname "Root Unlock Interval (sec)" -notepropertyvalue $(if ($drift) { if ($rootUnlockInterval -ne $requiredConfig.rootUnlockInterval) { "$($rootUnlockInterval) [ $($requiredConfig.rootUnlockInterval) ]" } else { "$($rootUnlockInterval)" }} else { "$($rootUnlockInterval)" })}
        Return $accountLockoutObject
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-LocalAccountLockout

Function Set-LocalAccountLockout {
    <#
        .SYNOPSIS
        Configure account lockoput for local users.

        .DESCRIPTION
        The Set-LocalAccountLockout cmdlets configures the account lockout policy local users

        .EXAMPLE
        Set-LocalAccountLockout -vmName sfo-w01-vc01 -guestUser root -guestPassword VMw@re1! -failures 3 -unlockInterval 900 -rootUnlockInterval 300
        This example updates the account lockout policy for vCenter Server

        .EXAMPLE
        Set-LocalAccountLockout -vmName sfo-vcf01 -guestUser root -guestPassword VMw@re1! -failures 3 -unlockInterval 86400 -rootUnlockInterval 300
        This example updates the account lockout policy for SDDC Manager

        .EXAMPLE
        Set-LocalAccountLockout -vmName sfo-wsa01 -guestUser root -guestPassword VMw@re1! -failures 3 -unlockInterval 900 -rootUnlockInterval 900
        This example updates the account lockout policy for Workspace ONE Access.

        .PARAMETER vmName
        The virtual machine name.

        .PARAMETER guestUser
        The guest user name.

        .PARAMETER guestPassword
        The guest user password.

        .PARAMETER failures
        The maximum number of login failures.

        .PARAMETER unlockInterval
        The unlock interval in seconds.

        .PARAMETER rootUnlockInterval
        The root unlock interval in seconds.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$guestPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$failures,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$unlockInterval,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$rootUnlockInterval
    )

    Try {
        $scriptCommand = "sed -E -i.bak '"
        if ($PsBoundParameters.ContainsKey("failures")) {
            $failureCommand = "s/deny=[-]?[0-9]+/deny=$failures/"
            $scriptCommand += $failureCommand
        }
        if ($PsBoundParameters.ContainsKey("unlockInterval")) {
            $unlockIntervalCommand = ";s/ unlock_time=[-]?[0-9]+/ unlock_time=$unlockInterval/"
            $scriptCommand += $unlockIntervalCommand
        }
        if ($PsBoundParameters.ContainsKey("rootUnlockInterval")) {
            $rootUnlockIntervalCommand = ";s/root_unlock_time=[-]?[0-9]+/root_unlock_time=$rootUnlockInterval/"
            $scriptCommand += $rootUnlockIntervalCommand
        }

        $scriptCommand += "' /etc/pam.d/system-auth"
        Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser $guestUser -GuestPassword $guestPassword -Confirm:$false | Out-Null
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-LocalAccountLockout

Function Get-GlobalPermission {
    <#
        .SYNOPSIS
        Get vSphere Global Permission.

        .DESCRIPTION
        The Get-GlobalPermission cmdlet gets a list of vSphere Global Permission

        .EXAMPLE
        Get-GlobalPermission
        This example shows how to gets a list of vSphere Global Permission.
    #>


    Try {
        $uri = "https://$($Global:DefaultMobServer.Server)/invsvc/mob3/?moid=authorizationService&" + "method=AuthorizationService.GetGlobalAccessControlList"
        $body = "vmware-session-nonce=$($Global:DefaultMobServer.SessionNonce)"
        $params = @{
            Uri             = $uri
            WebSession      = $Global:DefaultMobServer.WebSession
            Credential      = $Global:DefaultMobServer.Credential
            Method          = "POST"
            Body            = $body
            UseBasicParsing = $true
        }
        $response = Invoke-WebRequest @params
        $vsphereRoles = Get-VIRole | Select-Object Name, @{N = "Id"; E = { @($_.Id) } } # Gather vSphere Roles and their Id
        $roleLookup = @{}
        foreach ($role in $vsphereRoles) {
            $roleLookup."$($role.Id)" = $role.Name
        }
        # Extract the data from the parsed HTML
        $html = New-Object -Com "HTMLFile"
        [string]$htmlBody = $response.Content
        $html.write([ref]$htmlBody)
        $table = $html.getElementsByTagName("table")[3]
        $td = $table.getElementsByTagName("tr")[4].getElementsByTagName("td")[2]
        $li = $td.getElementsByTagName("ul")[0].getElementsByTagName("li")
            
        foreach ($item in $li) {
            if ($item.innerHTML.StartsWith("<TABLE")) {
                $principalTable = $item.getElementsByTagName("tr")[3].getElementsByTagName("td")[2].getElementsByTagName("table")[0]
                $principal = $principalTable.getElementsByTagName("tr")[4].getElementsByTagName("td")[2].innerText
                $isGroup = $principalTable.getElementsByTagName("tr")[3].getElementsByTagName("td")[2].innerText
                $type = Switch ($isGroup) {
                    $true {"group"}
                    $false {"user"}
                }
                $role = $item.getElementsByTagName("tr")[10].getElementsByTagName("li")[0].innerText
                $propagate = $item.getElementsByTagName("tr")[9].getElementsByTagName("td")[2].innerText
    
                [PSCustomObject] @{
                    Principal = $principal
                    Type      = $type
                    Role      = $RoleLookup.$($Role)
                    Propagate = $propagate
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-GlobalPermission

Function Add-GlobalPermission {
    <#
        .SYNOPSIS
        Add a vSphere Global Permission.

        .DESCRIPTION
        The Add-GlobalPermission cmdlet adds a new user or group a vSphere Global Permission

        .EXAMPLE
        Add-GlobalPermission -principal gg-vc-admins -roleId -1 -propagate true -type group
        This example shows how to add the Administrator global permission to a group called svc-vc-admins.

        .PARAMETER principal
        The user or group name.

        .PARAMETER roleId
        The vSphere Role Id.

        .PARAMETER propagate
        The propagate flag.

        .PARAMETER type
        The user or group type.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$roleId,
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [String]$propagate,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type
    )

    Try {
        $userEscaped = [uri]::EscapeUriString($principal) # Escape username
        $uri = "https://$($Global:DefaultMobServer.Server)/invsvc/mob3/?moid=authorizationService&" + "method=AuthorizationService.AddGlobalAccessControlList" # vSphere MOB URL to private enableMethods
        # The POST data payload must include the vmware-session-nonce variable + URL-encoded
        if ($type -eq "group") {
            $body = "vmware-session-nonce=$($Global:DefaultMobServer.SessionNonce)&permissions=%3Cpermissions%3E%0D%0A+++%3Cprincipal%3E%0D%0A++++++%3Cname%3E$userEscaped%3C%2Fname%3E%0D%0A++++++%3Cgroup%3Etrue%3C%2Fgroup%3E%0D%0A+++%3C%2Fprincipal%3E%0D%0A+++%3Croles%3E$roleId%3C%2Froles%3E%0D%0A+++%3Cpropagate%3E$propagate%3C%2Fpropagate%3E%0D%0A%3C%2Fpermissions%3E"
        } else {
            $body = "vmware-session-nonce=$($Global:DefaultMobServer.SessionNonce)&permissions=%3Cpermissions%3E%0D%0A+++%3Cprincipal%3E%0D%0A++++++%3Cname%3E$userEscaped%3C%2Fname%3E%0D%0A++++++%3Cgroup%3Efalse%3C%2Fgroup%3E%0D%0A+++%3C%2Fprincipal%3E%0D%0A+++%3Croles%3E$roleId%3C%2Froles%3E%0D%0A+++%3Cpropagate%3E$propagate%3C%2Fpropagate%3E%0D%0A%3C%2Fpermissions%3E"
        }
        $params = @{
            Uri             = $uri
            WebSession      = $Global:DefaultMobServer.WebSession
            Credential      = $Global:DefaultMobServer.Credential
            Method          = "POST"
            Body            = $body
            UseBasicParsing = $true
        }
        $response = Invoke-WebRequest @params
        if ($response.StatusCode -eq 200) {
            Write-Verbose "Successfully added vCenter Global Permission for ($principal)"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-GlobalPermission

Function Remove-GlobalPermission {
    <#
        .SYNOPSIS
        Remove a vSphere Global Permission.

        .DESCRIPTION
        The Remove-GlobalPermission cmdlet removes a user or group from a vSphere Global Permission

        .EXAMPLE
        Remove-GlobalPermission -principal gg-vc-admins -type group
        This example shows how to remove the Administrator global permission from the group called svc-vc-admins.

        .PARAMETER principal
        The user or group name.

        .PARAMETER type
        The user or group type.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("group", "user")] [String]$type
    )

    Try {
        $userEscaped = [uri]::EscapeUriString($principal) # Escape username
        $uri = "https://$($Global:DefaultMobServer.Server)/invsvc/mob3/?moid=authorizationService&" + "method=AuthorizationService.RemoveGlobalAccess"
        if ($type -eq "group") {
            $body = "vmware-session-nonce=$($Global:DefaultMobServer.SessionNonce)&principals=%3Cprincipals%3E%0D%0A+++%3Cname%3E$userEscaped%3C%2Fname%3E%0D%0A+++%3Cgroup%3Etrue%3C%2Fgroup%3E%0D%0A%3C%2Fprincipals%3E"
        } else {
            $body = "vmware-session-nonce=$($Global:DefaultMobServer.SessionNonce)&principals=%3Cprincipals%3E%0D%0A+++%3Cname%3E$userEscaped%3C%2Fname%3E%0D%0A+++%3Cgroup%3Efalse%3C%2Fgroup%3E%0D%0A%3C%2Fprincipals%3E"
        }     
        $params = @{
            Uri             = $uri
            WebSession      = $Global:DefaultMobServer.WebSession
            Credential      = $Global:DefaultMobServer.Credential
            Method          = "POST"
            Body            = $body
            UseBasicParsing = $true
        }
        $response = Invoke-WebRequest @params
        if ($response.StatusCode -eq 200) {
            Write-Verbose "Successfully removed vCenter Gobal Permission for ($principal)"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-GlobalPermission

Function Add-DrsVmToVmGroup {
    <#
        .SYNOPSIS
        Creates a vSphere VM to VM Group.

        .DESCRIPTION
        The Add-DrsVmToVmGroup cmdlet creates a vSphere VM to VM Group

        .EXAMPLE
        Add-DrsVmToVmGroup -name vm-vm-rule-wsa-vra -vmGroup sfo-m01-vm-group-wsa -dependOnVmGroup sfo-m01-vm-group-vra -Enabled -cluster sfo-m01-cl01
        This example shows how to create a vSphere VM to VM group in the vCenter Server.

        .PARAMETER name
        The name of the VM to VM group.

        .PARAMETER vmGroup
        The name of the VM group.

        .PARAMETER dependOnVmGroup
        The name of the VM group to depend on.

        .PARAMETER cluster
        The name of the cluster.

        .PARAMETER enabled
        The enabled flag.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmGroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$dependOnVmGroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$enabled=$true
    )

    Try {
        $updateCluster = Get-Cluster | Where-Object {$_.Name -eq $cluster}
        $spec = New-Object VMware.Vim.ClusterConfigSpecEx
        $spec.RulesSpec = New-Object VMware.Vim.ClusterRuleSpec[] (1)
        $spec.RulesSpec[0] = New-Object VMware.Vim.ClusterRuleSpec
        $spec.RulesSpec[0].Operation = 'add'
        $spec.RulesSpec[0].Info = New-Object VMware.Vim.ClusterDependencyRuleInfo
        $spec.RulesSpec[0].Info.DependsOnVmGroup = $dependOnVmGroup
        $spec.RulesSpec[0].Info.VmGroup = $vmGroup
        $spec.RulesSpec[0].Info.Name = $name
        $spec.RulesSpec[0].Info.UserCreated = $true
        $spec.RulesSpec[0].Info.Enabled = $true

        $ClusterToReconfig = Get-View -Id $updateCluster.ExtensionData.MoRef
        $ClusterToReconfig.ReconfigureComputeResource_Task($spec, $true)
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-DrsVmToVmGroup

Function Remove-DrsVmToVmGroup {
    <#
        .SYNOPSIS
        Remove a vSphere VM to VM Group.

        .DESCRIPTION
        The Remove-DrsVmToVmGroup cmdlet removes a vSphere VM to VM Group

        .EXAMPLE
        Remove-DrsVmToVmGroup -name vm-vm-rule-wsa-vrli -cluster sfo-m01-cl01
        This example shows how to remove a vSphere VM to VM group from vCenter Server.

        .PARAMETER name
        The name of the VM to VM group.

        .PARAMETER cluster
        The name of the cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster
    )

    Try {
        $updateCluster = Get-Cluster | Where-Object {$_.Name -eq $cluster}
        $spec = New-Object VMware.Vim.ClusterConfigSpecEx
        $spec.RulesSpec = New-Object VMware.Vim.ClusterRuleSpec[] (1)
        $spec.RulesSpec[0] = New-Object VMware.Vim.ClusterRuleSpec
        $spec.RulesSpec[0].RemoveKey = (Get-DrsVmToVmGroup -name $name -cluster $cluster).Key
        $spec.RulesSpec[0].Operation = 'remove'
        $ClusterToReconfig = Get-View -Id $updateCluster.ExtensionData.MoRef
        $ClusterToReconfig.ReconfigureComputeResource_Task($spec, $true)
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-DrsVmToVmGroup

Function Get-DrsVmToVmGroup {
    <#
        .SYNOPSIS
        Gets all vSphere VM to VM Group.

        .DESCRIPTION
        The Get-DrsVmToVmGroup cmdlet retrieves the vSphere VM to VM Group

        .EXAMPLE
        Get-DrsVmToVmGroup -cluster sfo-m01-cl01
        This example shows how to retrieve all VM to VM groups in the vCenter Server

        .EXAMPLE
        Get-DrsVmToVmGroup -name vm-vm-rule-wsa-vra -cluster sfo-m01-cl01
        This example shows how to retrieve a vSphere VM to VM group in the vCenter Server.

        .PARAMETER name
        The name of the VM to VM group.

        .PARAMETER cluster
        The name of the cluster.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster
    )

    Try {
        $getCluster = Get-Cluster | Where-Object {$_.Name -eq $cluster}
        if ($PsBoundParameters.ContainsKey("name")){
            $getCluster.ExtensionData.Configuration.Rule | Where-Object {$_.Name -eq $name}
        } else {
            $getCluster.ExtensionData.Configuration.Rule
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-DrsVmToVmGroup

Function Get-VcLicense {
    <#
        .SYNOPSIS
        Get list of licenses in vCenter Server.

        .DESCRIPTION
        The Get-VcLicense cmdlet gets a list of licenses in vCenter Server

        .EXAMPLE
        Get-VcLicense
        This example shows how to get a list of licenses in vCenter Server.
    #>


    Try {
        $licenseManager = Get-View LicenseManager
        $LicenseManager.Licenses
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VcLicense

Function New-VcLicense {
    <#
        .SYNOPSIS
        Add a license to vCenter Server.

        .DESCRIPTION
        The New-VcLicense cmdlet adds a license to vCenter Server

        .EXAMPLE
        New-VcLicense -licenseKey <license_key>
        This example shows how to add a license to vCenter Server.

        .PARAMETER licenseKey
        The license key.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$licenseKey
    )

    Try {
        $licenseManager = Get-View LicenseManager
        $licenseManager.AddLicense($licenseKey,$null)
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-VcLicense

Function Remove-VcLicense {
    <#
        .SYNOPSIS
        Remove a license from vCenter Server.

        .DESCRIPTION
        The Remove-VcLicense cmdlet removes a license from vCenter Server

        .EXAMPLE
        Remove-VcLicense -licenseKey <license_key>
        This example shows how to remove a license from vCenter Server.

        .PARAMETER licenseKey
        The license key.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$licenseKey
    )

    Try {
        $licenseManager = Get-View LicenseManager
        $licenseManager.RemoveLicense($licenseKey)
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-VcLicense

Function Get-SubscribedLibrary {
    <#
        .SYNOPSIS
        Retrieves the specified Subscribed Content Library.

        .DESCRIPTION
        The Get-SubscribedLibrary cmdlet retrieves the specified Subscribed Content Library

        .EXAMPLE
        Get-SubscribedLibrary -name Kubernetes
        This example retrieves the Subscribed Content Library named Kubernetes.

        .PARAMETER name
        The name of the Subscribed Content Library.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {    
        $body = '{ "name": "' + $name + '", "type": "SUBSCRIBED" }' 
        $subscribedLibraryId = Invoke-RestMethod -Method POST -Uri "https://$vcApiServer/api/content/library?action=find" -Headers $vcApiHeaders -body $body
        $return = Invoke-RestMethod -Method GET -URI "https://$vcApiServer/api/content/subscribed-library/$subscribedLibraryId" -Headers $vcApiHeaders
        $return
    } Catch {
        Write-Error $_.Exception.Message 
    }
}
Export-ModuleMember -Function Get-SubscribedLibrary

Function Get-VcenterBackupStatus {
    <#
        .SYNOPSIS
        Returns a list of all backup jobs performed on a vCenter Server instance.

        .DESCRIPTION
        The Get-VcenterBackupStatus cmdlet returns a list of all backups performed on a vCenter Server instance.

        .EXAMPLE
        Get-VcenterBackupStatus | Select-Object -Last 1
        This example demonstrates piping the results of this function into Select-Object to return the status of the last backup.
    #>


    Try {
        if ($vcenterApiHeaders) {
            $uri = "https://$vcenterApiServer/rest/appliance/recovery/backup/job/details"
            (Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vcenterApiHeaders).Value
        }
    } Catch {
        $errorStatus = $_.Exception
    }
}
Export-ModuleMember -Function Get-VcenterBackupStatus

Function Get-SnapshotStatus {
    <#
        .SYNOPSIS
        Returns the status of a virtual machine's snapshots.

        .DESCRIPTION
        The Get-SnapshotStatus cmdlet returns the status of a virtual machine's snapshots.

        .EXAMPLE
        Get-SnapshotStatus -vm "foo"
        This example returns the status of the snapshots for the virtual machine named "foo".

        .PARAMETER vm
        The virtual machine name.
    #>


    Param (
        [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vm
    )

    Try {
        $response = Get-VM $vm | Get-Snapshot | Select-Object -Property Name, Created, isCurrent # Get the snapshot details
        $response # Return the snapshot details
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-SnapshotStatus

Function Get-SnapshotConsolidation {
    <#
        .SYNOPSIS
        Returns the status of a virtual machine's need for snapshot consolidation.

        .DESCRIPTION
        The Get-SnapshotConsolidation cmdlet returns the status of a virtual machine's need for snapshot consolidation.

        .EXAMPLE
        Get-SnapshotConsolidation -vm "foo"
        This example returns the status of the snapshot consolidation for the virtual machine named "foo".

        .PARAMETER vm
        The virtual machine name.
    #>


    Param (
        [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vm
    )

    Try {
        $response = (Get-View -ViewType VirtualMachine -Filter @{'Name' = $vm }).Runtime.ConsolidationNeeded # Get the consolidation status
        $response # Return the consolidation status
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-SnapshotConsolidation

Function Get-EsxiAlert {
    <#
        .SYNOPSIS
        Returns the triggered alarms for an ESXi host.

        .DESCRIPTION
        The Get-EsxiAlert cmdlet returns all triggered alarms for ESXi host.

        .EXAMPLE
        Get-EsxiAlert -host sfo-w01-esx01.sfo.rainpole.io
        This example returns all triggered alarms for and ESXi host named sfo-w01-esx01.sfo.rainpole.io.

        .PARAMETER host
        The ESXi host name.
    #>


    Param (
        [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$host
    )

    Try {
        $vmhosts = Get-VMHost
        $vmhost = $vmhosts | Where-Object {$_.name -eq $host}
        foreach ($triggeredAlarm in $vmhost.ExtensionData.TriggeredAlarmState) {
            $alarm = "" | Select-Object Entity, Alarm, Status, Time, Acknowledged, AckBy, AckTime
            $alarm.Alarm = (Get-AlarmDefinition -id $triggeredAlarm.alarm).name
            $alarm.Entity =  ( $vmhosts | Where-Object {$_.id -eq $triggeredAlarm.Entity} ).name # or just $host
            $alarm.Status = $triggeredAlarm.OverallStatus
            $alarm.Time = $triggeredAlarm.Time
            $alarm.Acknowledged = $triggeredAlarm.Acknowledged
            $alarm.AckBy = $triggeredAlarm.AcknowledgedByUser
            $alarm.AckTime = $triggeredAlarm.AcknowledgedTime
            $alarm
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-EsxiAlert

Function Get-VsanHealthTest {
    <#
        .SYNOPSIS
        Returns the vSAN healthcheck tests from a vSAN cluster in vCenter Server.

        .DESCRIPTION
        The Get-VsanHealthTest cmdlet returns all vSAN healthcheck tests from a VSAN cluster in vCenter Server.

        .EXAMPLE
        Get-VsanHealthTest -cluster sfo-m01-c01
        This example returns all vSAN healthcheck tests from vSAN cluster sfo-m01-c01 in connected vCenter Server.

        .PARAMETER cluster
        The vSAN cluster name.
    #>


    Param (
        [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster
    )

    Try {
        $vsanClusterHealthSystem = Get-VSANView -Id "VsanVcClusterHealthSystem-vsan-cluster-health-system"
        $clusterView = (Get-Cluster -Name $cluster).ExtensionData.MoRef
        $results = $vsanClusterHealthSystem.VsanQueryVcClusterHealthSummary($clusterView,$null,$null,$true,$null,$null,'defaultView')
        $healthCheckGroups = $results.groups
        $healthTests = New-Object System.Collections.ArrayList
        foreach ($healthCheckGroup in $healthCheckGroups) {
            foreach ($test in $healthCheckGroup.GroupTests) {
                $testResult = [pscustomobject] @{
                    GroupName = $healthCheckGroup.GroupName
                    TestName = $test.TestName
                    TestHealth = $test.TestHealth.ToUpper()
                }
                $healthTests += $testResult
            }
        }
        $healthTests
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VsanHealthTest

Function Get-VcenterTriggeredAlarm {
    <#
        .SYNOPSIS
        Returns the triggered alarms for a vCenter Server instance.

        .DESCRIPTION
        The Get-VcenterTriggeredAlarm cmdlet returns all triggered alarms from vCenter Server instance.

        .EXAMPLE
        Get-VcenterTriggeredAlarm -server sfo-w01-vc01.sfo.rainpole.io
        This example returns all triggered alarms for a vCenter Server instance named sfo-w01-vc01.sfo.rainpole.io.

        .PARAMETER server
        The vCenter Server name.
    #>


    Param (
        [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server
    )

    Try {
        $rootFolder = Get-Folder -Server $server "Datacenters"
        foreach ($triggeredAlarm in $rootFolder.ExtensionData.TriggeredAlarmState) {
            $alarm = "" | Select-Object EntityType, Alarm, Status, Time, Acknowledged, AckBy, AckTime
            $alarm.Alarm = (Get-View -Server $server $triggeredAlarm.Alarm).Info.Name
            $alarm.EntityType = (Get-View -Server $server $triggeredAlarm.Entity).GetType().Name
            $alarm.Status = $triggeredAlarm.OverallStatus
            $alarm.Time = $triggeredAlarm.Time
            $alarm.Acknowledged = $triggeredAlarm.Acknowledged
            $alarm.AckBy = $triggeredAlarm.AcknowledgedByUser
            $alarm.AckTime = $triggeredAlarm.AcknowledgedTime
            $alarm
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VcenterTriggeredAlarm

Function Get-ESXiAdminGroup {
    <#
        .SYNOPSIS
        Retrieves Config.HostAgent.plugins.hostsvc.esxAdminsGroup on ESXi host.

        .DESCRIPTION
        Connects to specified ESXi Host and retrieves the setting for Config.HostAgent.plugins.hostsvc.esxAdminsGroup

        .EXAMPLE
        Get-ESXiAdminGroup -esxiHost sfo01-m01-esx01.sfo.rainpole.io.

        .PARAMETER esxiHost
        The ESXi host name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$esxiHost
    )
    
    Try {
        if (-Not $Global:DefaultVIServer.IsConnected) {
            Write-Error "No valid vCenter Server Connection found, please use the Connect-VIServer to connect"; Break
        } else {
            $esxAdminsGroupSettings = (Get-AdvancedSetting -Entity $esxiHost -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroup).Value.toString()
            $tmp = [pscustomobject] @{
                Host = $esxiHost;
                esxAdminsGroup = $esxAdminsGroupSettings;
            }
            $tmp
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-ESXiAdminGroup
    
Function Set-ESXiAdminGroup {
    <#
        .SYNOPSIS
        Configure Config.HostAgent.plugins.hostsvc.esxAdminsGroup on ESXi host.

        .DESCRIPTION
        Connects to specified ESXi Host and sets a new value for Config.HostAgent.plugins.hostsvc.esxAdminsGroup

        .EXAMPLE
        Set-ESXiAdminGroup -esxiHost sfo01-m01-esx01.sfo.rainpole.io -groupName ug-esxi-admins.

        .PARAMETER esxiHost
        The ESXi host name.

        .PARAMETER groupName
        The new group name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$esxiHost,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupName
    )
    
    Try {
        if (-Not $Global:DefaultVIServer.IsConnected) {
            Write-Error "No valid vCenter Server Connection found, please use the Connect-VIServer to connect"; Break
        } else {
            Get-AdvancedSetting -Entity $esxiHost -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroup | Set-AdvancedSetting -Value $groupName -Confirm:$false
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-ESXiAdminGroup

Function Get-VCenterCEIP {
    <#
        .SYNOPSIS
        Retrieves the the Customer Experience Improvement Program (CEIP) setting for vCenter Server.

        .DESCRIPTION
        The Get-VCenterCEIP cmdlet retrieves the the CEIP setting for vCenter Server

        .EXAMPLE
        Get-VCenterCEIP.
    #>


    Try {
        if (-Not $Global:DefaultVIServer.IsConnected) {
            Write-Host "No valid vCenter Server Connection found, please use the Connect-VIServer to connect"; Break
        } else {
            $ceipSettings = (Get-AdvancedSetting -Entity $Global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData).Value.toString() | ConvertFrom-Json
            $ceipEnabled = $ceipSettings.consentConfigurations[0].consentAccepted
            $tmp = [pscustomobject] @{
                FQDN = $Global:DefaultVIServer.Name;
                CEIP = $ceipEnabled;
            }
            $tmp
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VCenterCEIP

Function Set-VCenterCEIP {
    <#
        .SYNOPSIS
        Enables or Disables the Customer Experience Improvement Program (CEIP) setting for vCenter Server.

        .DESCRIPTION
        The Set-VCenterCEIP cmdlet enables or disables the CEIP setting for vCenter Server
    
        .EXAMPLE
        Set-VCenterCEIP -Enabled

        .EXAMPLE
        Set-VCenterCEIP -Disabled.

        .PARAMETER Enabled
        Enables the CEIP setting for vCenter Server.

        .PARAMETER Disabled
        Disables the CEIP setting for vCenter Server.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()][Switch]$Enabled,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$Disabled
    )

    Try {
        If (-Not $Global:DefaultVIServer.IsConnected) {
            Write-Host "No valid vCenter Server Connection found, please use the Connect-VIServer to connect"; Break
        } else {
            $ceipSettings = (Get-AdvancedSetting -Entity $Global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData).Value.toString() | ConvertFrom-Json
            If($Enabled) {
                $originalVersion = $ceipSettings.version
                $ceipSettings.version = [int]$originalVersion + 1
                $ceipSettings.consentConfigurations[0].consentAccepted = $True
                $ceipSettings.consentConfigurations[1].consentAccepted = $True
                $updatedceipSettings = $ceipSettings | ConvertTo-Json
                Write-Host "Enabling Customer Experience Improvement Program (CEIP) ..."
                Get-AdvancedSetting -Entity $Global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData | Set-AdvancedSetting -Value $updatedceipSettings -Confirm:$false
            } else {
                $originalVersion = $ceipSettings.version
                $ceipSettings.version = [int]$originalVersion + 1
                $ceipSettings.consentConfigurations[0].consentAccepted = $False
                $ceipSettings.consentConfigurations[1].consentAccepted = $False
                $updatedceipSettings = $ceipSettings | ConvertTo-Json
                Write-Host "Disablng Customer Experience Improvement Program (CEIP) ..."
                Get-AdvancedSetting -Entity $Global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData | Set-AdvancedSetting -Value $updatedceipSettings -Confirm:$false
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-VCenterCEIP

#EndRegion End vSphere API Endpoint Functions ######
###################################################################################

###################################################################################
#Region Begin Workspace ONE Access Functions ######

Function Request-WSAToken {
    <#
        .SYNOPSIS
        Connects to the specified Workspace ONE Access instance to obtain a session token.

        .DESCRIPTION
        The Request-WSAToken cmdlet connects to the specified Workspace ONE Access instance and requests a session token

        .EXAMPLE
        Request-WSAToken -fqdn sfo-wsa01.sfo.rainpole.io -user admin -pass VMware1!
        This example shows how to connect to a Workspace ONE Access instance and request a session token.

        .PARAMETER fqdn
        The Workspace ONE Access FQDN.

        .PARAMETER user
        The Workspace ONE Access user name.

        .PARAMETER pass
        The Workspace ONE Access user password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    If ( -not $PsBoundParameters.ContainsKey("user") -or ( -not $PsBoundParameters.ContainsKey("pass"))) {
        # Request Credentials
        $creds = Get-Credential
        $user = $creds.UserName.ToString()
        $pass = $creds.GetNetworkCredential().password
    }

    $Global:workspaceOne = $fqdn

    # Validate credentials by executing an API call
    $wsaHeaders = @{"Content-Type" = "application/json" }
    $wsaHeaders.Add("Accept", "application/json; charset=utf-8")
    $uri = "https://$workspaceOne/SAAS/API/1.0/REST/auth/system/login"
    $body = '{"username": "' + $user + '", "password": "' + $pass + '", "issueToken": "true"}'

    Try {
        # Checking against the API
        # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        if ($PSEdition -eq 'Core') {
            $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -Body $body -SkipCertificateCheck
            $Global:sessionToken = "HZN " + $response.sessionToken
        } else {
            $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -Body $body
            $Global:sessionToken = "HZN " + $response.sessionToken
        }
        if ($response.sessionToken) {
            Write-Output "Successfully Requested New Session Token From Workspace ONE Access instance: $fqdn"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-WSAToken

Function Get-WSAIdentityProvider {
    <#
        .SYNOPSIS
        Get identity providers.

        .DESCRIPTION
        The Get-WSAIdentityProvider cmdlets retrieves a list of identity providers in Workspace ONE Access

        .EXAMPLE
        Get-WSAIdentityProvider
        This example retrieves a list of identity providers in Workspace ONE Access.
    #>


    Try {
        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.identityprovider.summary.list+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/identityProviders?onlyEnabledAdapters=true"
        $response = Invoke-RestMethod -Uri $uri -Method 'GET' -Headers $wsaHeaders
        $response.items
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAIdentityProvider

Function Get-WSAConnector {
    <#
        .SYNOPSIS
        Get connectors.

        .DESCRIPTION
        The Get-WSAConnector cmdlets retrieves a list of connectors in Workspace ONE Access

        .EXAMPLE
        Get-WSAConnector
        This example retrieves a list of connectors in Workspace ONE Access.
    #>


    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.connector+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/connectorinstances"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
        $response.items
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAConnector

Function Add-WSAConnector {
    <#
        .SYNOPSIS
        Add connector to identity providor.

        .DESCRIPTION
        The Add-WSAConnector cmdlets adds a connector to an identity providoer in Workspace ONE Access

        .EXAMPLE
        Add-WSAConnector -wsaFqdn xint-wsa01b.rainpole.io -domain sfo.rainpole.io -bindUserPass VMw@re1!
        This example adds a connector to an identity providoer in Workspace ONE Access.

        .PARAMETER wsaNode
        The Workspace ONE Access node FQDN.

        .PARAMETER domain
        The domain name.

        .PARAMETER bindUserPass
        The bind user password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaNode,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUserPass
    )

    Try {
        $identityProviderId = (Get-WSAIdentityProvider | Where-Object {$_.directoryConfigurations.name -eq $domain}).id
        $directoryId = (Get-WSADirectory | Where-Object {$_.name -eq $domain}).directoryId
        $connectorId = (Get-WSAConnector | Where-Object {$_.host -eq $wsaNode}).instanceId

        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.connector.management.connector+json"}
        $wsaHeaders.Add("Content-Type", "application/vnd.vmware.horizon.manager.connector.management.directory.bindDetails+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/connectorinstances/$connectorId/associatedirectory?idp=$identityProviderId"
        $body = '{"directoryId": "' + $directoryId + '", "directoryBindPassword":"' + $bindUserPass + '", "usedForAuthentication":true, "bindToAD":true}'
        $response = Invoke-RestMethod -Uri $uri -Method 'POST' -Headers $wsaHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-WSAConnector

Function Get-WSADirectory {
    <#
        .SYNOPSIS
        Get diretories.

        .DESCRIPTION
        The Get-WSADirectory cmdlets retrieves all directories in Workspace ONE Access

        .EXAMPLE
        Get-WSADirectory
        This example retrieves a list of directories in Workspace ONE Access

        .EXAMPLE
        Get-WSADirectory -connector
        This example retrieves a list of connectors for a directory in Workspace ONE Access.

        .PARAMETER connector
        The connector switch.

        .PARAMETER directoryId
        The directory ID.
    #>


    Param (
        [Parameter (ParameterSetName = "connector", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$directoryId,
        [Parameter (ParameterSetName = "connector", Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$connector
    )

    Try {
        if ($PsBoundParameters.ContainsKey("connector")) {
            $wsaHeaders = @{"Accept" = "" }
            $wsaHeaders.Add("Authorization", "$sessionToken")
            $uri = "https://xint-wsa01.rainpole.io/SAAS/jersey/manager/api/connectormanagement/directoryconfigs/$directoryId/connectors"
            $response = Invoke-RestMethod -Uri $uri -Method 'GET' -Headers $wsaHeaders
            $response.items
        } else {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.ad.over.ldap+json" }
            $wsaHeaders.Add("Authorization", "$sessionToken")
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs"
            $response = Invoke-RestMethod -Uri $uri -Method 'GET' -Headers $wsaHeaders
            $response.items
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSADirectory

Function Get-WSADirectoryDomain {
    <#
        .SYNOPSIS
        Get directory domains.

        .DESCRIPTION
        The Get-WSADirectoryDomain cmdlets retrieves a list of directory domains in Workspace ONE Access

        .EXAMPLE
        Get-WSADirectoryDomain -directoryId a1c985d5-0eeb-4a66-bc51-11eda9321aac
        This example retrieves a list of directory domains in Workspace ONE Access.

        .PARAMETER directoryId
        The directory ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$directoryId
    )

    Try {
        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.connector.management.directory.domain.list+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs/$directoryId/domains"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
        $response.items
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSADirectoryDomain

Function Add-WSALdapDirectory {
    <#
        .SYNOPSIS
        Create an LDAP directory.

        .DESCRIPTION
        The Add-WSALdapDirectory cmdlets creates a new LDAP Active Directory connection in Workspace ONE Access

        .EXAMPLE
        Add-WSALdapDirectory -domainName sfo.rainpole.io -baseDn "ou=VVD,dc=sfo,dc=rainpole,dc=io" -bindDn "cn=svc-wsa-ad,ou=VVD,dc=sfo,dc=rainpole,dc=io"
        This example creates a new LDAP Active Directory connection in Workspace ONE Access.

        .PARAMETER domainName
        The domain name.

        .PARAMETER baseDn
        The base DN.

        .PARAMETER bindDn
        The bind DN.

        .PARAMETER certificate
        The certificate file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindDn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificate
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.ad.over.ldap+json" }
        $wsaHeaders.Add("Accept", "application/vnd.vmware.horizon.manager.connector.management.directory.ad.over.ldap+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        if ($PsBoundParameters.ContainsKey("certificate")){
            #read certificate file contents as certdata
            $certdata = (Get-Content ($certificate)) -join "\n"
            $body = '{
                "useSRV":true,
                "directoryType":"ACTIVE_DIRECTORY_LDAP",
                "directorySearchAttribute":"sAMAccountName",
                "directoryConfigId":null,
                "useGlobalCatalog":false,
                "syncConfigurationEnabled":false,
                "useStartTls":true,
                "userAttributeMappings":[],
                "name":"'
 + $domainName + '",
                "baseDN":"'
 + $baseDn + '",
                "bindDN":"'
 + $bindDn + '",
                "sslCertificate":"'
 + $certdata + '"
            }'

        } else {
            $body = '{
                "useSRV":true,
                "directoryType":"ACTIVE_DIRECTORY_LDAP",
                "directorySearchAttribute":"sAMAccountName",
                "directoryConfigId":null,
                "useGlobalCatalog":false,
                "syncConfigurationEnabled":false,
                "useStartTls":false,
                "userAttributeMappings":[],
                "name":"'
 + $domainName + '",
                "baseDN":"'
 + $baseDn + '",
                "bindDN":"'
 + $bindDn + '"
            }'

        }
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs"
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-WSALdapDirectory

Function Set-WSABindPassword {
    <#
        .SYNOPSIS
        Create an LDAP directory.

        .DESCRIPTION
        The Set-WSABindPassword cmdlets creates a new LDAP Active Directory connection in Workspace ONE Access

        .EXAMPLE
    Set-WSABindPassword -directoryId a1c985d5-0eeb-4a66-bc51-11eda9321aac -connectorId 59ee9717-a09e-45b6-9e5f-8d92a55a1825 -password VMw@re1!
        This example creates a new LDAP Active Directory connection in Workspace ONE Access.

        .PARAMETER directoryId
        The directory ID.

        .PARAMETER connectorId
        The connector ID.

        .PARAMETER pass
        The bind password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$directoryId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$connectorId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.details+json" }
        $wsaHeaders.Add("Accept", "application/vnd.vmware.horizon.manager.connector.management.connector+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $body = '{"directoryId":"' + $directoryId + '","directoryBindPassword":"' + $pass + '","usedForAuthentication":true}'
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/connectorinstances/$connectorId/associatedirectory"
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WSABindPassword

Function Set-WSASyncSetting {
    <#
        .SYNOPSIS
        Set directory sync schedule.

        .DESCRIPTION
        The Set-WSASyncSetting cmdlets configures the directory sync schedule in Workspace ONE Access

        .EXAMPLE
        Set-WSASyncSetting -directoryId a1c985d5-0eeb-4a66-bc51-11eda9321aac
        This example configures the directory sync schedule in Workspace ONE Access.

        .PARAMETER directoryId
        The directory ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$directoryId
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.syncschedule+json" }
        $wsaHeaders.Add("Accept", "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.syncschedule+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $body = '{"frequency":"fifteenMinutes"}'
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs/$directoryId/syncprofile"
        Invoke-RestMethod $uri -Method 'PUT' -Headers $wsaHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WSASyncSetting

Function Start-WSADirectorySync {
    <#
        .SYNOPSIS
        Start an directory sync.

        .DESCRIPTION
        The Start-WSADirectorySync cmdlets triggers a directory sync in Workspace ONE Access

        .EXAMPLE
        Start-WSADirectorySync -directoryId a1c985d5-0eeb-4a66-bc51-11eda9321aac
        This example starts a directory sync in Workspace ONE Access.

        .PARAMETER directoryId
        The directory ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$directoryId
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.sync+json" }
        $wsaHeaders.Add("Accept", "application/vnd.vmware.horizon.v1.0+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $body = '{"ignoreSafeguards":true}'
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs/$directoryId/syncprofile/sync"
        Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Start-WSADirectorySync

Function Set-WSADirectoryUser {
    <#
        .SYNOPSIS
        Add users to directory.

        .DESCRIPTION
        The Set-WSADirectoryUser cmdlets configures the user/ou that should be sycncronised for Workspace ONE Access

        .EXAMPLE
        Set-WSADirectoryUser -directoryId a1c985d5-0eeb-4a66-bc51-11eda9321aac -json (Get-Content -Raw .\adUsers.json)
        This example configures the user/ou that should be sycncronised for Workspace ONE Access.

        .PARAMETER directoryId
        The directory ID.

        .PARAMETER json
        The JSON file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$directoryId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.users+json" }
        $wsaHeaders.Add("Accept", "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.users+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs/$directoryId/syncprofile"
        Invoke-RestMethod $uri -Method 'PUT' -Headers $wsaHeaders -Body $json
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WSADirectoryUser

Function Set-WSADirectoryGroup {
    <#
        .SYNOPSIS
        Add groups to directory.

        .DESCRIPTION
        The Set-WSADirectoryGroup cmdlets configures the groups/ou that should be sycncronised for Workspace ONE Access

        .EXAMPLE
        Set-WSADirectoryUser -directoryId a1c985d5-0eeb-4a66-bc51-11eda9321aac -json (Get-Content -Raw .\adGroups.json)
        This example configures the groups/ou that should be sycncronised for Workspace ONE Access.

        .PARAMETER directoryId
        The directory ID.

        .PARAMETER json
        The JSON file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$directoryId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.groups+json" }
        $wsaHeaders.Add("Accept", "application/vnd.vmware.horizon.manager.connector.management.directory.sync.profile.groups+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/connectormanagement/directoryconfigs/$directoryId/syncprofile"
        $response = Invoke-RestMethod $uri -Method 'PUT' -Headers $wsaHeaders -Body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WSADirectoryGroup

Function Get-WSASmtpConfiguration {
    <#
        .SYNOPSIS
        Get SMTP configuration.

        .DESCRIPTION
        The Get-WSASmtpConfiguration cmdlets retrieves the SMTP configurtion of Workspace ONE Access

        .EXAMPLE
        Get-WSASmtpConfiguration
        This example gets the current SMTP configuration of Workspace ONE Access.
    #>


    Try {
        $wsaHeaders = @{"Accept" = "application/json, text/plain, */*" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/system/config/smtp"
        $response = Invoke-RestMethod $uri -Headers $wsaHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSASmtpConfiguration

Function Set-WSASmtpConfiguration {
    <#
        .SYNOPSIS
        Set SMTP configuration.

        .DESCRIPTION
        The Set-WSASmtpConfiguration cmdlets configures the SMTP configurtion of Workspace ONE Access

        .EXAMPLE
        Set-WSASmtpConfiguration
        This example sets the SMTP configuration of Workspace ONE Access.

        .PARAMETER fqdn
        The FQDN of the SMTP server.

        .PARAMETER port
        The port of the SMTP server.

        .PARAMETER user
        The user name of the SMTP server.

        .PARAMETER pass
        The password of the SMTP server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        $wsaHeaders = @{"Accept" = "application/json, text/plain, */*" }
        $wsaHeaders.Add("Content-Type", "application/vnd.vmware.horizon.manager.system.config.smtp+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        if (-not $PsBoundParameters.ContainsKey("pass")) {
            $body = '{ "host": "' + $fqdn + '", "port": ' + $port + ', "user": "' + $user + '", "password": "' + $pass + '"}'
        } else {
            $body = '{ "host": "' + $fqdn + '", "port": ' + $port + ', "user": "' + $user + '" }'
        }
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/system/config/smtp"
        $response = Invoke-RestMethod $uri -Method 'PUT' -Headers $wsaHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WSASmtpConfiguration

Function Set-WSARoleMember {
    <#
        .SYNOPSIS
        Set Workspace ONE Access Role Member.

        .DESCRIPTION
        The Set-WSARoleMember cmdlets updates a Workspace ONE Access role with the given group

        EXAMPLE
        Set-WSARoleMember -id 55048dee-fe1b-404a-936d-3e0b86a7209e -groupId fe515568-fdcd-43c7-9971-e834d7246203
        This example updates a Workspace ONE Access role with the given GroupId.

        .PARAMETER id
        The Role ID.

        .PARAMETER groupId
        The Group ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Roles/$id"
        $json = '{
            "schemas": [
                "urn:scim:schemas:core:1.0"
            ],
            "members": [ {
                "value": "$groupId",
                "type": "Group"
            }]
        }'

        Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -body $json -headers $wsaHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WSARoleMember

Function Get-WSARole {
    <#
        .SYNOPSIS
        Get roles.

        .DESCRIPTION
        The Get-WSARole cmdlets retrieves the roles in Workspace ONE Access

        .EXAMPLE
        Get-WSARole
        This example retrieves the roles in Workspace ONE Access.

        .PARAMETER id
        The Role ID.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Roles/$id"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response
        } else {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Roles"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response.Resources
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSARole

Function Get-WSAGroup {
    <#
        .SYNOPSIS
        Get groups.

        .DESCRIPTION
        The Get-WSAGroup cmdlets retrieves the groups in Workspace ONE Access

        .EXAMPLE
        Get-WSAGroup
        This example retrieves the groups in Workspace ONE Access.

        .PARAMETER id
        The Group ID.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Groups/$id"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response
        } else {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Groups"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response.Resources
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAGroup

Function Get-WSAUser {
    <#
        .SYNOPSIS
        Get users.

        .DESCRIPTION
        The Get-WSAUser cmdlets retrieves the users in Workspace ONE Access

        .EXAMPLE
        Get-WSAUser
        This example retrieves the users in Workspace ONE Access.

        .PARAMETER id
        The User ID.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Users/$id"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response
        } else {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Users"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response.Resources
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAUser

Function Get-WSARuleSet {
    <#
        .SYNOPSIS
        Get rulesets.

        .DESCRIPTION
        The Get-WSARuleSet cmdlets retrieves the rulesets in Workspace ONE Access

        .EXAMPLE
        Get-WSARuleSet
        This example retrieves the rulesets in Workspace ONE Access.
    #>


    Try {
        $wsaHeaders = @{"Accept-Type" = "application/json, text/plain, */*" }
        $wsaHeaders.Add("Content-Type", "application/vnd.vmware.vidm.accesscontrol.ruleset.list+json")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/acs/rulesets"
        $response = Invoke-RestMethod $uri -Headers $wsaHeaders
        $response.items
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSARuleSet

Function Get-WSAOAuthToken {
    <#
        .SYNOPSIS
        Get AOuth Token.

        .DESCRIPTION
        The Get-WSAOAuthToken cmdlets gets an OAuth token from Workspace ONE Access

        .EXAMPLE
        Get-WSAOAuthToken
        This example retrieves the am OAuth oken from Workspace ONE Access.
    #>


    Try {
        $wsaHeaders = @{"Content-Type" = "application/x-www-form-urlencoded; charset=UTF-8" }
        $wsaHeaders.Add("Accept", "application/json, text/javascript, */*; q=0.01")
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/admin/settings/OAuthClient/generateRandomOAuthSecret"
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAOAuthToken

Function Get-WSAClient {
    <#
        .SYNOPSIS
        Get clients.

        .DESCRIPTION
        The Get-WSAClient cmdlets gets a list of clients in Workspace ONE Access

        .EXAMPLE
        Get-WSAClient
        This example retrieves all clients in Workspace ONE Access.

        .PARAMETER clientId
        The client ID.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$clientId
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.oauth2client+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        if ($PsBoundParameters.ContainsKey("clientId")) {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/oauth2clients/$clientId"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response
        } else {
            $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/oauth2clients"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
            $response.items
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAClient

Function Add-WSAClient {
    <#
        .SYNOPSIS
        Add a client.

        .DESCRIPTION
        The Add-WSAClient cmdlets add a client in Workspace ONE Access

        .EXAMPLE
        Add-WSAClient -json .\SampleJson\nsxClient.json
        This example retrieves all clients in Workspace ONE Access.

        .PARAMETER clientId
        The client ID.

        .PARAMETER sharedSecret
        The shared secret.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$clientId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$sharedSecret
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.horizon.manager.oauth2client+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $body = '{
            "clientId": "'
 + $clientId + '",
            "secret": "'
 + $sharedSecret + '",
            "scope": "admin",
            "authGrantTypes": "refresh_token client_credentials",
            "redirectUri": "",
            "tokenType": "Bearer",
            "tokenLength": 32,
            "accessTokenTTL": 8,
            "refreshTokenTTL": 1440,
            "refreshTokenIdleTTL": 4,
            "rememberAs": "'
 + $clientId + '",
            "displayUserGrant": false,
            "internalSystemClient": false,
            "inheritanceAllowed": true
        }'

        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/oauth2clients"
        Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-WSAClient

Function Add-WSARoleAssociation {
    <#
        .SYNOPSIS
        Add the AD group to the WSA role.

        .DESCRIPTION
        Add the AD group to the given WSA role.

        .EXAMPLE
        Add-WSARoleAssociation -roleId "1d0b09a1-8744-4f85-8c4f-ac104e586010" -groupId "1e942dc6-94ba-43ef-97ce-9ba34fee1609"

        .PARAMETER roleId
        The role id

        .PARAMETER groupId
        The group id.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$roleId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/vnd.vmware.vidm.accesscontrol.ruleset.associations.bulk.request+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/acs/associations/rulesets/$roleId"
        $body = '{
            "operations": [
                {
                    "users": [],
                    "groups": [
                        "'
+$groupId+'"
                    ],
                    "associationMethodTO": "POST"
                },
                {
                    "users": [],
                    "groups": [],
                    "associationMethodTO": "DELETE"
                }
            ]
        }'


        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-WSARoleAssociation

Function Get-WSARoleId {
    <#
        .SYNOPSIS
        Get role id for role name from Workspace ONE Access.

        .DESCRIPTION
        The Get-WSARoleId cmdlets gets the role id corresponding to a given role name from Workspace One Access

        .EXAMPLE
        Get-WSARoleId -role "Super Admin"
        This example retrieves the rile id for the Super Admin role

        .PARAMETER role
        The role name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/acs/rulesets"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
        $roledetails = $response.items | Where-Object {$_.name -eq $role}
        $roleId=$roledetails._links.self.href.split('/')[3]
        $roleId
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSARoleId

Function Get-WSAActiveDirectoryGroupDetail {
    <#
        .SYNOPSIS
        Get details for an Active Directory group in Workspace ONE Access.

        .DESCRIPTION
        The Get-WSAActiveDirectoryGroupDetail cmdlets gets details from Workspace ONE Access for the given Active Directory group

        .EXAMPLE
        Get-WSAActiveDirectoryGroupDetail -group "gg-wsa-admins".

        .PARAMETER group
        The group name
        This example gets the details for the Active Directory group 'gg-wsa-admins'.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$group
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/scim/Groups/.search?locale=en"
        $body = '{
                    "attributes": "id,displayName",
                    "filter": "(displayName co \"'
 + $group + '\")"
                }'

        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $wsaHeaders -body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSAActiveDirectoryGroupDetail

Function Get-WSARoleAssociation {
    <#
        .SYNOPSIS
        Get associations for the given Role Id.

        .DESCRIPTION
        The Get-WSARoleAssociation retrieves the associations for the given Role Id from Workspace ONE Access.
        This includes details of the groups associated with the ole.

        .EXAMPLE
        Get-WSARoleAssociation -roleId "1d0b09a1-8744-4f85-8c4f-ac104e586010".

        .PARAMETER roleId
        The role id
        This example retrieves the associations based on the role Id provided.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$roleId
    )

    Try {
        $wsaHeaders = @{"Content-Type" = "application/json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workSpaceOne/acs/associations/rulesets/$roleId"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $wsaHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WSARoleAssociation

Function Get-WsaAccountLockout {
    <#
        .SYNOPSIS
        Get account lockout policy.

        .DESCRIPTION
        Get details of the account lockout policy for Workspace ONE Access

        .EXAMPLE
        Get-WsaAccountLockout.
    #>


    Try {
        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.password.lockout+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workspaceOne/SAAS/jersey/manager/api/passwordlockoutconfig"
        Invoke-RestMethod $uri -Headers $wsaHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WsaAccountLockout

Function Set-WsaAccountLockout {
    <#
        .SYNOPSIS
        Set account lockout policy.

        .DESCRIPTION
        Set configuration of the account lockout policy for Workspace ONE Access

        .EXAMPLE
        Set-WsaAccountLockout -numAttempts 5 -attemptInterval 15 -unlockInterval 15.

        .PARAMETER numAttempts
        The number of attempts.

        .PARAMETER attemptInterval
        The attempt interval.

        .PARAMETER unlockInterval
        The unlock interval.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$numAttempts,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$attemptInterval,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$unlockInterval
    )

    Try {
        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.password.lockout+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $wsaHeaders.Add("Content-Type", "application/vnd.vmware.horizon.manager.password.lockout+json")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/passwordlockoutconfig"
        $body = '{"numAttempts":' + $numAttempts + ',"attemptInterval":' + $attemptInterval + ',"unlockInterval":' + $unlockInterval + '}'
        Invoke-RestMethod $uri -Method 'PUT' -Headers $wsaHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WsaAccountLockout

Function Get-WsaPasswordPolicy {
    <#
        .SYNOPSIS
        Get password policy.

        .DESCRIPTION
        Get details of the password policy for Workspace ONE Access

        .EXAMPLE
        Get-WsaPasswordPolicy.
    #>


    Try {
        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.tenants.tenant.passwordpolicy+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $uri = "https://$workspaceOne/SAAS/jersey/manager/api/tenants/tenant/passwordpolicy"
        Invoke-RestMethod $uri -Headers $wsaHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-WsaPasswordPolicy

Function Set-WsaPasswordPolicy {
    <#
        .SYNOPSIS
        Set password complexity and expiration policies.

        .DESCRIPTION
        Set configuration of the password complexity and expiration policies for Workspace ONE Access

        .EXAMPLE
        Set-WsaPasswordPolicy -minLen 15 -minLower 1 -minUpper 1 -minDigit 1 -minSpecial 1 -history 5 -maxConsecutiveIdenticalCharacters 1 -maxPreviousPasswordCharactersReused 0 -tempPasswordTtlInHrs 24 -passwordTtlInDays 999 -notificationThresholdInDays 14 -notificationIntervalInDays 7.

        .PARAMETER minLen
        The minimum length of the password.

        .PARAMETER minLower
        The minimum number of lowercase characters.

        .PARAMETER minUpper
        The minimum number of uppercase characters.

        .PARAMETER minDigit
        The minimum number of digits.

        .PARAMETER minSpecial
        The minimum number of special characters.

        .PARAMETER history
        The number of previous passwords to be remembered.

        .PARAMETER maxConsecutiveIdenticalCharacters
        The maximum number of consecutive identical characters.

        .PARAMETER maxPreviousPasswordCharactersReused
        The maximum number of previous password characters reused.

        .PARAMETER tempPasswordTtlInHrs
        The temporary password time to live in hours.

        .PARAMETER passwordTtlInDays
        The password time to live in days.

        .PARAMETER notificationThresholdInDays
        The notification threshold in days.

        .PARAMETER notificationIntervalInDays
        The notification interval in days.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$minLen,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$minLower,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$minUpper,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$minDigit,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$minSpecial,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$history,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$maxConsecutiveIdenticalCharacters,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$maxPreviousPasswordCharactersReused,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tempPasswordTtlInHrs,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$passwordTtlInDays,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$notificationThresholdInDays,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$notificationIntervalInDays

    )

    Try {
        $wsaHeaders = @{"Accept" = "application/vnd.vmware.horizon.manager.tenants.tenant.passwordpolicy+json" }
        $wsaHeaders.Add("Authorization", "$sessionToken")
        $wsaHeaders.Add("Content-Type", "application/vnd.vmware.horizon.manager.tenants.tenant.passwordpolicy+json")
        $uri = "https://$workSpaceOne/SAAS/jersey/manager/api/tenants/tenant/passwordpolicy"
        $passwordTtlInHours = [int]$passwordTtlInDays * 24
        $notificationThresholdInMilliSec = [int]$notificationThresholdInDays * 24 * 3600 * 1000
        $notificationIntervalInMilliSec = [int]$notificationIntervalInDays * 24 * 3600 * 1000
        $body = '{
            "minLen":'
+ $minLen + ',
            "minLower":'
+ $minLower + ',
            "minUpper":'
+ $minUpper + ',
            "minDigit":'
+ $minDigit + ',
            "minSpecial":'
+ $minSpecial + ',
            "history":'
+ $history + ',
            "maxConsecutiveIdenticalCharacters":'
+ $maxConsecutiveIdenticalCharacters + ',
            "maxPreviousPasswordCharactersReused":'
+ $maxPreviousPasswordCharactersReused + ',
            "tempPasswordTtl":'
+ $tempPasswordTtlInHrs + ',
            "passwordTtlInHours":'
+ $passwordTtlInHours + ',
            "notificationThreshold":'
+ $notificationThresholdInMilliSec + ',
            "notificationInterval":'
+ $notificationIntervalInMilliSec + '
        }'

        Invoke-RestMethod $uri -Method 'PUT' -Headers $wsaHeaders -Body $body | Out-Null
        Get-WsaPasswordPolicy
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WsaPasswordPolicy

#EndRegion End Workspace ONE Access Functions ######
###################################################################################

###################################################################################
#Region Begin NSX Functions ######

Function Request-NsxtToken {
    <#
        .SYNOPSIS
        Connects to the specified NSX Manager.

        .DESCRIPTION
        The Request-NsxtToken cmdlet connects to the specified NSX Manager with the supplied credentials

        .EXAMPLE
        Request-NsxtToken -fqdn sfo-w01-nsx01.sfo.rainpole.io -username admin -password VMw@re1!VMw@re1!
        This example shows how to connect to NSX Manager

        .EXAMPLE
        Get-NsxtServerDetail -fqdn sfo-vcf01.sfo.rainpole.io -username admin@local -password VMw@re1!VMw@re1! -domain sfo-w01 | Request-NsxtToken
        This example shows how to connect to NSX Manager using pipeline input from Get-NsxtServerDetail.

        .PARAMETER fqdn
        The FQDN of the NSX Manager.

        .PARAMETER username
        The username of the NSX Manager.

        .PARAMETER password
        The password of the NSX Manager.

        .PARAMETER inputObject
        The input object from Get-NsxtServerDetail.

        .PARAMETER skipCertificateCheck
        Skip the certificate check.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()][String]$fqdn,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psobject]$inputObject,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$skipCertificateCheck
    )

    if ($inputObject) {
        $username = $inputObject.adminUser
        $password = $inputObject.adminPass
        $fqdn = $inputObject.fqdn
        $sddcManager = (Get-VCFManager).fqdn
    } else {
        if (!$PsBoundParameters.ContainsKey("username") -or (!$PsBoundParameters.ContainsKey("password"))) {
            # Request Credentials
            $creds = Get-Credential
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        if (!$PsBoundParameters.ContainsKey("fqdn")) {
            $fqdn = Read-Host "NSX Manager FQDN not found, please enter a value e.g. sfo-m01-nsx01.sfo.rainpole.io"
        }
    }

    if ($PsBoundParameters.ContainsKey("skipCertificateCheck")) {
        if (-not("placeholder" -as [type])) {
            add-type -TypeDefinition @"
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public static class Placeholder {
    public static bool ReturnTrue(object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors) { return true; }

    public static RemoteCertificateValidationCallback GetDelegate() {
        return new RemoteCertificateValidationCallback(Placeholder.ReturnTrue);
    }
}
"@

        } 
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = [placeholder]::GetDelegate()
    }

    # Validate credentials by executing an API call
    $Global:nsxtHeaders = createBasicAuthHeader $username $password
    $Global:nsxtmanager = $fqdn
    $uri = "https://$nsxtmanager/api/v1/logical-ports"

    Try {
        # Checking against the NSX Managers API
        # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        if ($PSEdition -eq 'Core') {
            $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $nsxtHeaders -SkipCertificateCheck
        } else {
            $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $nsxtHeaders
        }
        if ($response) {
            if ($inputObject) {
                Write-Output "Successfully Requested New API Token for NSX Manager $nsxtmanager via SDDC Manager $sddcManager"
            } else {
                Write-Output "Successfully Requested New API Token for NSX Manager $nsxtmanager"
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
New-Alias -name Request-NsxToken -Value Request-NsxtToken
Export-ModuleMember -Alias Request-NsxToken -Function Request-NsxtToken

Function Get-NsxtComputeManager {
    <#
        .SYNOPSIS
        Retrieves a list of compute managers from NSX Manager.

        .DESCRIPTION
        The Get-NsxtComputeManager cmdlet gets compute managers from NSX Manager

        .EXAMPLE
        Get-NsxtComputeManager
        This example gets all compute managers

        .EXAMPLE
        Get-NsxtComputeManager -vCenterServer "sfo-m01-vc01.sfo.rainpole.io"
        This example gets the compute manager named "sfo-m01-vc01.sfo.rainpole.io".

        .PARAMETER vCenterServer
        The vCenter Server FQDN.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vCenterServer
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("vCenterServer")) {
            $uri = "https://$nsxtManager/api/v1/fabric/compute-managers"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results
        } elseif ($PsBoundParameters.ContainsKey("vCenterServer")) {
            $uri = "https://$nsxtManager/api/v1/fabric/compute-managers"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $responseChecked = $response.results | Where-Object { $_.server -eq $vCenterServer }

            if (!$responseChecked) {
                Write-Output "Compute Manager $vCenterServer was not found."
            } elseif ($responseChecked) {
                $responseChecked
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtComputeManager

Function Set-NsxtComputeManager {
    <#
        .SYNOPSIS
        Configure a set of parameters on a compute manager.

        .DESCRIPTION
        The Set-NsxtComputeManager cmdlet configures a set of parameters on a compute manager

        .EXAMPLE
        Get-NsxtComputeManager -vCenterServer sfo-w01-vc01.sfo.rainpole.io | Set-NsxtComputeManager -EnableTrust:$true
        This example enables trust (sets OIDC provider to true) for Compute Manager sfo-w01-vc01.sfo.rainpole.io
        In this release, it is required to use pipeline input from Get-NsxtComputeManager.

        .PARAMETER EnableTrust
        Enable trust (sets OIDC provider to true) for Compute Manager.

        .PARAMETER inputObject
        The input object from Get-NsxtComputeManager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Bool]$EnableTrust,
        [Parameter (ValueFromPipeline, Mandatory = $true)] [psObject]$inputObject
    )

    # Validating pipeline input resource_type
    if ($inputObject.resource_type -ne "ComputeManager") {
        Write-Error "Invalid pipeline passthrough."
        Break
    } elseif ($inputObject.resource_type -eq "ComputeManager") {
        $computeManagerId = $inputObject.id
        $computeManagerDisplayName = $inputObject.display_name
        $computeManagerRevision = $inputObject._revision
        $computeManagerFqdn = $inputObject.server
        $computeManagerOriginType = $inputObject.origin_type
        $computeManagerSetAsOidcProvider = $inputObject.set_as_oidc_provider
        $computeManagerCredentialType = $inputObject.credential.credential_type
        $computeManagerCredentialThumbprint = $inputObject.credential.thumbprint
    }

    if ($EnableTrust -eq $computeManagerSetAsOidcProvider) {
        Write-Error -Message "Compute Manager trust is already set to $EnableTrust."
        Break
    }

    $json = @"
{
"_revision" : $computeManagerRevision,
"server" : "$computeManagerFqdn",
"display_name" : "$computeManagerDisplayName",
"origin_type" : "$computeManagerOriginType",
"set_as_oidc_provider" : "$EnableTrust",
"credential" :
{
    "credential_type" : "$computeManagerCredentialType",
    "thumbprint" : "$computeManagerCredentialThumbprint"
}
}
"@


    Try {
        $uri = "https://$nsxtManager/api/v1/fabric/compute-managers/$computeManagerId"
        $response = Invoke-RestMethod -Method PUT -URI $uri -ContentType application/json -body $json -headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtComputeManager

Function Get-NsxtVidm {
    <#
        .SYNOPSIS
        Get Identity Manager configuration.

        .DESCRIPTION
        The Get-NsxtVidm cmdlet gets the Identity Manager configuration

        .EXAMPLE
        Get-NsxtVidm
        This example gets the Identity Manager configuration.
    #>


    Try {
        $uri = "https://$nsxtManager/api/v1/node/aaa/providers/vidm"
        Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtVidm

Function Set-NsxtVidm {
    <#
        .SYNOPSIS
        Set Identity Manager configuration.

        .DESCRIPTION
        The Set-NsxtVidm cmdlet configures Identity Manager in NSX Manager

        .EXAMPLE
        Set-NsxtVidm
        This example configures the Identity Manager in NSX Manager.

        .PARAMETER wsaHostname
        The Workspace ONE Access hostname.

        .PARAMETER thumbprint
        The Workspace ONE Access thumbprint.

        .PARAMETER clientId
        The Workspace ONE Access client ID.

        .PARAMETER sharedSecret
        The Workspace ONE Access shared secret.

        .PARAMETER nsxHostname
        The NSX Manager hostname.

        .PARAMETER disable
        Disable the Identity Manager configuration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wsaHostname,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$thumbprint,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$clientId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sharedSecret,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxHostname,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$disable
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/node/aaa/providers/vidm"
        if ($PsBoundParameters.ContainsKey("disable")) {
            $status = "false"
        } else {
            $status = "true"
        }
        $body = '{
            "lb_enable": false,
            "vidm_enable": '
 + $status + ',
            "host_name": "'
 + $wsaHostname + '",
            "thumbprint": "'
 + $thumbprint + '",
            "client_id": "'
 + $clientId + '",
            "client_secret": "'
 + $sharedSecret + '",
            "node_host_name": "'
 + $nsxHostname + '"
        }'

        $response = Invoke-RestMethod $uri -Method 'PUT' -Headers $nsxtHeaders -body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtVidm

Function Get-NsxtLdap {
    <#
        .SYNOPSIS
        Get LDAP configuration.

        .DESCRIPTION
        The Get-NsxtLdap cmdlet gets the LDAP configuration

        .EXAMPLE
        Get-NsxtLdap
        This example retrives a list of all configure LDAP identiry sources

        .EXAMPLE
        Get-NsxtLdap -id sfo
        This example retrives the details of a one LDAP identity source.

        .PARAMETER id
        The LDAP identity source ID.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtManager/policy/api/v1/aaa/ldap-identity-sources/$id"
            Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        } else {
            $uri = "https://$nsxtManager/policy/api/v1/aaa/ldap-identity-sources"
            (Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders).results
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtLdap

Function New-NsxtLdap {
    <#
        .SYNOPSIS
        Add an LDAP identity source.

        .DESCRIPTION
        The New-NsxtLdap cmdlet adds an LDAP identity source

        .EXAMPLE
        New-NsxtLdap -dcMachineName dc-sfo01 -protocol LDAPS -startTtls false -domain sfo.rainpole.io -baseDn "ou=Security Users,dc=sfo,dc=rainpole,dc=io" -bindUser svc-nsx-ad@sfo.rainpole.io -bindPassword VMw@re1! -certificate Root64.cer
        This example create an Active Directory Identity Source over LDAPS

        .EXAMPLE
        New-NsxtLdap -dcMachineName dc-sfo01 -protocol LDAP -startTtls false -domain sfo.rainpole.io -baseDn "ou=Security Users,dc=sfo,dc=rainpole,dc=io" -bindUser svc-nsx-ad@sfo.rainpole.io -bindPassword VMw@re1!
        This example create an Active Directory Identity Source over LDAP.

        .PARAMETER dcMachineName
        The domain controller machine name.

        .PARAMETER protocol
        The protocol to use (LDAP or LDAPS).

        .PARAMETER startTtls
        Start TLS.

        .PARAMETER domain
        The domain name.

        .PARAMETER baseDn
        The base DN.

        .PARAMETER bindUser
        The bind user.

        .PARAMETER bindPassword
        The bind password.

        .PARAMETER certificate
        The certificate file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$dcMachineName,
        [Parameter (Mandatory = $true)] [ValidateSet("LDAP", "LDAPS")] [String]$protocol,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$startTtls,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$baseDn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$bindPassword,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificate
    )

    if (!$PsBoundParameters.ContainsKey("certificate") -and ($protocol -eq "LDAPS")) {
        $certificate = Get-ExternalFileName -title "Select the Root CA Certificate File (.cer)" -fileType "cer" -location "default"
    } elseif ($protocol -eq "LDAPS") {
        if (!(Test-Path -Path $certificate)) {
            Write-Error  "Certificate (cer) for Root Certificate Authority '$certificate' File Not Found"
            Break
        }
    }

    if ($protocol -eq "LDAPS") {
        $primaryUrl = 'LDAPS://' + $dcMachineName + '.' + $domain + ':636'
        $certdata = (Get-Content ($certificate)) -join "\n"
    } elseif ($protocol -eq "LDAP") {
        $primaryUrl = 'LDAP://' + $dcMachineName + '.' + $domain + ':389'
    }

    Try {
        $body = '{
            "resource_type": "ActiveDirectoryIdentitySource",
            "ldap_servers": [
                {
                    "url": "'
 + $primaryUrl + '",
                    "use_starttls": false,
                    "certificates": [
                        "'
 + $certdata + '"
                    ],
                    "bind_identity": "'
 + $bindUser + '",
                    "password": "'
 + $bindPassword + '",
                    "enabled": true
                }
            ],
            "display_name": "'
 + $domain + '",
            "domain_name": "'
 + $domain + '",
            "base_dn": "'
 + $baseDn + '"
        }'

        $uri = "https://$nsxtManager/policy/api/v1/aaa/ldap-identity-sources/$domain"
        Invoke-RestMethod $uri -Method 'PUT' -Headers $nsxtHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLdap

Function Remove-NsxtLdap {
    <#
        .SYNOPSIS
        Delete LDAP identity source.

        .DESCRIPTION
        The Remove-NsxtLdap cmdlet removes an LDAP identity source

        .EXAMPLE
        Remove-NsxtLdap -id sfo.rainpole.io
        This example deletes an LDAP identity source.

        .PARAMETER id
        The LDAP identity source ID.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/policy/api/v1/aaa/ldap-identity-sources/$id"
        Invoke-RestMethod $uri -Method 'DELETE' -Headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtLdap

Function Get-NsxtLdapStatus {
    <#
        .SYNOPSIS
        Get LDAP configuration status.

        .DESCRIPTION
        The Get-NsxtLdapStatus cmdlet gets the LDAP configuration status

        .EXAMPLE
        Get-NsxtLdapStatus -id
        This example gets the configure status of an LDAP identiry source

        .PARAMETER id
        The LDAP identity source ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/policy/api/v1/aaa/ldap-identity-sources/" + $id + "?action=probe"
        (Invoke-RestMethod $uri -Method 'POST' -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtLdapStatus
Function Get-NsxtPrincipalIdentity {
    <#
        .SYNOPSIS
        Get list of NSX Principal Identities
    
        .DESCRIPTION
        The Get-NsxtPrincipalIdentity cmdlet gets a list of NSX Principal Identities
    
        .EXAMPLE
        Get-NsxtPrincipalIdentity
        This example gets a list of NSX Principal Identities

        .EXAMPLE
        Get-NsxtPrincipalIdentity -principalId <principal_id>
        This example get an NSX Principal Identity by its Id.

        .EXAMPLE
        Get-NsxtPrincipalIdentity -name svc-iom-sfo-m01-nsx
        This example get an NSX Principal Identity by its name.

        .PARAMETER principalId
        The NSX Principal Identity ID.

        .PARAMETER name
        The NSX Principal Identity name.
    #>


    Param (
        [Parameter (Mandatory=$false)] [ValidateNotNullOrEmpty()] [String]$principalId,
        [Parameter (Mandatory=$false)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtmanager/policy/api/v1/trust-management/principal-identities/$principalId"
            Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
        } elseif ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtmanager/policy/api/v1/trust-management/principal-identities"
            (Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders).results | Where-Object {$_.name -eq $name}
        } else {
            $uri = "https://$nsxtmanager/policy/api/v1/trust-management/principal-identities"
            (Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders).results
        
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtPrincipalIdentity

Function New-NsxtPrincipalIdentity {
    <#
        .SYNOPSIS
        Add an NSX Principal Identity.

        .DESCRIPTION
        The New-NsxtPrincipalIdentity cmdlet adds an NSX Princial Identity

        .EXAMPLE
        New-NsxtPrincipalIdentity -name svc-iom-sfo-m01-nsx -nodeId sfo-m01-nsx01 -role enterprise_admin -certificateData ./sfo-m01-nsx01.cer
        This example adds an NSX Princial Identity.

        .PARAMETER name
        The NSX Principal Identity name.

        .PARAMETER nodeId
        The NSX Manager node ID.

        .PARAMETER role
        The NSX Principal Identity role.

        .PARAMETER certificateData
        The NSX Principal Identity certificate.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nodeId,
        [Parameter (Mandatory = $true)] [ValidateSet("lb_admin", "security_engineer", "vpn_admin", "network_op", "netx_partner_admin", "gi_partner_admin", "security_op", "network_engineer", "lb_auditor", "auditor", "enterprise_admin")] [String]$role,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateData
    )
    
    Try {
        if ($PSBoundParameters.ContainsKey('certificateData')) {
            if (!(Test-Path -Path $certificateData)) {
                Write-Error  "Certificate (cer) for NSX Credential '$certificateData' File Not Found"
                Break
            } else {
                $Global:dataFile = (Get-Content ($certificateData)) -join "\n"
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }

    Try {
        $Global:body = '{
            "name": "'
+ $name + '",
            "node_id": "'
+ $nodeId + '",
            "role": "'
+ $role + '",
            "certificate_pem": "'
+ $dataFile + '"
        }'

        $uri = "https://$nsxtmanager/policy/api/v1/trust-management/principal-identities/with-certificate"
        Invoke-RestMethod -Method POST -URI $uri -ContentType application/json -headers $nsxtHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtPrincipalIdentity

Function Set-NsxtPrincipalIdentityCertificate {
    <#
        .SYNOPSIS
        Update the certificate of the NSX Principal Identity
    
        .DESCRIPTION
        The Set-NsxtPrincipalIdentityCertificate cmdlet updates the certificate of the NSX Principal Identity
    
        .EXAMPLE
        Set-NsxtPrincipalIdentityCertificate -principalId <principal_id> -certificateId <certificate_id>
        This example updates the certificate of the NSX Principal Identity.

        .PARAMETER principalId
        The NSX Principal Identity ID.

        .PARAMETER certificateId
        The NSX Principal Identity certificate ID.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$principalId,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$certificateId
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/trust-management/principal-identities?action=update_certificate"
        $body = '{
            "principal_identity_id": "'
+ $principalId + '",
            "certificate_id": "'
+ $certificateId + '"
        }'

        Invoke-RestMethod -Method POST -URI $uri -ContentType application/json -headers $nsxtHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtPrincipalIdentity

Function Remove-NsxtPrincipalIdentity {
    <#
        .SYNOPSIS
        Delete an NSX Principal Identity
    
        .DESCRIPTION
        The Remove-NsxtPrincipalIdentity cmdlet deletes an NSX Principal Identity
    
        .EXAMPLE
        Remove-NsxtPrincipalIdentity -principalId <principal_id>
        This example deletes an NSX Principal Identity.

        .PARAMETER principalId
        The NSX Principal Identity ID.
    #>


    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$principalId
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/trust-management/principal-identities/$principalId"
        Invoke-RestMethod -Method DELETE -URI $uri -ContentType application/json -headers $nsxtHeaders 
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtPrincipalIdentity

Function Get-NsxtRole {
    <#
        .SYNOPSIS
        Gets NSX Manager roles.

        .DESCRIPTION
        The Get-NsxtRole cmdlet gets the roles in NSX Manager

        .EXAMPLE
        Get-NsxtRole
        This example gets all roles in NSX Manager.
    #>


    Try {
        $uri = "https://$nsxtManager/api/v1/aaa/roles"
        (Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtRole

Function Set-NsxtRole {
    <#
        .SYNOPSIS
        Adds a role to a user/group.

        .DESCRIPTION
        The Set-NsxtRole cmdlet assigns users/groups to roles

        .EXAMPLE
        Set-NsxtRole -principal "gg-nsx-enterprise-admins@sfo.rainpole.io" -type remote_group -role enterprise_admin -identitySource LDAP -domain sfo.rainpole.io
        This example assigned the Enterprise Admin role to usee from LDAP Identity Provider

        .EXAMPLE
        Set-NsxtRole -principal "gg-nsx-enterprise-admins@sfo.rainpole.io" -type remote_group -role enterprise_admin -identitySource VIDM
        This example assigned the Enterprise Admin role to usee from Workspace ONE Access Identity Provider.

        .PARAMETER principal
        The user/group principal.

        .PARAMETER type
        The type of principal (remote_group or remote_user).

        .PARAMETER role
        The role to assign.

        .PARAMETER identitySource
        The identity source (LDAP, VIDM, OIDC).

        .PARAMETER domain
        The domain name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$principal,
        [Parameter (Mandatory = $true)] [ValidateSet("remote_group", "remote_user")] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateSet("lb_admin", "security_engineer", "vpn_admin", "network_op", "netx_partner_admin", "gi_partner_admin", "security_op", "network_engineer", "lb_auditor", "auditor", "enterprise_admin")] [String]$role,
        [Parameter (Mandatory = $true)] [ValidateSet("LDAP", "VIDM", "OIDC")] [String]$identitySource,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domain
    )

    Try {
        if ($PsBoundParameters.ContainsKey("identitySource") -eq "LDAP") {
            $identitySourceId = (Get-NsxtLdap | Where-Object { $_.domain_name -eq $domain }).id
            $body = '{
                "name": "'
 + $principal + '",
                "type": "'
 + $type + '",
                "identity_source_type": "'
 + $identitySource + '",
                "identity_source_id": "'
 + $identitySourceId + '",
                "roles": [
                        {
                            "role": "'
 + $role + '"
                        }
                    ]
                }'

        } else {
            $body = '{
                "name": "'
 + $principal + '",
                "type": "'
 + $type + '",
                "identity_source_type": "'
 + $identitySource + '"
                "roles": [
                        {
                            "role": "'
 + $role + '"
                        }
                    ]
                }'

        }
        $uri = "https://$nsxtManager/api/v1/aaa/role-bindings"
        Invoke-RestMethod $uri -Method 'POST' -Headers $nsxtHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtRole

Function Remove-NsxtRole {
    <#
        .SYNOPSIS
        Delete a user/group role assignment.

        .DESCRIPTION
        The Remove-NsxtRole cmdlet removes a user/group role in NSX Manager

        .EXAMPLE
        Remove-NsxtRole -id
        This example removes the role for the user/group based on the id.

        .PARAMETER id
        The role ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/aaa/role-bindings/$id"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtRole

Function Get-NsxtUser {
    <#
        .SYNOPSIS
        Gets all users and groups.

        .DESCRIPTION
        The Get-NsxtUser cmdlet gets all users and groups in NSX Manager

        .EXAMPLE
        Get-NsxtUser
        This example gets all users and grops in NSX Manager.
    #>


    Try {
        $uri = "https://$nsxtManager/api/v1/aaa/role-bindings"
        (Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtUser

Function Get-NsxtVidmUser {
    <#
        .SYNOPSIS
        Gets Identity Manager users.

        .DESCRIPTION
        The Get-NsxtVidmUser cmdlet gets all Identity Manager users from NSX Manager

        .EXAMPLE
        Get-NsxtVidmUser -searchString svc
        This example gets all Identity Manager users starting with 'svc' from NSX Manager.

        .PARAMETER searchString
        The search string.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateLength(3, 255)] [String]$searchString
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/aaa/vidm/users?search_string=$searchString"
        (Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtVidmUser

Function Get-NsxtVidmGroup {
    <#
        .SYNOPSIS
        Gets Identity Manager groups.

        .DESCRIPTION
        The Get-NsxtVidmGroup cmdlet gets all Identity Manager groups from NSX Manager

        .EXAMPLE
        Get-NsxtVidmGroup -searchString gg-
        This example gets all Identity Manager groups starting with gg- from NSX Manager.

        .PARAMETER searchString
        The search string.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateLength(3, 255)] [String]$searchString
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/aaa/vidm/groups?search_string=$searchString"
        (Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtVidmGroup

Function Get-NsxEdgeCluster {
    <#
        .SYNOPSIS
        Retrieves NSX Edge Cluster(s).

        .DESCRIPTION
        The Get-NsxtEdgeCluster cmdlet retrieves NSX Edge Cluster(s)

        .EXAMPLE
        Get-NsxtEdgeCluster
        This example returns any NSX Edge Clusters

        .EXAMPLE
        Get-NsxtEdgeCluster -Name "sfo-w01-ec01"
        This example returns any NSX Edge Clusters.

        .PARAMETER Name
        The NSX Edge Cluster name.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$Name
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("Name")) {
            $uri = "https://$nsxtmanager/api/v1/edge-clusters"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results
        } elseif ($PsBoundParameters.ContainsKey("Name")) {
            $uri = "https://$nsxtmanager/api/v1/edge-clusters"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $responseChecked = $response.results | Where-Object { $_.display_name -eq $Name }

            if (!$responseChecked) {
                Write-Output "NSX Edge Cluster $Name was not found."
            } elseif ($responseChecked) {
                $responseChecked
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxEdgeCluster

Function Get-NsxtTransportZone {
    <#
        .SYNOPSIS
        Get a list of Transport Zones.

        .DESCRIPTION
        The Get-NsxtTransportZone cmdlet retrieves a list of Transport Zones

        .EXAMPLE
        Get-NsxtTransportZone
        This example gets all Transport Zones

        .EXAMPLE
        Get-NsxtTransportZone -name overlay-tz-sfo-w01-nsx01.sfo.rainpole.io
        This example gets the Transport Zone with the name "overlay-tz-sfo-w01-nsx01.sfo.rainpole.io".

        .PARAMETER name
        The Transport Zone name.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtManager/policy/api/v1/infra/sites/default/enforcement-points/default/transport-zones"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results | Sort-Object display_name
        } elseif ($PsBoundParameters.ContainsKey("Name")) {
            $uri = "https://$nsxtManager/policy/api/v1/infra/sites/default/enforcement-points/default/transport-zones"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $responseChecked = $response.results | Where-Object { $_.display_name -eq $name }

            if (!$responseChecked) {
                Write-Output "NSX Transport Zone $name was not found"
            } elseif ($responseChecked) {
                $responseChecked
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTransportZone

Function New-NsxtSegment {
    <#
        .SYNOPSIS
        Create a new NSX Segment.

        .DESCRIPTION
        The New-NsxtSegment cmdlet creates NSX Segments

        .EXAMPLE
        New-NsxtSegment -Name "sfo-w01-xreg-seg01" -GatewayType "Tier1" -ConnectedGateway "sfo-w01-ec01-t1-gw01" -Cidr "192.168.31.1/24" -TransportZone "overlay-tz-sfo-w01-nsx01.sfo.rainpole.io"
        This example creates an NSX Overlay Segment with the name "sfo-w01-xreg-seg01", connected to Tier-1 gateway "sfo-w01-ec01-t1-gw01", Transport Zone "overlay-tz-sfo-w01-nsx01.sfo.rainpole.io", and CIDR address of "192.168.31.1/24".

        .PARAMETER Name
        The NSX Segment name.

        .PARAMETER ConnectedGateway
        The NSX Gateway name.

        .PARAMETER Cidr
        The CIDR address.

        .PARAMETER TransportZone
        The NSX Transport Zone name.

        .PARAMETER GatewayType
        The NSX Gateway type (Tier0 or Tier1).

        .PARAMETER SegmentType
        The NSX Segment type (Overlay or VLAN).

        .PARAMETER VlanId
        The NSX VLAN ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$Name,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ConnectedGateway,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$Cidr,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$TransportZone,
        [Parameter (Mandatory = $false)] [ValidateSet("Tier0", "Tier1")] [String]$GatewayType,
        [Parameter (Mandatory = $true)] [ValidateSet("Overlay", "VLAN")] [String]$SegmentType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$VlanId
    )

    if ($GatewayType -eq "Tier0") {
        $connectivityPath = (Get-NsxtTier0Gateway -Name $ConnectedGateway).path
    } elseif ($GatewayType -eq "Tier1") {
        $connectivityPath = (Get-NsxtTier1Gateway -Name $ConnectedGateway).path
    } elseif (!$GatewayType -and $VlanId) {
        Write-Output "Valid VLAN segment configuration"
    } else {
        Write-Error "Gateway type not defined"
    }
    $transportZonePath = (Get-NsxtTransportZone -Name $TransportZone).path
    if ($SegmentType -match "overlay") {
        $json = @"
{
"display_name" : "$Name",
"subnets" : [{ "gateway_address" : "$Cidr" }],
"connectivity_path" : "$connectivityPath",
"transport_zone_path" : "$transportZonePath"
}
"@

    } elseif ($SegmentType -match "vlan") {
        $json = @"
{
"display_name" : "$Name",
"vlan_ids" : [ "$VlanId" ],
"transport_zone_path" : "$transportZonePath"
}
"@

    } else {
        Write-Error "SegmentType $SegmentType is invalid."
    }

    Try {
        $uri = "https://$nsxtManager/policy/api/v1/infra/segments/$Name"
        $response = Invoke-WebRequest -Method PATCH -URI $uri -ContentType application/json -Body $json -headers $nsxtHeaders
        if ($response.StatusCode -eq 200 -or $response.StatusCode -eq 204) {
            Write-Output "NSX Segment $Name successfully created."
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtSegment

Function Get-NsxtSegment {
    <#
        .SYNOPSIS
        Get a list of Segments.

        .DESCRIPTION
        The Get-NsxtSegment cmdlet retrieves a list of Segments

        .EXAMPLE
        Get-NsxtSegment
        This example gets all Segments

        .EXAMPLE
        Get-NsxtSegment -name sfo-w01-kub-seg01
        This example gets the segment with the name sfo-w01-kub-seg01.

        .PARAMETER name
        The Segment name.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtManager/policy/api/v1/infra/segments/"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results | Sort-Object display_name
        } elseif ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtManager/policy/api/v1/infra/segments/"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results | Where-Object { $_.display_name -eq $name }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtSegment

Function Remove-NsxtSegment {
    <#
        .SYNOPSIS
        Removes a named Segment.

        .DESCRIPTION
        The Remove-NsxtSegment cmdlet removes a named segment.

        .EXAMPLE
        Remove-NsxtSegment -name sfo-w01-kub-seg01
        This example removes the segment with the name sfo-w01-kub-seg01.

        .PARAMETER name
        The Segment name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        $uri = "https://$nsxtManager/policy/api/v1/infra/segments/$Name"
        $response = Invoke-RestMethod -Method DELETE -URI $uri -ContentType application/json -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtSegment

Function Get-NsxtTier0Gateway {
    <#
        .SYNOPSIS
        Get a list of Tier 0 Gateways.

        .DESCRIPTION
        The Get-NsxtTier0 cmdlet retrieves a list of Tier 0 Gateways

        .EXAMPLE
        Get-NsxtTier0Gateway
        This example returns all Tier 0 Gateways

        .EXAMPLE
        Get-NsxtTier0Gateway -name sfo-w01-ec01-t0-gw01
        This example returns the Tier 0 Gateway named sfo-w01-ec01-t0-gw01

        .EXAMPLE
        Get-NsxtTier0Gateway -id 84a6c7a5-9fe8-4446-8684-814663399584
        This example returns the Tier 0 Gateway based on its id.

        .PARAMETER name
        The Tier 0 Gateway name.

        .PARAMETER id
        The Tier 0 Gateway id.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("name") -and !$PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-0s"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results
        } elseif ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-0s/$id"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-0s"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results | Where-Object { $_.display_name -eq $name }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTier0Gateway

Function Get-NsxtTier1Gateway {
    <#
        .SYNOPSIS
        Get a list of Tier 1 Gateways.

        .DESCRIPTION
        The Get-NsxtTier1Gateway cmdlet retrieves a list of Tier 1 Gateways

        .EXAMPLE
        Get-NsxtTier1Gateway
        This example returns all Tier 1 Gateways

        .EXAMPLE
        Get-NsxtTier1Gateway -name sfo-w01-ec01-t1-gw01
        This example returns the Tier 1 Gateway named sfo-w01-ec01-t1-gw01

        .EXAMPLE
        Get-NsxtTier1Gateway -id 84a6c7a5-9fe8-4446-8684-814663399584
        This example returns the Tier 1 Gateway based on its id.

        .PARAMETER name
        The Tier 1 Gateway name.

        .PARAMETER id
        The Tier 1 Gateway id.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ( -not $PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results
        } elseif ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s/$id"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results | Where-Object { $_.display_name -eq $name }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTier1Gateway

Function Get-NsxtPrefixList {
    <#
        .SYNOPSIS
        Get Tier-0 Gateway IP Prefix Lists.

        .DESCRIPTION
        The Get-NsxtTier0PrefixList cmdlet retrieves the IP Prefix Lists assigned to a Tier-0 Gateway

        .EXAMPLE
        Get-NsxtPrefixList -tier0Gateway sfo-w01-ec01-t0-gw01
        This example returns all IP Prefix Lists

        .EXAMPLE
        Get-NsxtPrefixList -tier0Gateway sfo-w01-ec01-t0-gw01 -name sfo-w01-cl01-prefix-list
        This example returns the IP Prefix List based on the prefix name provided

        .EXAMPLE
        Get-NsxtTier0Gateway -name sfo-w01-ec01-t0-gw01 | Get-NsxtPrefixList -name sfo-w01-cl01-prefix-list
        This example returns the IP Prefix List based on the prefix name provided.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER name
        The IP Prefix List name.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tier0Gateway,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    # Validating pipeline input resource_type
    if ($inputObject -and $inputObject.resource_type -eq "Tier0") {
        $tier0Gateway = $inputObject.display_name
        $uriPath = $inputObject.path
    } elseif ($inputObject -and $inputObject.resource_type -ne "Tier0") {
        Write-Error "Invalid pipeline passthrough. Exiting."
        Break
    } elseif (!$inputObject -and $Tier0Gateway) {
        $uriPath = (Get-NsxtTier0Gateway -Name $Tier0Gateway).path
    } else {
        if (!$tier0Gateway) {
            $tier0Gateway = Read-Host -Prompt "Tier-0 Gateway not defined. Type in the name of your Tier-0 Gateway, then press Enter"
        }
    }

    Try {
        if (!$name) {
            $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/prefix-lists"
            $response = Invoke-RestMethod -Method GET -URI $uri -headers $nsxtHeaders -ErrorAction SilentlyContinue
            $response.results
        } elseif ($name) {
            $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/prefix-lists"
            $response = Invoke-RestMethod -Method GET -URI $uri -headers $nsxtHeaders -ErrorAction SilentlyContinue
            $response.results | Where-Object { $_.display_name -eq $name }
        }
    } Catch {
        if ($_.Exception -match "400" -or $_.Exception -match "Bad Request") {
            Write-Output $uri
            Write-Error "The NSX Tier-0 Gateway was not properly defined"
        }
    }
}
Export-ModuleMember -Function Get-NsxtPrefixList

Function New-NsxtPrefixList {
    <#
        .SYNOPSIS
        Creates a Tier-0 Gateway IP Prefix List.

        .DESCRIPTION
        The New-NsxtPrefixList cmdlet creates a Prefix List on a specified Tier-0 Gateway

        .EXAMPLE
        New-NsxtPrefixList -name sfo-w01-cl01-prefix-list -tier0Gateway sfo-w01-ec01-t0-gw01 -subnetCIDR 192.168.20.0/24 -action PERMIT
        This example creates a new IP Prefix List on a Tier 0 Gateway.

        .PARAMETER name
        The IP Prefix List name.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER subnetCIDR
        The subnet CIDR.

        .PARAMETER GE
        The greater than or equal to value.

        .PARAMETER LE
        The less than or equal to value.

        .PARAMETER action
        The action (PERMIT or DENY).

        .PARAMETER json
        The JSON body.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$name,
        [Parameter (Mandatory = $false)] [String]$tier0Gateway,
        [Parameter (Mandatory = $false)] [String]$subnetCIDR,
        [Parameter (Mandatory = $false)] [String]$GE,
        [Parameter (Mandatory = $false)] [String]$LE,
        [Parameter (Mandatory = $false)] [ValidateSet("PERMIT", "DENY")] [String]$action,
        [Parameter (Mandatory = $false)] [String]$json,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    # Validating pipeline input resource_type
    if ($inputObject -and $inputObject.resource_type -eq "Tier0") {
        $uriPath = $inputObject.path
        $Tier0Gateway = $inputObject.display_name
    } elseif ($inputObject -and $inputObject.resource_type -ne "Tier0") {
        Write-Error "Invalid pipeline passthrough. Exiting."
        Break
    } elseif (!$inputObject) {
        if (!$Tier0Gateway) {
            $Tier0Gateway = Read-Host -Prompt "Tier-0 Gateway not defined. Type in the name of your Tier-0 Gateway, then press Enter"
            $uriPath = (Get-NsxtTier0Gateway -Name $Tier0Gateway).path
        }
    }
    if (!$json) {
        if (!$GE -or !$LE) {
            $Json = @"
{
    "display_name" : "$Name",
    "prefixes" :
    [
        {
        "network" : "$SubnetCIDR",
        "action" : "$Action"
        }
    ]
}
"@

        } elseif ($GE -and $LE) {
            $Json = @"
{
    "display_name" : "$Name",
    "prefixes" :
    [
        {
        "network" : "$SubnetCIDR",
        "action" : "$Action",
        "ge" : "$GE",
        "le" : "$LE"
        }
    ]
}
"@

        } else {
            Write-Error "Invalid subnet configuration."
        }
    }

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/prefix-lists/$name"
        $response = Invoke-RestMethod -Method PUT -URI $uri -ContentType application/json -body $json -headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtPrefixList

Function Remove-NsxtPrefixList {
    <#
        .SYNOPSIS
        Remove an IP Prefix List from a Tier-0 Gateway.

        .DESCRIPTION
        The Remove-NsxtPrefixList cmdlet removes a IP Prefix List from a specified Tier-0 Gateway

        .EXAMPLE
        Remove-NsxtPrefixList -name sfo-w01-cl01-prefix-list -tier0Gateway sfo-w01-ec01-t0-gw01
        This example removes a Prefix List on a Tier 0 Gateway.

        .PARAMETER name
        The IP Prefix List name.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tier0Gateway
    )

    Try {
        $gatewayId = (Get-NsxtTier0Gateway -name $tier0Gateway).id
        $uri = "https://$nsxtManager/policy/api/v1/infra/tier-0s/$gatewayId/prefix-lists/$name"
        $response = Invoke-RestMethod -Method DELETE -URI $uri -ContentType application/json -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtPrefixList

Function Add-NsxtPrefix {
    <#
        .SYNOPSIS
        Add a single entry to an existing NSX IP Prefix List.

        .DESCRIPTION
        The Add-NsxtPrefix cmdlet adds a single entry to an existing NSX IP Prefix List

        .EXAMPLE
        Get-NsxtPrefixList -name sfo-w01-cl01-prefix-list | Add-NsxtPrefix -subnetCIDR 192.168.21.0/24 -LE 32 -GE 28 -action PERMIT
        This example adds an IP Prefix entry on an existing IP Prefix List.

        .PARAMETER prefixListName
        The IP Prefix List name.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER subnetCIDR
        The subnet CIDR.

        .PARAMETER GE
        The greater than or equal to value.

        .PARAMETER LE
        The less than or equal to value.

        .PARAMETER action
        The action (PERMIT or DENY).

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$prefixListName,
        [Parameter (Mandatory = $false)] [String]$tier0Gateway,
        [Parameter (Mandatory = $false)] [String]$subnetCIDR,
        [Parameter (Mandatory = $false)] [String]$GE,
        [Parameter (Mandatory = $false)] [String]$LE,
        [Parameter (Mandatory = $false)] [String]$action,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    if (!$inputObject -and $tier0Gateway -and $prefixListName) {
        $uriPath = (Get-NsxtTier0Gateway -Name $tier0Gateway).path
        $existingPrefixes = (Get-NsxtPrefixList -Name $prefixListName -Tier0Gateway $tier0Gateway).prefixes
    }

    if ($inputObject -and $inputObject.resource_type -eq "PrefixList") {
        $uriPath = $inputObject.parent_path
        $Tier0GatewayId = $inputObject.parent_path.Split('/')[3]
        $PrefixListName = $inputObject.display_name
        $existingPrefixes = $inputObject.prefixes

        $getTier0Gateway = Get-NsxtTier0Gateway -name $tier0GatewayId -ErrorAction SilentlyContinue

        if ($getTier0Gateway -eq "NSX Tier-0 Gateway $tier0GatewayId was not found") {
            $tier0Gateway = (Get-NsxtTier0Gateway -Id $tier0GatewayId).display_name
        } else {
            $Tier0Gateway = $Tier0GatewayId
        }
    } elseif ($inputObject -and $inputObject.resource_type -ne "PrefixList") {
        Write-Error "Invalid pipeline passthrough"
        Break
    }

    $prefixes = @()
    $prefixes += $existingPrefixes
    if (!$GE -or !$LE) {
        $newPrefix = @{
            network = $subnetCIDR
            action  = $action
        }
    } elseif ($GE -and $LE) {
        $newPrefix = @{
            network = $subnetCIDR
            action  = $action
            ge      = $GE
            le      = $LE
        }
    } else {
        Write-Error "Invalid subnet configuration"
    }

    $prefixes += $newPrefix
    $prefixesJson = $prefixes | ConvertTo-Json
    $json = @"
    {
        "display_name": "$PrefixListName",
        "prefixes": $prefixesJson
    }
"@


    Try {
        $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/prefix-lists/$PrefixListName"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -body $json -headers $nsxtHeaders
        $response

        if (!$response) {
            $output = Get-NsxtPrefixList -Name $PrefixListName -Tier0Gateway $Tier0Gateway
            $output
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-NsxtPrefix

Function Get-NsxtRouteMap {
    <#
        .SYNOPSIS
        Get Tier-0 Gateway Route Maps.

        .DESCRIPTION
        The Get-NsxtRouteMap cmdlet retrieves the Route Maps assigned to a specified Tier-0 Gateway

        .EXAMPLE
        Get-NsxtRouteMap -tier0Gateway sfo-w01-ec01-t0-gw01
        This example gets all Route Maps on the Tier-0 Gateway

        .EXAMPLE
        Get-NsxtRouteMap -tier0Gateway sfo-w01-ec01-t0-gw01 -name sfo-w01-ec01-t0-gw01-routemap
        This example gets a specific route map by name from the Tier-0 Gateway.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER name
        The Route Map name.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$tier0Gateway,
        [Parameter (Mandatory = $false)] [String]$name,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    # Validating pipeline input resource_type
    if ($inputObject -and $inputObject.resource_type -eq "Tier0") {
        $tier0Gateway = $inputObject.display_name
        $uriPath = $inputObject.path
    } elseif ($inputObject -and $inputObject.resource_type -ne "Tier0") {
        Write-Error "Invalid pipeline passthrough. Exiting."
        Break
    } elseif (!$inputObject) {
        if (!$tier0Gateway) {
            Write-Output "Tier 0 Gateway: $Tier0Gateway"
            $Tier0Gateway = Read-Host -Prompt "Tier-0 Gateway not defined. Type in the name of your Tier-0 Gateway, then press Enter"
        }
        $uriPath = (Get-NsxtTier0Gateway -Name $tier0Gateway).path
    }

    Try {
        if (!$PsBoundParameters.ContainsKey("Name")) {
            $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/route-maps"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results
        } elseif ($PsBoundParameters.ContainsKey("Name")) {
            $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/route-maps"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results | Where-Object { $_.display_name -eq $Name }
        }
    } Catch {
        if ($_.Exception -match "400" -or $_.Exception -match "Bad Request") {
            Write-Error "The NSX Tier-0 Gateway was not properly defined."
        }
    }
}
Export-ModuleMember -Function Get-NsxtRouteMap

Function New-NsxtRouteMap {
    <#
        .SYNOPSIS
        Creates a Route Map on a specified Tier-0 Gateway.

        .DESCRIPTION
        The New-NsxtRouteMap cmdlet creates a Route Map on a specified Tier-0 Gateway

        .EXAMPLE
        New-NsxtRouteMap -Name sfo-w01-cl01-route-map -Tier0Gateway sfo-w01-ec01-t0-gw01 -PrefixList sfo-w01-ec01-prefix-list
        This example creates a new Route Map on a Tier-0 Gateway

        .EXAMPLE
        Net-NsxtTier0Gateway sfo-w01-ec01-t0-gw01 | Get-NsxtPrefixList -Name sfo-w01-ec01-prefix-list | New-NsxtRouteMap -Name sfo-w01-cl01-route-map
        This example creates a new Route Map on a Tier-0 Gateway.

        .PARAMETER name
        The Route Map name.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER prefixList
        The IP Prefix List name.

        .PARAMETER action
        The action (PERMIT or DENY).

        .PARAMETER json
        The JSON body.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$Name,
        [Parameter (Mandatory = $false)] [String]$Tier0Gateway,
        [Parameter (Mandatory = $false)] [String]$PrefixList,
        [Parameter (Mandatory = $false)] [String]$Action,
        [Parameter (Mandatory = $false)] [String]$Json,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    if ($inputObject) {
        if ($inputObject.resource_type -eq "Tier0") {
            $Tier0Gateway = $inputObject.display_name
            $Tier0GatewayId = $inputObject.id
            $uriPath = $inputObject.path
        } elseif ($inputObject.resource_type -eq "PrefixList") {
            $Tier0GatewayId = $inputObject.parent_path.Split('/')[3]
            $PrefixListPath = $inputObject.path
            $Tier0Gateway = (Get-NsxtTier0Gateway -Id $Tier0GatewayId).display_name
            $uriPath = $inputObject.parent_path
        } else {
            Write-Error "Invalid pipeline passthrough. Exiting."
            Break
        }
    } elseif (!$inputObject) {
        $uriPath = (Get-NsxtTier0Gateway -Name $Tier0Gateway).path
    }

    if (!$PrefixListPath) {
        $PrefixListPath = $uriPath + "/prefix-lists/" + $PrefixList
    }
    $json = @"
{
    "display_name" : "$Name",
    "entries" :
    [
        {
        "action" : "$Action",
        "prefix_list_matches" : [ "$prefixListPath" ]
        }
    ]
}
"@


    Try {
        $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/route-maps/$Name"
        $response = Invoke-RestMethod -Method PUT -URI $uri -ContentType application/json -body $json -headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtRouteMap

Function Remove-NsxtRouteMap {
    <#
        .SYNOPSIS
        Remove a Route Map from a specified Tier-0 Gateway.

        .DESCRIPTION
        The Remove-NsxtRouteMap cmdlet removes a Route Map attached to a specified Tier-0 Gateway

        .EXAMPLE
        Remove-NsxtRouteMap -name sfo-w01-ec01-t0-gw01-routemap -tier0Gateway sfo-w01-ec01-t0-gw01
        This example removes the Route Map sfo-w01-ec01-t0-gw01-routemap from Tier-0 Gateway sfo-w01-ec01-t0-gw01.

        .PARAMETER name
        The Route Map name.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$name,
        [Parameter (Mandatory = $false)] [String]$tier0Gateway,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    if ($inputObject) {
        if ($inputObject.resource_type -eq "Tier0RouteMap") {
            $Name = $inputObject.display_name
            $Tier0GatewayId = $inputObject.parent_path.Split('/')[3]
            $Tier0Gateway = (Get-NsxtTier0Gateway -Id $Tier0GatewayId).display_name
            $uriPath = $inputObject.parent_path
        } elseif ($inputObject.resource_type -eq "Tier0" -and $Name -and !$Tier0Gateway) {
            $Tier0GatewayId = $inputObject.id
            $Tier0Gateway = $inputObject.display_name
            $uriPath = $inputObject.path
        } else {
            Write-output $inputObject.resource_type
            Write-Error "Invalid pipeline passthrough. Exiting."
            Break
        }
    } elseif (!$inputObject) {
        if (!$tier0Gateway) {
            $tier0Gateway = Read-Host -Prompt "Tier-0 Gateway not defined. Type in the name of your Tier-0 Gateway, then press Enter"
        }
        $uriPath = (Get-NsxtTier0Gateway -Name $Tier0Gateway).path
    }

    Try {
        $getRouteRedistribution = Get-NsxtRouteRedistributionPolicy -tier0Gateway $tier0Gateway
        if ($getRouteRedistribution.route_redistribution_config.redistribution_rules.route_map_path -eq $preCheckRouteMap.path) {
            $getRouteRedistribution | Set-NsxtRouteRedistributionPolicy -tier0Gateway $tier0Gateway -RemoveRouteMap:$True | Out-Null
        }
    } Catch {
        Write-Error $_.Exception.Message
    }

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/route-maps/$name"
        $response = Invoke-RestMethod -Method DELETE -URI $uri -headers $nsxtHeaders -ContentType application/json
        $response
    } Catch {
        Write-Error $_.Exception.Message
        Break
    }
}
Export-ModuleMember -Function Remove-NsxtRouteMap

Function Get-NsxtRouteRedistributionPolicy {
    <#
        .SYNOPSIS
        Get the route redistribution policy from a Tier-0 Gateway.

        .DESCRIPTION
        The Get-NsxtRouteRedistributionPolicy cmdlet get the route redistribution policy from a Tier-0 Gateway

        .EXAMPLE
        Get-NsxtRouteRedistributionPolicy -tier0Gateway sfo-w01-ec01-t0-gw01
        This example returns the route redistribution policy for Tier-0 Gateway sfo-w01-ec01-t0-gw01.

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$tier0Gateway,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    if ($inputObject -and $inputObject.resource_type -eq "Tier0") {
        $Tier0Gateway = $inputObject.display_name
        $uriPath = $inputObject.path
    } elseif ($inputObject -and $inputObject.resource_type -ne "Tier0") {
        Write-Error "Invalid pipeline passthrough. Exiting."
        Break
    } elseif (!$inputObject) {
        if (!$Tier0Gateway) {
            $Tier0Gateway = Read-Host -Prompt "Tier-0 Gateway not defined. Type in the name of your Tier-0 Gateway, then press Enter"
        }
        $uriPath = (Get-NsxtTier0Gateway -Name $Tier0Gateway).path
    }

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/locale-services/default"
        $response = Invoke-RestMethod -Method GET -URI $uri -headers $nsxtHeaders -ContentType application/json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember Get-NsxtRouteRedistributionPolicy

Function Set-NsxtRouteRedistributionPolicy {
    <#
        .SYNOPSIS
        Set the route redistriution policy for a Tier 0 Gateway.

        .DESCRIPTION
        The Set-NsxtRouteRedistributionPolicy cmdlet sets the route redistriution policy for a Tier 0 Gateway

        .EXAMPLE
        Get-NsxtRouteRedistributionPolicy -tier0Gateway "sfo-w01-ec01-t0-gw01" | Set-NsxtRouteRedistributionPolicy -RouteMap "sfo-w01-ec01-t0-gw01-routemap"
        This example sets the RouteMap "sfo-w01-ec01-t0-gw01-routemap" on the route redistribution policy for Tier-0 Gateway "sfo-w01-t0-ec01-t0-gw01".

        .PARAMETER tier0Gateway
        The Tier-0 Gateway name.

        .PARAMETER routeMap
        The Route Map name.

        .PARAMETER removeRouteMap
        Remove the Route Map from the route redistribution policy.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $false)] [String]$tier0Gateway,
        [Parameter (Mandatory = $false)] [String]$routeMap,
        [Parameter (Mandatory = $false)] [Bool]$removeRouteMap,
        [Parameter (ValueFromPipeline, Mandatory = $true)] [psObject]$inputObject
    )

    if ($inputObject -and $inputObject.resource_type -eq "LocaleServices") {
        $Tier0GatewayId = $inputObject.parent_path.Split('/')[3]
        $Tier0Gateway = (Get-NsxtTier0Gateway -Id $Tier0GatewayId).display_name
        $edgeClusterPath = $inputObject.edge_cluster_path
        $bgpEnabled = $inputObject.route_redistribution_config.bgp_enabled
        $routeRedistributionName = $inputObject.route_redistribution_config.redistribution_rules.name
        $routeRedistributionTypes = $inputObject.route_redistribution_config.redistribution_rules.route_redistribution_types
        $uriPath = $inputObject.parent_path
    } elseif ($inputObject -and $inputObject.resource_type -ne "LocaleServices") {
        Write-Error "Invalid pipeline passthrough. Exiting."
        Break
    }

    if (!$inputObject) {
        if (!$Tier0Gateway) {
            $Tier0Gateway = Read-Host -Prompt "Tier-0 Gateway not defined. Type in the name of your Tier-0 Gateway, then press Enter"
        }
        $getRedistributionPolicy = Get-NsxtTier0Gateway -Name $Tier0Gateway
        $edgeClusterPath = $getRedistributionPolicy.edge_cluster_path
        $bgpEnabled = $getRedistributionPolicy.route_redistribution_config.bgp_enabled
        $routeRedistributionName = $getRedistributionPolicy.route_redistribution_config.redistribution_rules.name
        $routeRedistributionTypes = $getRedistributionPolicy.route_redistribution_config.redistribution_rules.route_redistribution_types
        $uriPath = (Get-NsxtTier0Gateway -Name $Tier0Gateway).path
    }

    $routeMapPath = "/infra/tier-0s/$Tier0GatewayId/route-maps/$RouteMap"

    foreach ($routeRedistributionType in $routeRedistributionTypes) {
        $routeRedistributionTypeString += @"
"$routeRedistributionType",
"@

    }

    $routeRedistributionTypeString = $routeRedistributionTypeString.Substring(0, $routeRedistributionTypeString.Length - 1)

    if ($RemoveRouteMap -eq $true) {
        $json = @"
{
    "edge_cluster_path" : "$edgeClusterPath",
    "route_redistribution_config" :
    {
        "bgp_enabled" : "$bgpEnabled",
        "redistribution_rules" :
        [
            {
            "name" : "$routeRedistributionName",
            "route_redistribution_types" : [ $routeRedistributionTypeString ]
            }
        ]
    }
}
"@

    } elseif ($RemoveRouteMap -eq $false -or !$RemoveRouteMap) {
        $json = @"
{
    "edge_cluster_path" : "$edgeClusterPath",
    "route_redistribution_config" :
    {
        "bgp_enabled" : "$bgpEnabled",
        "redistribution_rules" :
        [
            {
            "name" : "$routeRedistributionName",
            "route_redistribution_types" : [ $routeRedistributionTypeString ],
            "route_map_path" : "$routeMapPath"
            }
        ]
    }
}
"@

    }

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1" + $uriPath + "/locale-services/default"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -headers $nsxtHeaders -ContentType application/json -body $json
        $response

        if (!$response) {
            $output = Get-NsxtRouteRedistributionPolicy -Tier0Gateway $Tier0Gateway
            $output
        }
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember Set-NsxtRouteRedistributionPolicy

Function Get-NsxtManagerAuthPolicy {
    <#
        .SYNOPSIS
        Get the Authentication Policy for NSX Manager Nodes.

        .DESCRIPTION
        The Get-NsxtManagerAuthPolicy cmdlet getss the current authentication policy for NSX Manager Node

        .EXAMPLE
        Get-NsxtManagerAuthPolicy -nsxtManagerNode "sfo-m01-nsx01a.sfo.rainpole.io"
        This example returns the current Authentication policy in NSX manager node sfo-m01-nsx01a.sfo.rainpole.io.

        .PARAMETER nsxtManagerNode
        The NSX Manager Node name.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxtManagerNode
    )

    Try {
        $requestingURL = "https://" + $nsxtManagerNode + "/api/v1/node/aaa/auth-policy"
        $response = Invoke-RestMethod -Method GET -URI $requestingURL -ContentType application/json -headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember Get-NsxtManagerAuthPolicy

Function Set-NsxtManagerAuthPolicy {
    <#
        .SYNOPSIS
        Set the Authentication Policy for NSX Manager Node.

        .DESCRIPTION
        The Set-NsxtManagerAuthPolicy cmdlet configures the authentication policy for NSX Manager Node

        .EXAMPLE
        Set-NsxtManagerAuthPolicy -nsxtManagerNode "sfo-m01-nsx01a.sfo.rainpole.io" -api_lockout_period 900 -api_reset_period 120 -api_max_attempt 5 -cli_lockout_period 900 -cli_max_attempt 5 -min_passwd_length 15 -maximum_password_length 30 -digits 10 -lower_chars -1 -upper_chars -1 -special_chars -1 -max_repeats 2 -max_sequence 3 -minimum_unique_chars 0 -password_remembrance 5 -hash_algorithm "sha512"
        This example customized the Authentication policy in NSX manager node sfo-m01-nsx01a.sfo.rainpole.io.

        .PARAMETER nsxtManagerNode
        The NSX Manager Node name.

        .PARAMETER api_lockout_period
        The API lockout period in seconds.

        .PARAMETER api_reset_period
        The API reset period in seconds.

        .PARAMETER api_max_attempt
        The API max attempts.

        .PARAMETER cli_lockout_period
        The CLI lockout period in seconds.

        .PARAMETER cli_max_attempt
        The CLI max attempts.

        .PARAMETER min_passwd_length
        The minimum password length.

        .PARAMETER maximum_password_length
        The maximum password length.

        .PARAMETER digits
        The number of digits.

        .PARAMETER lower_chars
        The number of lower case characters.

        .PARAMETER upper_chars
        The number of upper case characters.

        .PARAMETER special_chars
        The number of special characters.

        .PARAMETER max_repeats
        The maximum number of repeated characters.

        .PARAMETER max_sequence
        The maximum number of sequential characters.

        .PARAMETER minimum_unique_chars.

        .PARAMETER password_remembrance
        The password remembrance.

        .PARAMETER hash_algorithm
        The hash algorithm.

        .PARAMETER inputObject
        The Tier-0 Gateway object.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxtManagerNode,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$api_lockout_period,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$api_reset_period,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$api_max_attempt,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$cli_lockout_period,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$cli_max_attempt,
        [Parameter (Mandatory = $false)] [ValidateRange(8, 128)] [int]$min_passwd_length,
        [Parameter (Mandatory = $false)] [ValidateRange(8, 128)] [int]$maximum_password_length,
        [Parameter (Mandatory = $false)] [ValidateRange(-128, 128)] [int]$digits,
        [Parameter (Mandatory = $false)] [ValidateRange(-128, 128)] [int]$lower_chars,
        [Parameter (Mandatory = $false)] [ValidateRange(-128, 128)] [int]$upper_chars,
        [Parameter (Mandatory = $false)] [ValidateRange(-128, 128)] [int]$special_chars,
        [Parameter (Mandatory = $false)] [ValidateRange(0, 128)] [int]$max_repeats,
        [Parameter (Mandatory = $false)] [ValidateRange(0, 128)] [int]$max_sequence,
        [Parameter (Mandatory = $false)] [ValidateRange(0, 128)] [int]$minimum_unique_chars,
        [Parameter (Mandatory = $false)] [ValidateSet("sha512", "sha256")] [string]$hash_algorithm,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [int]$password_remembrance 
    )

    $authPolicyBody = @{}
    if ($PsBoundParameters.ContainsKey("api_lockout_period")) {
        $authPolicyBody += @{api_failed_auth_lockout_period = $api_lockout_period }
    }
    if ($PsBoundParameters.ContainsKey("api_reset_period")) {
        $authPolicyBody += @{api_failed_auth_reset_period = $api_reset_period }
    }
    if ($PsBoundParameters.ContainsKey("api_max_attempt")) {
        $authPolicyBody += @{api_max_auth_failures = $api_max_attempt }
    }
    if ($PsBoundParameters.ContainsKey("cli_lockout_period")) {
        $authPolicyBody += @{cli_failed_auth_lockout_period = $cli_lockout_period }
    }
    if ($PsBoundParameters.ContainsKey("cli_max_attempt")) {
        $authPolicyBody += @{cli_max_auth_failures = $cli_max_attempt }
    }
    if ($PsBoundParameters.ContainsKey("min_passwd_length")) {
        $authPolicyBody += @{minimum_password_length = $min_passwd_length }
    }
    if ($PsBoundParameters.ContainsKey("maximum_password_length")) {
        $authPolicyBody += @{maximum_password_length = $maximum_password_length }
    }
    if ($PsBoundParameters.ContainsKey("lower_chars")) {
        $authPolicyBody += @{lower_chars = $lower_chars }
    }
    if ($PsBoundParameters.ContainsKey("upper_chars")) {
        $authPolicyBody += @{upper_chars = $upper_chars }
    }
    if ($PsBoundParameters.ContainsKey("special_chars")) {
        $authPolicyBody += @{special_chars = $special_chars }
    }
    if ($PsBoundParameters.ContainsKey("password_remembrance")) {
        $authPolicyBody += @{password_remembrance = $password_remembrance }
    }
    if ($PsBoundParameters.ContainsKey("minimum_unique_chars")) {
        $authPolicyBody += @{minimum_unique_chars = $minimum_unique_chars }
    } 
    if ($PsBoundParameters.ContainsKey("max_repeats")) {
        $authPolicyBody += @{max_repeats = $max_repeats }
    }
    if ($PsBoundParameters.ContainsKey("max_sequence")) {
        $authPolicyBody += @{max_sequence = $max_sequence }
    }
    if ($PsBoundParameters.ContainsKey("digits")) {
        $authPolicyBody += @{digits = $digits }
    }
    if ($PsBoundParameters.ContainsKey("hash_algorithm")) {
        $authPolicyBody += @{hash_algorithm = $hash_algorithm }
    }

    Try {
        $requestingURL = "https://" + $nsxtManagerNode + "/api/v1/node/aaa/auth-policy"
        $response = Invoke-RestMethod -Method PUT -URI $requestingURL -ContentType application/json -headers $nsxtHeaders -Body ($authPolicyBody | ConvertTo-Json)
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember Set-NsxtManagerAuthPolicy

Function Get-NsxtEdgeNodeAuthPolicy {
    <#
        .SYNOPSIS
        Get the Authentication Policy for NSX Edge Nodes.

        .DESCRIPTION
        The Get-NsxtEdgeNodeAuthPolicy cmdlet getss the authentication policy for NSX Edge Nodes

        .EXAMPLE
        Get-NsxtEdgeNodeAuthPolicy -nsxtManagerNode "sfo-m01-nsx01a.sfo.rainpole.io"
        This example returns the password policy in NSX manager node sfo-m01-nsx01a.sfo.rainpole.io.

        .PARAMETER nsxtManagerNode
        The NSX Manager Node name.

        .PARAMETER nsxtEdgeNodeID
        The NSX Edge Node ID.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxtManager,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxtEdgeNodeID
    )

    Try {
        $requestingURL = "https://" + $nsxtManager + "/api/v1/transport-nodes/" + $nsxtEdgeNodeID + "/node/aaa/auth-policy"
        $response = Invoke-RestMethod -Method GET -URI $requestingURL -ContentType application/json -headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember Get-NsxtEdgeNodeAuthPolicy

Function Set-NsxtEdgeNodeAuthPolicy {
    <#
        .SYNOPSIS
        Set the Authentication Policy for NSX Edge Nodes.

        .DESCRIPTION
        The Set-NsxtEdgeNodeAuthPolicy cmdlet sets the authentication policy for NSX Edge Nodes

        .EXAMPLE
        Set-NsxtEdgeNodeAuthPolicy -nsxtManager sfo-m01-nsx01.sfo.rainpole.io -nsxtEdgeNodeID <node_id> -cli_lockout_period 900 -cli_max_attempt 5 -min_passwd_length 15
        This example configures the password policy in NSX Edge node sfo-m01-nsx01a.sfo.rainpole.io.

        .PARAMETER nsxtManager
        The NSX Manager Node name.

        .PARAMETER nsxtEdgeNodeID
        The NSX Edge Node ID.

        .PARAMETER cli_lockout_period
        The CLI lockout period in seconds.

        .PARAMETER cli_max_attempt
        The CLI max attempts.

        .PARAMETER min_passwd_length
        The minimum password length.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxtManager,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$nsxtEdgeNodeID,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$cli_lockout_period,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$cli_max_attempt,
        [Parameter (Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [int]$min_passwd_length
    )

    $authPolicyBody = @{}
    if ($PsBoundParameters.ContainsKey("cli_lockout_period")) {
        $authPolicyBody += @{cli_failed_auth_lockout_period = $cli_lockout_period }
    }
    if ($PsBoundParameters.ContainsKey("cli_max_attempt")) {
        $authPolicyBody += @{cli_max_auth_failures = $cli_max_attempt }
    }
    if ($PsBoundParameters.ContainsKey("min_passwd_length")) {
        $authPolicyBody += @{minimum_password_length = $min_passwd_length }
    }

    Try {
        $requestingURL = "https://" + $nsxtManager + "/api/v1/transport-nodes/" + $nsxtEdgeNodeID + "/node/aaa/auth-policy"
        $response = Invoke-RestMethod -Method PUT -URI $requestingURL -ContentType application/json -headers $nsxtHeaders -Body ($authPolicyBody | ConvertTo-Json)
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember Set-NsxtEdgeNodeAuthPolicy

Function Get-NsxtSyslogStatus {
    <#
        .SYNOPSIS
        Gets the status of the Syslog Service.

        .DESCRIPTION
        The Get-NsxtSyslogStatus cmdlet gets the status of the Syslog Service for NSX components

        .EXAMPLE
        Get-NsxtSyslogStatus -type node
        This example gets the status of the syslog service for NSX Manager node

        .EXAMPLE
        Get-NsxtSyslogStatus -type transport -id f3bd5bf0-23cd-4c6f-8de5-ab065f74d7fe
        This example gets the status of the syslog service for NSX Edge node.

        .PARAMETER Node
        The NSX Manager node.

        .PARAMETER Transport
        The NSX Edge node.

        .PARAMETER id
        The NSX Edge node ID.
    #>


    Param (
        [Parameter (ParameterSetName = 'node', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$node,
        [Parameter (ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$transport,
        [Parameter (ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("node")) {
            $uri = "https://$nsxtManager/api/v1/node/services/syslog/status"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
            $response
        }
        if ($PsBoundParameters.ContainsKey("transport")) {
            $uri = "https://$nsxtManager/api/v1/transport-nodes/$id/node/services/syslog/status"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtSyslogStatus

Function Get-NsxtSyslogExporter {
    <#
        .SYNOPSIS
        Gets Syslog exporters.

        .DESCRIPTION
        The Get-NsxtSyslogExporter cmdlet gets the Syslog exporters configures for NSX components

        .EXAMPLE
        Get-NsxtSyslogExporter -node
        This example gets the configuration of the syslog exporters for NSX Manager node

        .EXAMPLE
        Get-NsxtSyslogExporter -transport -id f3bd5bf0-23cd-4c6f-8de5-ab065f74d7fe
        This example gets the configuration of the syslog exporters for NSX Edge node.

        .PARAMETER Node
        The NSX Manager node.

        .PARAMETER Transport
        The NSX Edge node.

        .PARAMETER id
        The NSX Edge node ID.
    #>


    Param (
        [Parameter (ParameterSetName = 'node', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$node,
        [Parameter (ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$transport,
        [Parameter (ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("node")) {
            $uri = "https://$nsxtManager/api/v1/node/services/syslog/exporters"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
            $response.results
        }
        if ($PsBoundParameters.ContainsKey("transport")) {
            $uri = "https://$nsxtManager/api/v1/transport-nodes/$id/node/services/syslog/exporters"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
            $response.results
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtSyslogExporter

Function Set-NsxtSyslogExporter {
    <#
        .SYNOPSIS
        Sets Syslog exporters.

        .DESCRIPTION
        The Set-NsxtSyslogExporter cmdlet Sets the Syslog exporters configures for NSX components

        .EXAMPLE
        Set-NsxtSyslogExporter -node -exporterName Syslog1 -logLevel INFO -port 514 -protocol TCP -server sfo-vrli01.sfo.rainpole.io
        This example gets the status of the syslog service for NSX Manager node

        .EXAMPLE
        Set-NsxtSyslogExporter -transport -id f3bd5bf0-23cd-4c6f-8de5-ab065f74d7fe -exporterName Syslog1 -logLevel INFO -port 514 -protocol TCP -server sfo-vrli01.sfo.rainpole.io
        This example gets the status of the syslog service for NSX Edge node.

        .PARAMETER Node
        The NSX Manager node.

        .PARAMETER Transport
        The NSX Edge node.

        .PARAMETER id
        The NSX Edge node ID.

        .PARAMETER exporterName
        The Syslog exporter name.

        .PARAMETER logLevel
        The Syslog log level.

        .PARAMETER port
        The Syslog port.

        .PARAMETER protocol
        The Syslog protocol.

        .PARAMETER server
        The Syslog server.
    #>


    Param (
        [Parameter ( ParameterSetName = 'node', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$node,
        [Parameter ( ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$transport,
        [Parameter ( ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter ( Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$exporterName,
        [Parameter ( Mandatory = $true)] [ValidateSet("EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG")]  [String]$logLevel,
        [Parameter ( Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$port,
        [Parameter ( Mandatory = $true)] [ValidateSet("TCP", "TLS", "UDP", "LI", "LI-TLS")] [String]$protocol,
        [Parameter ( Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server
    )

    Try {
        $json = '{
            "exporter_name": "'
 + $exporterName + '",
            "level": "'
 + $logLevel + '",
            "port": '
 + $port + ',
            "protocol": "'
 + $protocol + '",
            "server": "'
 + $server + '"
        }'


        if ($PsBoundParameters.ContainsKey("node")) {
            $uri = "https://$nsxtManager/api/v1/node/services/syslog/exporters"
            $response = Invoke-RestMethod $uri -Method 'POST' -Headers $nsxtHeaders -ContentType application/json -body $json
            $response
        }
        if ($PsBoundParameters.ContainsKey("transport")) {
            $uri = "https://$nsxtManager/api/v1/transport-nodes/$id/node/services/syslog/exporters"
            $response = Invoke-RestMethod $uri -Method 'POST' -Headers $nsxtHeaders -ContentType application/json -body $json
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtSyslogExporter

Function Remove-NsxtSyslogExporter {
    <#
        .SYNOPSIS
        Delete Syslog exporters.

        .DESCRIPTION
        The Remove-NsxtSyslogExporter cmdlet deletes the Syslog exporters for NSX components

        .EXAMPLE
        Remove-NsxtSyslogExporter -node -exporterName Syslog1
        This example deletes the syslog exporters for NSX Manager node

        .EXAMPLE
        Remove-NsxtSyslogExporter -transport -id f3bd5bf0-23cd-4c6f-8de5-ab065f74d7fe -exporterName Syslog1
        This example deletes the syslog exporters for for NSX Edge node.

        .PARAMETER Node
        The NSX Manager node.

        .PARAMETER Transport
        The NSX Edge node.

        .PARAMETER id
        The NSX Edge node ID.

        .PARAMETER exporterName
        The Syslog exporter name.
    #>


    Param (
        [Parameter (ParameterSetName = 'node', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$node,
        [Parameter (ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Switch]$transport,
        [Parameter (ParameterSetName = 'transport', Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter ( Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$exporterName
    )

    Try {
        if ($PsBoundParameters.ContainsKey("node")) {
            $uri = "https://$nsxtManager/api/v1/node/services/syslog/exporters/$exporterName"
            $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $nsxtHeaders
            $response
        }
        if ($PsBoundParameters.ContainsKey("transport")) {
            $uri = "https://$nsxtManager/api/v1/transport-nodes/$id/node/services/syslog/exporters/$exporterName"
            $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $nsxtHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtSyslogExporter

Function Copy-vRealizeLoadBalancer {
    <#
        .SYNOPSIS
        Creates a Load Balancer for VMware Aria component failover.

        .DESCRIPTION
        Creates a new loadbalancer in a secondary VMware Cloud Foundation instance by duplicating the settings of the
        existing load balancer in the instance where the VMware Aria components are currently running.

        .EXAMPLE
        Copy-vRealizeLoadBalancer -sddcManagerAFQDN sfo-vcf01.sfo.rainpole.io -sddcManagerAUser administrator@vsphere.local -sddcManagerAPassword VMw@re1! -sddcManagerBFQDN lax-vcf01.lax.rainpole.io -sddcManagerBUser administrator@vsphere.local -sddcManagerBPassword VMw@re1! -serviceInterfaceIP 192.168.11.3 -wsaCertName xint-wsa01
        This example copies settings from Load Balancer in the Primary SDDC to a new Load Balancer in Recovery SDDC.

        .PARAMETER sddcManagerAFQDN
        The fully qualified domain name of the SDDC Manager instance where the VMware Aria components are currently running.

        .PARAMETER sddcManagerAUser
        The username of the SDDC Manager instance where the VMware Aria components are currently running.

        .PARAMETER sddcManagerAPassword
        The password of the SDDC Manager instance where the VMware Aria components are currently running.

        .PARAMETER sddcManagerBFQDN
        The fully qualified domain name of the SDDC Manager instance where the VMware Aria components will be running after failover.

        .PARAMETER sddcManagerBUser
        The username of the SDDC Manager instance where the VMware Aria components will be running after failover.

        .PARAMETER sddcManagerBPassword
        The password of the SDDC Manager instance where the VMware Aria components will be running after failover.

        .PARAMETER serviceInterfaceIP
        The IP address of the Service Interface on the new Load Balancer.

        .PARAMETER wsaCertName
        The name of the certificate to be used by the new Load Balancer.
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [String]$sddcManagerAFqdn,
        [Parameter (Mandatory = $true)] [String]$sddcManagerAUser,
        [Parameter (Mandatory = $true)] [String]$sddcManagerAPassword,
        [Parameter (Mandatory = $true)] [String]$sddcManagerBFqdn,
        [Parameter (Mandatory = $true)] [String]$sddcManagerBUser,
        [Parameter (Mandatory = $true)] [String]$sddcManagerBPassword,
        [Parameter (Mandatory = $true)] [String]$serviceInterfaceIp,
        [Parameter (Mandatory = $true)] [String]$wsaCertName
    )

    Try {
        # Setup Parameters
        $t1Name = "recovery-t1-gw01"
        $siName = "recovery-t1-gw01-si01"
        $lbName = "recovery-lb01"

        #Retrieve Edge Cluster Details from SDDC Manager B
        Request-VCFToken -fqdn $sddcManagerBFqdn -Username $sddcManagerBUser -Password $sddcManagerBPassword | Out-Null
        $mgmtNsxtClusterID = (Get-VCFWorkloadDomain | Where-Object { $_.type -eq "Management" }).nsxtCluster.id
        $edgeClusterName = (Get-VCFEdgeCluster | Where-Object { $_.nsxtCluster.id -eq $mgmtNsxtClusterID }).Name
        
        #Retrieve Segment, WSA, VRA and vROPS Details from SDDC Manager A
        Request-VCFToken -fqdn $sddcManagerAFqdn -Username $sddcManagerAUser -Password $sddcManagerAPassword | Out-Null
        $xintSegmentDetails = Get-VCFApplicationVirtualNetwork | Where-Object { $_.regionType -eq "X_REGION" }
        $wsaDetailsObject = Get-WSAServerDetail -fqdn $sddcManagerAFqdn -username $sddcManagerAUser -password $sddcManagerAPassword
        $vraDetailsObject = Get-vRAServerDetail -fqdn $sddcManagerAFqdn -username $sddcManagerAUser -password $sddcManagerAPassword
        $vropsDetailsObject = Get-vROPsServerDetail -fqdn $sddcManagerAFqdn -username $sddcManagerAUser -password $sddcManagerAPassword

        #Add Cert to NSX
        $nsxManager = Get-NsxtServerDetail -fqdn $sddcManagerBFqdn -user $sddcManagerBUser -pass $sddcManagerBPassword -domainType MANAGEMENT
        Request-NsxToken -fqdn $nsxManager.fqdn -username $nsxManager.adminUser -password $nsxManager.adminPass | Out-Null

        #Get xint segment ID from NSX LM on recovery site
        $segmentID = Get-NsxtGlobalSegmentID -segmentName $xintSegmentDetails.name
    } Catch {
        Debug-ExceptionWriter -object $_
    }
    
    Try {
        if ((!$edgeClusterName) -OR (!$xintSegmentDetails) -OR (!$wsaDetailsObject) -OR ((!$vraDetailsObject) -AND (!$vropsDetailsObject))) {
            Write-Output "Requirements for Copying Load Balancer not Met".
            if (!$wsaDetailsObject) { Write-Output "Clustered Workspace ONE Access was not discovered in the source SDDC Manager instance" }
            if ((!$vraDetailsObject) -AND (!$vropsDetailsObject)) { Write-Output "Neither VMware Aria Automation nor VMware Aria Operations was discovered in the source SDDC Manager instance" }
            if (!$xintSegmentDetails) { Write-Output "Cross-Region Segment was discovered in the target SDDC Manager instance" }
            if (!$edgeClusterName) { Write-Output "Management Edge Cluster was not discovered in the target SDDC Manager instance" }
        } else {    
            #Create a Load Balancer Spec
            if (!$vraDetailsObject) {
                $lbCustomObject = New-vRealizeLoadBalancerSpec -xintSegmentDetails $xintSegmentDetails -serviceInterfaceIp $serviceInterfaceIp -wsaDetailsObject $wsaDetailsObject -vropsDetailsObject $vropsDetailsObject -wsaCertName $wsaCertName -t1Name $t1Name -lbName $lbName -siName $siName -segmentID $segmentID
            } elseif (!$vropsDetailsObject) {
                $lbCustomObject = New-vRealizeLoadBalancerSpec -xintSegmentDetails $xintSegmentDetails -serviceInterfaceIp $serviceInterfaceIp -wsaDetailsObject $wsaDetailsObject -vraDetailsObject $vraDetailsObject -wsaCertName $wsaCertName -t1Name $t1Name -lbName $lbName -siName $siName -segmentID $segmentID
            } else {
                $lbCustomObject = New-vRealizeLoadBalancerSpec -xintSegmentDetails $xintSegmentDetails -serviceInterfaceIp $serviceInterfaceIp -wsaDetailsObject $wsaDetailsObject -vraDetailsObject $vraDetailsObject -vropsDetailsObject $vropsDetailsObject -wsaCertName $wsaCertName -t1Name $t1Name -lbName $lbName -siName $siName -segmentID $segmentID
            }

            $wsaCertPresent = Add-CertToNsxCertificateStore -certName $wsaCertName
        
            if ($wsaCertPresent -eq $true) {
                $ConfigJson = $lbCustomObject.t1_spec.gw | ConvertTo-Json
                New-NsxtTier1 -tier1Gateway $t1Name -json $ConfigJson
                $edgeClusterID = (Get-NsxtEdgeCluster -name $edgeClusterName).id
                $ConfigJson = '{"edge_cluster_path": "/infra/sites/default/enforcement-points/default/edge-clusters/' + $edgeClusterID + '"}'
                Set-NsxtTier1 -tier1Gateway $t1name -json $ConfigJson
                $ConfigJson = '{
                    "segment_path": "'
+ $lbCustomObject.t1_spec.service_interface.segment_path + '",
                    "subnets": [
                    {
                        "ip_addresses": [ "'
+ $lbCustomObject.t1_spec.service_interface.subnets.ip_addresses + '" ],
                        "prefix_len": "'
+ $lbCustomObject.t1_spec.service_interface.subnets.prefix_len + '"
                    }
                    ]
                    }'

                New-NsxtTier1ServiceInterface -tier1Gateway $t1name -interfaceId $lbCustomObject.t1_spec.service_interface.id -json $ConfigJson
                $ConfigJson = '{
                    "network": "'
+ $lbCustomObject.t1_spec.static_routes.network + '",
                    "next_hops": [
                        {
                            "ip_address": "'
+ $lbCustomObject.t1_spec.static_routes.next_hops.ip_address + '",
                            "admin_distance": '
+ $lbCustomObject.t1_spec.static_routes.next_hops.admin_distance + ',
                            "scope": [
                                "'
+ $lbCustomObject.t1_spec.static_routes.next_hops.scope + '"
                            ]
                        }
                    ],
                    "display_name": "'
+ $lbCustomObject.t1_spec.static_routes.display_name + '"
                    }'

                New-NsxtTier1StaticRoute -tier1Gateway $t1name -segment $xintSegmentDetails.name -json $ConfigJson
                $ConfigJson = $lbCustomObject.lb_spec.lb_service | ConvertTo-Json
                New-NsxtLoadBalancer -lbName $lbName -json $ConfigJson
                Foreach ($monitor in $lbCustomObject.lb_spec.service_monitors) {
                    Try {
                        $ConfigJson = $monitor | ConvertTo-Json -Depth 10
                        New-NsxtLBServiceMonitor -monitorName $monitor.display_name -json $ConfigJson
                    } Catch {
                        Debug-ExceptionWriter -object $_
                    }
                }
                Foreach ($profile in $lbCustomObject.lb_spec.app_profiles) {
                    Try {
                        $ConfigJson = $profile | ConvertTo-Json
                        New-NsxtLBAppProfile -appProfileName $profile.display_name -json $ConfigJson
                    } Catch {
                        Debug-ExceptionWriter -object $_
                    }
                }
                Foreach ($profile in $lbCustomObject.lb_spec.persistence_profiles) {
                    Try {
                        $ConfigJson = $profile | ConvertTo-Json
                        New-NsxtLBPersistenceAppProfile -appProfileName $profile.display_name -json $ConfigJson
                    } Catch {
                        Debug-ExceptionWriter -object $_
                    }
                }
                Foreach ($pool in $lbCustomObject.lb_spec.pools) {
                    Try {
                        $ConfigJson = $pool | ConvertTo-Json
                        New-NsxtLBPool -poolName $pool.display_name -json $ConfigJson
                    } Catch {
                        Debug-ExceptionWriter -object $_
                    }
                }
                Foreach ($virtualServer in $lbCustomObject.lb_spec.virtual_Servers) {
                    Try {
                        $ConfigJson = $virtualServer | ConvertTo-Json -Depth 10
                        New-NsxtLBVirtualServer -virtualServerName $virtualServer.display_name -json $ConfigJson
                    } Catch {
                        Debug-ExceptionWriter -object $_
                    }
                }
            } else {
                Write-Error "Aborting remainder of NSX Load Balancer configuration until certificate files present"
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Copy-vRealizeLoadBalancer

Function New-vRealizeLoadBalancerSpec {
    Param (
        [Parameter (Mandatory = $true)] [Array]$xintSegmentDetails,
        [Parameter (Mandatory = $true)] [Array]$serviceInterfaceIp,
        [Parameter (Mandatory = $true)] [Array]$wsaDetailsObject,
        [Parameter (Mandatory = $false)] [Array]$vraDetailsObject,
        [Parameter (Mandatory = $false)] [Array]$vropsDetailsObject,
        [Parameter (Mandatory = $true)] [String]$wsaCertName,
        [Parameter (Mandatory = $true)] [String]$t1Name,
        [Parameter (Mandatory = $true)] [String]$lbName,
        [Parameter (Mandatory = $true)] [String]$siName,
        [Parameter (Mandatory = $true)] [String]$segmentID
    )

    $xintSegmentName = $xintSegmentDetails.name
    $xintSegmentServiceInterfacePrefixLength = cidrMaskLookup -source mask -value $xintSegmentDetails.subnetMask
    $xintSegmentNextHopIP = $xintSegmentDetails.gateway

    $xintWsaVip = $wsaDetailsObject.loadBalancerIpAddress
    $xintWsaNode1Ip = $wsaDetailsObject.node1IpAddress
    $xintWsaNode2Ip = $wsaDetailsObject.node2IpAddress
    $xintWsaNode3Ip = $wsaDetailsObject.node3IpAddress
    $xintWsaNode1Name = $wsaDetailsObject.fqdn[0].split(".")[0]
    $xintWsaNode2Name = $wsaDetailsObject.fqdn[1].split(".")[0]
    $xintWsaNode3Name = $wsaDetailsObject.fqdn[2].split(".")[0]

    If ($vropsDetailsObject) {
        $xintVropsVip = $vropsDetailsObject.loadBalancerIpAddress
        $xintVropsNode1Ip = $vropsDetailsObject.node1IpAddress
        $xintVropsNode2Ip = $vropsDetailsObject.node2IpAddress
        $xintVropsNode3Ip = $vropsDetailsObject.node3IpAddress
        $xintVropsNode1Name = $vropsDetailsObject.fqdn[0].split(".")[0]
        $xintVropsNode2Name = $vropsDetailsObject.fqdn[1].split(".")[0]
        $xintVropsNode3Name = $vropsDetailsObject.fqdn[2].split(".")[0]    
    }

    If ($vraDetailsObject) {
        $xintVraVip = $vraDetailsObject.loadBalancerIpAddress
        $xintVraNode1Ip = $vraDetailsObject.node1IpAddress
        $xintVraNode2Ip = $vraDetailsObject.node2IpAddress
        $xintVraNode3Ip = $vraDetailsObject.node3IpAddress
        $xintVraNode1Name = $vraDetailsObject.fqdn[0].split(".")[0]
        $xintVraNode2Name = $vraDetailsObject.fqdn[1].split(".")[0]
        $xintVraNode3Name = $vraDetailsObject.fqdn[2].split(".")[0]   
    }

    $lbJson += '{'
    $lbJson += '"t1_spec":{'
    $lbJson += '"gw":{'
    $lbJson += '"resource_type": "Tier1",'
    $lbJson += '"id": "<!--REPLACE WITH T1NAME-->",'
    $lbJson += '"force_whitelisting": false,'
    $lbJson += '"tier0_path": ""'
    $lbJson += '},'
    $lbJson += '"service_interface":{'
    $lbJson += '"segment_path": "/global-infra/segments/<!--REPLACE WITH SEGMENTID-->",'
    $lbJson += '"id": "<!--REPLACE WITH siName-->",'
    $lbJson += '"overridden": false,'
    $lbJson += '"subnets": ['
    $lbJson += '{'
    $lbJson += '"ip_addresses": ['
    $lbJson += '"<!--REPLACE WITH SI IP-->"'
    $lbJson += '],'
    $lbJson += '"prefix_len": <!--REPLACE WITH SI PREFIX-->'
    $lbJson += '}'
    $lbJson += ']'
    $lbJson += '},'
    $lbJson += '"static_routes":{'
    $lbJson += '"network": "0.0.0.0/0",'
    $lbJson += '"next_hops": ['
    $lbJson += '{'
    $lbJson += '"ip_address": "<!--REPLACE WITH NEXT HOP IP-->",'
    $lbJson += '"admin_distance": 1,'
    $lbJson += '"scope": ['
    $lbJson += '"/infra/tier-1s/<!--REPLACE WITH T1NAME-->/locale-services/default/interfaces/<!--REPLACE WITH siName-->"'
    $lbJson += '] '
    $lbJson += '}'
    $lbJson += '],'
    $lbJson += '"display_name": "default"'
    $lbJson += '}'
    $lbJson += '},'
    $lbJson += '"lb_spec": {'
    $lbJson += '"lb_service": ['
    $lbJson += '{'
    $lbJson += '"display_name": "<!--REPLACE WITH LB NAME-->",'
    $lbJson += '"resource_type": "LBService",'
    $lbJson += '"enabled": true,'
    $lbJson += '"size": "SMALL",'
    $lbJson += '"connectivity_path":""'
    $lbJson += '}'
    $lbJson += '],'
    $lbJson += '"service_monitors": ['
    If ($vropsDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-https-monitor",'
        $lbJson += '"description": "VMware Aria Operations HTTPS Monitor",'
        $lbJson += '"resource_type": "LBHttpsMonitorProfile",'
        $lbJson += '"monitor_port": "443",'
        $lbJson += '"interval": "5",'
        $lbJson += '"fall_count": "3",'
        $lbJson += '"rise_count": "3",'
        $lbJson += '"timeout": "16",'
        $lbJson += '"request_method": "GET",'
        $lbJson += '"request_url": "/suite-api/api/deployment/node/status?services=api&services=adminui&services=ui",'
        $lbJson += '"request_version": "HTTP_VERSION_1_1",'
        $lbJson += '"response_status_codes": ['
        $lbJson += '"200","204","301"'
        $lbJson += '],'
        $lbJson += '"response_body": "ONLINE",'
        $lbJson += '"server_ssl_profile_binding": {'
        $lbJson += '"ssl_profile_path": "/infra/lb-server-ssl-profiles/default-balanced-server-ssl-profile"'
        $lbJson += '}'
        $lbJson += '},'
    }
    If ($vraDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vra-http-monitor",'
        $lbJson += '"description": "VMware Aria Automation HTTP Monitor",'
        $lbJson += '"resource_type": "LBHttpMonitorProfile",'
        $lbJson += '"monitor_port": "8008",'
        $lbJson += '"interval": "3",'
        $lbJson += '"fall_count": "3",'
        $lbJson += '"rise_count": "3",'
        $lbJson += '"timeout": "10",'
        $lbJson += '"request_method": "GET",'
        $lbJson += '"request_url": "/health",'
        $lbJson += '"request_version": "HTTP_VERSION_1_1",'
        $lbJson += '"response_status_codes": ['
        $lbJson += '"200"'
        $lbJson += '],'
        $lbJson += '"response_body": ""'
        $lbJson += '},'
    }
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-https-monitor",'
    $lbJson += '"description": "Clustered Workspace ONE Access HTTPS Monitor",'
    $lbJson += '"resource_type": "LBHttpsMonitorProfile",'
    $lbJson += '"monitor_port": "443",'
    $lbJson += '"interval": "3",'
    $lbJson += '"fall_count": "3",'
    $lbJson += '"rise_count": "3",'
    $lbJson += '"timeout": "10",'
    $lbJson += '"request_method": "GET",'
    $lbJson += '"request_url": "/SAAS/API/1.0/REST/system/health/heartbeat",'
    $lbJson += '"request_version": "HTTP_VERSION_1_1",'
    $lbJson += '"response_status_codes": ['
    $lbJson += '"200","201"'
    $lbJson += '],'
    $lbJson += '"response_body": "ok",'
    $lbJson += '"server_ssl_profile_binding": {'
    $lbJson += '"client_certificate_path": "/infra/certificates/<!--REPLACE WITH XREG WSA CERT-->",'
    $lbJson += '"ssl_profile_path": "/infra/lb-server-ssl-profiles/default-balanced-server-ssl-profile"'
    $lbJson += '}'
    $lbJson += '}'
    $lbJson += '],'
    $lbJson += '"app_profiles": ['
    If ($vropsDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-http-app-profile-redirect",'
        $lbJson += '"description": "Cross-Instance VMware Aria Operations redirect HTTP to HTTPs",'
        $lbJson += '"resource_type": "LBHttpProfile",'
        $lbJson += '"idle_timeout": "1800",'
        $lbJson += '"request_header_size": "1024",'
        $lbJson += '"response_header_size": "4096",'
        $lbJson += '"http_redirect_to_https": "True",'
        $lbJson += '"response_timeout": "60",'
        $lbJson += '"ntlm": "False"'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-tcp-app-profile",'
        $lbJson += '"description": "VMware Aria Operations TCP App Profile",'
        $lbJson += '"resource_type": "LBFastTcpProfile",'
        $lbJson += '"idle_timeout": "1800",'
        $lbJson += '"ha_flow_mirroring_enabled": "False",'
        $lbJson += '"close_timeout": "8"'
        $lbJson += '},'
    }
    If ($vraDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vra-tcp-app-profile",'
        $lbJson += '"description": "VMware Aria Automation TCP App Profile",'
        $lbJson += '"resource_type": "LBFastTcpProfile",'
        $lbJson += '"idle_timeout": "1800",'
        $lbJson += '"ha_flow_mirroring_enabled": "False",'
        $lbJson += '"close_timeout": "8"'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "vra-http-app-profile-redirect",'
        $lbJson += '"description": "VMware Aria Automation Profile to redirect HTTP to HTTPs",'
        $lbJson += '"resource_type": "LBHttpProfile",'
        $lbJson += '"idle_timeout": "1800",'
        $lbJson += '"request_header_size": "1024",'
        $lbJson += '"response_header_size": "4096",'
        $lbJson += '"http_redirect_to_https": "True",'
        $lbJson += '"response_timeout": "60",'
        $lbJson += '"ntlm": "False"'
        $lbJson += '},'
    }
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-http-app-profile",'
    $lbJson += '"description": "Clustered Workspace ONE Access HTTP Redirect",'
    $lbJson += '"resource_type": "LBHttpProfile",'
    $lbJson += '"idle_timeout": "3600",'
    $lbJson += '"x_forwarded_for": "INSERT",'
    $lbJson += '"request_header_size": "1024",'
    $lbJson += '"response_header_size": "4096",'
    $lbJson += '"http_redirect_to_https": "False",'
    $lbJson += '"response_timeout": "60",'
    $lbJson += '"ntlm": "False"'
    $lbJson += '},'
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-http-app-profile-redirect",'
    $lbJson += '"description": "Clustered Workspace ONE Access redirect HTTP to HTTPs",'
    $lbJson += '"resource_type": "LBHttpProfile",'
    $lbJson += '"idle_timeout": "3600",'
    $lbJson += '"request_header_size": "1024",'
    $lbJson += '"response_header_size": "4096",'
    $lbJson += '"http_redirect_to_https": "True",'
    $lbJson += '"response_timeout": "60",'
    $lbJson += '"ntlm": "False"'
    $lbJson += '}'
    $lbJson += '],'
    $lbJson += '"persistence_profiles": ['
    If ($vropsDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-source-ip-persistence-profile",'
        $lbJson += '"description": "VMware Aria Operations Analytics Cluster Source IP Persistence Profile",'
        $lbJson += '"resource_type": "LBSourceIpPersistenceProfile",'
        $lbJson += '"persistence_shared": "False",'
        $lbJson += '"purge": "FULL",'
        $lbJson += '"ha_persistence_mirroring_enabled": "False"'
        $lbJson += '},'
    }
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-cookie-persistence-profile",'
    $lbJson += '"description": "Cookie Persistence Profile",'
    $lbJson += '"resource_type": "LBCookiePersistenceProfile",'
    $lbJson += '"persistence_shared": "False",'
    $lbJson += '"cookie_mode": "REWRITE",'
    $lbJson += '"cookie_name": "JSESSIONID",'
    $lbJson += '"cookie_fallback": "True",'
    $lbJson += '"cookie_garble": "True"'
    $lbJson += '}'
    $lbJson += '],'
    $lbJson += '"pools": ['
    If ($vropsDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-server-pool",'
        $lbJson += '"description": "VMware Aria Operations Analytics Cluster Server Pool",'
        $lbJson += '"algorithm": "LEAST_CONNECTION",'
        $lbJson += '"active_monitor_paths": ['
        $lbJson += '"/infra/lb-monitor-profiles/vrops-https-monitor"'
        $lbJson += '],'
        $lbJson += '"snat_translation": {'
        $lbJson += '"type": "LBSnatAutoMap"'
        $lbJson += '},'
        $lbJson += '"members": ['
        $lbJson += '{'
        $lbJson += '"display_name": "<!--REPLACE WITH VROPS NODE 1 NAME-->",'
        $lbJson += '"backup_member": "false",'
        $lbJson += '"weight": 1,'
        $lbJson += '"admin_state": "ENABLED",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VROPS NODE 1 IP-->",'
        $lbJson += '"port": "443"'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "<!--REPLACE WITH VROPS NODE 2 NAME-->",'
        $lbJson += '"backup_member": "false",'
        $lbJson += '"weight": 1,'
        $lbJson += '"admin_state": "ENABLED",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VROPS NODE 2 IP-->",'
        $lbJson += '"port": "443"'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "<!--REPLACE WITH VROPS NODE 3 NAME-->",'
        $lbJson += '"backup_member": "false",'
        $lbJson += '"weight": 1,'
        $lbJson += '"admin_state": "ENABLED",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VROPS NODE 3 IP-->",'
        $lbJson += '"port": "443"'
        $lbJson += '}'
        $lbJson += ']'
        $lbJson += '},'
    }
    If ($vraDetailsObject) {    
        $lbJson += '{'
        $lbJson += '"display_name": "vra-server-pool",'
        $lbJson += '"description": "VMware Aria Automation Cluster Pool",'
        $lbJson += '"algorithm": "LEAST_CONNECTION",'
        $lbJson += '"active_monitor_paths": ['
        $lbJson += '"/infra/lb-monitor-profiles/vra-http-monitor"'
        $lbJson += '],'
        $lbJson += '"snat_translation": {'
        $lbJson += '"type": "LBSnatAutoMap"'
        $lbJson += '},'
        $lbJson += '"members": ['
        $lbJson += '{'
        $lbJson += '"display_name": "<!--REPLACE WITH VRA NODE 1 NAME-->",'
        $lbJson += '"backup_member": "false",'
        $lbJson += '"weight": 1,'
        $lbJson += '"admin_state": "ENABLED",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VRA NODE 1 IP-->",'
        $lbJson += '"port": "443"'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "<!--REPLACE WITH VRA NODE 2 NAME-->",'
        $lbJson += '"backup_member": "false",'
        $lbJson += '"weight": 1,'
        $lbJson += '"admin_state": "ENABLED",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VRA NODE 2 IP-->",'
        $lbJson += '"port": "443"'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "<!--REPLACE WITH VRA NODE 3 NAME-->",'
        $lbJson += '"backup_member": "false",'
        $lbJson += '"weight": 1,'
        $lbJson += '"admin_state": "ENABLED",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VRA NODE 3 IP-->",'
        $lbJson += '"port": "443"'
        $lbJson += '}'
        $lbJson += ']'
        $lbJson += '},'
    }
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-server-pool",'
    $lbJson += '"description": "Clustered Workspace ONE Access Server Pool",'
    $lbJson += '"algorithm": "LEAST_CONNECTION",'
    $lbJson += '"active_monitor_paths": ['
    $lbJson += '"/infra/lb-monitor-profiles/wsa-https-monitor"'
    $lbJson += '],'
    $lbJson += '"snat_translation": {'
    $lbJson += '"type": "LBSnatAutoMap"'
    $lbJson += '},'
    $lbJson += '"members": ['
    $lbJson += '{'
    $lbJson += '"display_name": "<!--REPLACE WITH WSA NODE 1 NAME-->",'
    $lbJson += '"backup_member": "false",'
    $lbJson += '"weight": 1,'
    $lbJson += '"admin_state": "ENABLED",'
    $lbJson += '"ip_address": "<!--REPLACE WITH WSA NODE 1 IP-->",'
    $lbJson += '"port": "443"'
    $lbJson += '},'
    $lbJson += '{'
    $lbJson += '"display_name": "<!--REPLACE WITH WSA NODE 2 NAME-->",'
    $lbJson += '"backup_member": "false",'
    $lbJson += '"weight": 1,'
    $lbJson += '"admin_state": "ENABLED",'
    $lbJson += '"ip_address": "<!--REPLACE WITH WSA NODE 2 IP-->",'
    $lbJson += '"port": "443"'
    $lbJson += '},'
    $lbJson += '{'
    $lbJson += '"display_name": "<!--REPLACE WITH WSA NODE 3 NAME-->",'
    $lbJson += '"backup_member": "false",'
    $lbJson += '"weight": 1,'
    $lbJson += '"admin_state": "ENABLED",'
    $lbJson += '"ip_address": "<!--REPLACE WITH WSA NODE 3 IP-->",'
    $lbJson += '"port": "443"'
    $lbJson += '}'
    $lbJson += ']'
    $lbJson += '}'
    $lbJson += '],'
    $lbJson += '"virtual_servers": ['
    If ($vropsDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-https",'
        $lbJson += '"description": "VMware Aria Operations Analytics Cluster UI",'
        $lbJson += '"resource_type": "LBVirtualServer",'
        $lbJson += '"enabled": "true",'
        $lbJson += '"lb_persistence_profile_path": "/infra/lb-persistence-profiles/vrops-source-ip-persistence-profile",'
        $lbJson += '"application_profile_path": "/infra/lb-app-profiles/vrops-tcp-app-profile",'
        $lbJson += '"pool_path": "/infra/lb-pools/vrops-server-pool",'
        $lbJson += '"lb_service_path": "/infra/lb-services/<!--REPLACE WITH LB NAME-->",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VROPS VIP-->",'
        $lbJson += '"ports": ['
        $lbJson += '"443"'
        $lbJson += ']'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "vrops-http-redirect",'
        $lbJson += '"description": "VMware Aria Operations Analytics Cluster HTTP to HTTPS Redirect",'
        $lbJson += '"resource_type": "LBVirtualServer",'
        $lbJson += '"enabled": "true",'
        $lbJson += '"application_profile_path": "/infra/lb-app-profiles/vrops-http-app-profile-redirect",'
        $lbJson += '"lb_service_path": "/infra/lb-services/<!--REPLACE WITH LB NAME-->",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VROPS VIP-->",'
        $lbJson += '"ports": ['
        $lbJson += '"80"'
        $lbJson += ']'
        $lbJson += '},'
    }
    If ($vraDetailsObject) {
        $lbJson += '{'
        $lbJson += '"display_name": "vra-https",'
        $lbJson += '"description": "VMware Aria Automation Cluster UI",'
        $lbJson += '"resource_type": "LBVirtualServer",'
        $lbJson += '"enabled": "true",'
        $lbJson += '"application_profile_path": "/infra/lb-app-profiles/vra-tcp-app-profile",'
        $lbJson += '"pool_path": "/infra/lb-pools/vra-server-pool",'
        $lbJson += '"lb_service_path": "/infra/lb-services/<!--REPLACE WITH LB NAME-->",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VRA VIP-->",'
        $lbJson += '"ports": ['
        $lbJson += '"443"'
        $lbJson += ']'
        $lbJson += '},'
        $lbJson += '{'
        $lbJson += '"display_name": "vra-http-redirect",'
        $lbJson += '"description": "VMware Aria Automation HTTP to HTTPS Redirect",'
        $lbJson += '"resource_type": "LBVirtualServer",'
        $lbJson += '"enabled": "true",'
        $lbJson += '"application_profile_path": "/infra/lb-app-profiles/vra-http-app-profile-redirect",'
        $lbJson += '"lb_service_path": "/infra/lb-services/<!--REPLACE WITH LB NAME-->",'
        $lbJson += '"ip_address": "<!--REPLACE WITH VRA VIP-->",'
        $lbJson += '"ports": ['
        $lbJson += '"80"'
        $lbJson += ']'
        $lbJson += '},'
    }
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-https",'
    $lbJson += '"description": "Clustered Workspace ONE Access Cluster UI",'
    $lbJson += '"resource_type": "LBVirtualServer",'
    $lbJson += '"enabled": "true",'
    $lbJson += '"lb_persistence_profile_path": "/infra/lb-persistence-profiles/wsa-cookie-persistence-profile",'
    $lbJson += '"application_profile_path": "/infra/lb-app-profiles/wsa-http-app-profile",'
    $lbJson += '"pool_path": "/infra/lb-pools/wsa-server-pool",'
    $lbJson += '"lb_service_path": "/infra/lb-services/<!--REPLACE WITH LB NAME-->",'
    $lbJson += '"ip_address": "<!--REPLACE WITH WSA VIP-->",'
    $lbJson += '"ports": ['
    $lbJson += '"443"'
    $lbJson += '],'
    $lbJson += '"client_ssl_profile_binding": {'
    $lbJson += '"default_certificate_path": "/infra/certificates/<!--REPLACE WITH XREG WSA CERT-->",'
    $lbJson += '"ssl_profile_path": "/infra/lb-client-ssl-profiles/default-balanced-client-ssl-profile"'
    $lbJson += '},'
    $lbJson += '"server_ssl_profile_binding": {'
    $lbJson += '"client_certificate_path": "/infra/certificates/<!--REPLACE WITH XREG WSA CERT-->",'
    $lbJson += '"ssl_profile_path": "/infra/lb-server-ssl-profiles/default-balanced-server-ssl-profile"'
    $lbJson += '},'
    $lbJson += '"rules": ['
    $lbJson += '{'
    $lbJson += '"match_strategy": "ALL",'
    $lbJson += '"phase": "HTTP_REQUEST_REWRITE",'
    $lbJson += '"actions": ['
    $lbJson += '{'
    $lbJson += '"type": "LBHttpRequestHeaderRewriteAction",'
    $lbJson += '"header_name": "Remoteport",'
    $lbJson += '"header_value": "$_remote_port"'
    $lbJson += '}'
    $lbJson += ']'
    $lbJson += '}'
    $lbJson += ']'
    $lbJson += '},'
    $lbJson += '{'
    $lbJson += '"display_name": "wsa-http-redirect",'
    $lbJson += '"description": "Clustered Workspace ONE Access Cluster HTTP to HTTPS Redirect",'
    $lbJson += '"resource_type": "LBVirtualServer",'
    $lbJson += '"enabled": "true",'
    $lbJson += '"application_profile_path": "/infra/lb-app-profiles/wsa-http-app-profile-redirect",'
    $lbJson += '"lb_service_path": "/infra/lb-services/<!--REPLACE WITH LB NAME-->",'
    $lbJson += '"ip_address": "<!--REPLACE WITH WSA VIP-->",'
    $lbJson += '"ports": ['
    $lbJson += '"80"'
    $lbJson += ']'
    $lbJson += '}'
    $lbJson += ']'
    $lbJson += '}'
    $lbJson += '}'

    $lbJson = $lbJson | ForEach-Object { $_ `
            -replace '<!--REPLACE WITH T1NAME-->', $t1Name `
            -replace '<!--REPLACE WITH xintSegmentName-->', $xintSegmentName `
            -replace '<!--REPLACE WITH SEGMENTID-->', $segmentID `
            -replace '<!--REPLACE WITH siName-->', $siName `
            -replace '<!--REPLACE WITH SI IP-->', $serviceInterfaceIp `
            -replace '<!--REPLACE WITH XREGION CIDR-->', $xintionVXLAN `
            -replace '<!--REPLACE WITH NEXT HOP IP-->', $xintSegmentNextHopIP `
            -replace '<!--REPLACE WITH SI PREFIX-->', $xintSegmentServiceInterfacePrefixLength `
            -replace '<!--REPLACE WITH LB NAME-->', $lbName `
            -replace '<!--REPLACE WITH XREG WSA CERT-->', $wsaCertName `
            -replace '<!--REPLACE WITH WSA NODE 1 NAME-->', $xintWsaNode1Name `
            -replace '<!--REPLACE WITH WSA NODE 2 NAME-->', $xintWsaNode2Name `
            -replace '<!--REPLACE WITH WSA NODE 3 NAME-->', $xintWsaNode3Name `
            -replace '<!--REPLACE WITH WSA NODE 1 IP-->', $xintWsaNode1IP `
            -replace '<!--REPLACE WITH WSA NODE 2 IP-->', $xintWsaNode2IP `
            -replace '<!--REPLACE WITH WSA NODE 3 IP-->', $xintWsaNode3IP `
            -replace '<!--REPLACE WITH VROPS NODE 1 NAME-->', $xintVropsNode1Name `
            -replace '<!--REPLACE WITH VROPS NODE 2 NAME-->', $xintVropsNode2Name `
            -replace '<!--REPLACE WITH VROPS NODE 3 NAME-->', $xintVropsNode3Name `
            -replace '<!--REPLACE WITH VROPS NODE 1 IP-->', $xintVropsNode1Ip `
            -replace '<!--REPLACE WITH VROPS NODE 2 IP-->', $xintVropsNode2Ip `
            -replace '<!--REPLACE WITH VROPS NODE 3 IP-->', $xintVropsNode3Ip `
            -replace '<!--REPLACE WITH VRA NODE 1 NAME-->', $xintVraNode1Name `
            -replace '<!--REPLACE WITH VRA NODE 2 NAME-->', $xintVraNode2Name `
            -replace '<!--REPLACE WITH VRA NODE 3 NAME-->', $xintVraNode3Name `
            -replace '<!--REPLACE WITH VRA NODE 1 IP-->', $xintVraNode1Ip `
            -replace '<!--REPLACE WITH VRA NODE 2 IP-->', $xintVraNode2Ip `
            -replace '<!--REPLACE WITH VRA NODE 3 IP-->', $xintVraNode3Ip `
            -replace '<!--REPLACE WITH WSA VIP-->', $xintWsaVip `
            -replace '<!--REPLACE WITH VROPS VIP-->', $xintVropsVip `
            -replace '<!--REPLACE WITH VRA VIP-->', $xintVraVip `
    }
    $lbCustomObject = $lbJson | ConvertFrom-Json
    Return $lbCustomObject
}
Export-ModuleMember -Function New-vRealizeLoadBalancerSpec

Function Get-NsxtGlobalSegmentID {
    <#
        .SYNOPSIS
        Gets NSX Global Segment Id

        .DESCRIPTION
        The Get-NsxtGlobalSegmentID cmdlet gets the NSX Global Segment Id

        .EXAMPLE
        Get-NsxtGlobalSegmentID -segmentName sfo-w01-ec01-xintion
        This example returns the NSX Global Segment Id.

        .PARAMETER segmentName
        The name of the NSX Global Segment.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$segmentName
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/global-infra/segments/"
        $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
        $segmentObjectId = ($response.results | where-object { $_.display_name -eq $segmentName }).id
    } Catch {
        Write-Error $_.Exception.Message
    }
    Return $segmentObjectId
}
Export-ModuleMember -Function Get-NsxtGlobalSegmentID

Function Add-CertToNsxCertificateStore {
    <#
        .SYNOPSIS
        Adds a Certificate to the NSX Certificate Store

        .DESCRIPTION
        The Add-CertToNsxCertificateStore cmdlet adds a Certificate to the NSX Certificate Store

        .EXAMPLE
        Add-CertToNsxCertificateStore -certName sfo-w01-ec01-xreg-wsa
        This example adds a Certificate to the NSX Certificate Store.

        .PARAMETER certName
        The name of the Certificate.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certName 
    )

    Try {
        $pemFile = Get-ExternalFileName -title "Select the Certificate Chain PEM File for Clustered WSA (.pem)" -fileType "pem" -location "default"
    } Catch {
        Write-Error $_.Exception.Message
    }
    Try {
        $keyFile = Get-ExternalFileName -title "Select the Key File for Clustered WSA (.key)" -fileType "key" -location "default"
    } Catch {
        Write-Error $_.Exception.Message
    }

    $certAlreadyImported = ""
    #check for existing certificate
    Try {
        $certAlreadyImported = Get-NsxtCertificate -certificateName $certName -ErrorAction SilentlyContinue
    } Catch {
        $certAlreadyImported = $false
    }

    # report on existing cert or install new cert
    if ($certAlreadyImported) {
        $wsaCertPresent = $true
    } else {
        $pemContent = (Get-Content $pemFile) -join "\n"
        $keyContent = (Get-Content $keyFile) -join "\n"
        $body = 
        '{
                "pem_encoded": "<!--REPLACE WITH PEM DATA-->",
                "private_key": "<!--REPLACE WITH KEY DATA-->"
            }
            '

        $body = $body | ForEach-Object { $_ `
                -replace '<!--REPLACE WITH PEM DATA-->', $pemContent `
                -replace '<!--REPLACE WITH KEY DATA-->', $keyContent `
        }
        Try {
            Set-NsxtCertificate -certificateName $certName -json $body
            $wsaCertPresent = $true
        } Catch {
            Debug-ExceptionWriter -object $_
        }   
    }
    Return $wsaCertPresent
}
Export-ModuleMember -Function Add-CertToNsxCertificateStore

Function Get-NsxtEdgeCluster {
    <#
        .SYNOPSIS
        Gets NSX Edge Cluster Id

        .DESCRIPTION
        The Get-NsxtEdgeCluster cmdlet gets the NSX Edge Cluster Id

        .EXAMPLE
        Get-NsxtEdgeCluster
        This example returns the NSX Edge Cluster Id.
    #>


    Try {
        $uri = "https://$nsxtmanager/api/v1/edge-clusters"
        $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtEdgeCluster

Function New-NsxtTier1 {
    <#
        .SYNOPSIS
        Creates a Tier 1 Gateway

        .DESCRIPTION
        The New-NsxtTier1 cmdlet creates a Teir 1 Gateway

        .EXAMPLE
        New-NsxtTier1 -tier1Gateway sfo-w01-ec01-t0-lb01 -json $ConfigJson
        This example creates a new Tier 1 Gateway.

        .PARAMETER tier1Gateway
        The name of the Tier 1 Gateway.

        .PARAMETER json
        The JSON configuration for the Tier 1 Gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier1Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s/$($tier1Gateway)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtTier1

Function Set-NsxtTier1 {
    <#
        .SYNOPSIS
        Configures Tier 1 Gateway

        .DESCRIPTION
        The Set-NsxtTier1 cmdlet configures a Tier 1 Gateway

        .EXAMPLE
        Set-NsxtTier1 -tier1Gateway -json
        This example sets the configuration on a Tier 1 Gateway.

        .PARAMETER tier1Gateway
        The name of the Tier 1 Gateway.

        .PARAMETER json
        The JSON configuration for the Tier 1 Gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier1Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s/$($tier1Gateway)/locale-services/default"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtTier1

Function New-NsxtTier1ServiceInterface {
    <#
        .SYNOPSIS
        Creates Service Interface on Tier 1 Gateway

        .DESCRIPTION
        The New-NsxtTier1ServiceInterface cmdlet configures a Service Interface on Tier 1 Gateway

        .EXAMPLE
        New-NsxtTier1ServiceInterface -tier1Gateway -interfaceId -json
        This example configures a Service Interface on a Tier 1 Gateway.

        .PARAMETER tier1Gateway
        The name of the Tier 1 Gateway.

        .PARAMETER interfaceId
        The name of the Interface.

        .PARAMETER json
        The JSON configuration for the Tier 1 Gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier1Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$interfaceId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s/$($tier1Gateway)/locale-services/default/interfaces/$($interfaceId)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtTier1ServiceInterface

Function New-NsxtTier1StaticRoute {
    <#
        .SYNOPSIS
        Creates Static Route on Tier 1 Gateway

        .DESCRIPTION
        The New-New-NsxtTier1StaticRoute cmdlet creates a static route on Tier 1 Gateway

        .EXAMPLE
        New-NsxtTier1StaticRoute -tier1Gateway -segment -json
        This example configures a Service Interface on a Tier 1 Gateway.

        .PARAMETER tier1Gateway
        The name of the Tier 1 Gateway.

        .PARAMETER segment
        The name of the Segment.

        .PARAMETER json
        The JSON configuration for the Tier 1 Gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$tier1Gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$segment,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-1s/$($tier1Gateway)/static-routes/$($segment)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtTier1StaticRoute

Function New-NsxtLoadBalancer {
    <#
        .SYNOPSIS
        Creates a Load Balancer

        .DESCRIPTION
        The New-NsxtLoadBalancer cmdlet creates a load balancer

        .EXAMPLE
        New-NsxtLoadBalancer -lbName -json
        This example creates a load balancer.

        .PARAMETER lbName
        The name of the Load Balancer.

        .PARAMETER json
        The JSON configuration for the Load Balancer.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$lbName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/lb-services/$($lbName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLoadBalancer

Function New-NsxtLBServiceMonitor { 
    <#
        .SYNOPSIS
        Creates a Load Balancer Service Monitor

        .DESCRIPTION
        The New-NsxtLBServiceMonitor cmdlet creates a Load Balancer Service Monitor

        .EXAMPLE
        New-NsxtLBServiceMonitor -monitorName -json
        This example creates a Load Balancer Serviec Monitor.

        .PARAMETER monitorName
        The name of the Load Balancer Service Monitor.

        .PARAMETER json
        The JSON configuration for the Load Balancer Service Monitor.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$monitorName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/lb-monitor-profiles/$($monitorName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLBServiceMonitor

Function New-NsxtLBAppProfile {
    <#
        .SYNOPSIS
        Creates a Load Balancer Application Profile

        .DESCRIPTION
        The New-NsxtLBAppProfile cmdlet creates a Load Balancer Application Profile

        .EXAMPLE
        New-NsxtLBAppProfile -appProfileName -json
        This example creates a Load Balancer Application Profile.

        .PARAMETER appProfileName
        The name of the Load Balancer Application Profile.

        .PARAMETER json
        The JSON configuration for the Load Balancer Application Profile.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$appProfileName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )
    
    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/lb-app-profiles/$($appProfileName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLBAppProfile

Function New-NsxtLBPersistenceAppProfile {
    <#
        .SYNOPSIS
        Creates a Load Balancer Persistence Application Profile

        .DESCRIPTION
        The New-NsxtLBPersistenceAppProfile cmdlet creates a Load Balancer Persistence Application Profile

        .EXAMPLE
        New-NsxtLBPersistenceAppProfile -appProfileName -json
        This example creates a Load Balancer Persistence Application Profile.

        .PARAMETER appProfileName
        The name of the Load Balancer Persistence Application Profile.

        .PARAMETER json
        The JSON configuration for the Load Balancer Persistence Application Profile.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$appProfileName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )
    
    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/lb-persistence-profiles/$($appProfileName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLBPersistenceAppProfile

Function New-NsxtLBPool {
    <#
        .SYNOPSIS
        Creates a Load Balancer Pool

        .DESCRIPTION
        The New-NsxtLBPool cmdlet creates a Load Balancer Pool

        .EXAMPLE
        New-NsxtLBPool -poolName -json
        This example creates a Load Balancer Pool.

        .PARAMETER poolName
        The name of the Load Balancer Pool.

        .PARAMETER json
        The JSON configuration for the Load Balancer Pool.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$poolName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/lb-pools/$($poolName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLBPool

Function New-NsxtLBVirtualServer {
    <#
        .SYNOPSIS
        Creates a Load Balancer Virtual Server

        .DESCRIPTION
        The New-NsxtLBVirtualServer cmdlet creates a Load Balancer Virtual Server

        .EXAMPLE
        New-NsxtLBVirtualServer -virtualServerName -json
        This example creates a Load Balancer Virtual Server.

        .PARAMETER virtualServerName
        The name of the Load Balancer Virtual Server.

        .PARAMETER json
        The JSON configuration for the Load Balancer Virtual Server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$virtualServerName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    ) 

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/lb-virtual-servers/$($virtualServerName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtLBVirtualServer

Function Get-NsxtCertificate {
    <#
        .SYNOPSIS
        Gets NSX Certificates

        .DESCRIPTION
        The Get-NsxtCertificates cmdlet gets certificates installed in NSX

        .EXAMPLE
        Get-NsxtCertificates
        This example gets the certificates installed in NSX.

        .PARAMETER certificateName
        The name of the certificate.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificateName
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("certificateName")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/certificates"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response.results
        } elseif ($PsBoundParameters.ContainsKey("certificateName")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/certificates/$($certificateName)"
            $response = Invoke-RestMethod -Method GET -URI $uri -ContentType application/json -headers $nsxtHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtCertificate

Function Set-NsxtCertificate {
    <#
        .SYNOPSIS
        Installs a Certificate in NSX

        .DESCRIPTION
        The Set-NsxtCertificates cmdlet installs certificates in NSX

        .EXAMPLE
        Set-NsxtCertificates
        This example installs the certificates in NSX.

        .PARAMETER certificateName
        The name of the certificate.

        .PARAMETER json
        The JSON configuration for the certificate.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/certificates/$($certificateName)"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -ContentType application/json -headers $nsxtHeaders -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtCertificate

Function Get-NsxtNodeProfile {
    <#
        .SYNOPSIS
        Get the NSX node profiles.

        .DESCRIPTION
        The Get-NsxtNodeProfile cmdlet returns the node profiles from the NSX Manager

        .EXAMPLE
        Get-NsxtNodeProfile
        This example returns all the node profiles from the NSX Manager.

        .EXAMPLE
        Get-NsxtNodeProfile -id $id
        This example returns the node profiles from the NSX Manager using the id.

        .PARAMETER id
        The id of the node profile.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {

        if ($PsBoundParameters.ContainsKey('id')) {
            $uri = "https://$nsxtManager/api/v1/configs/central-config/node-config-profiles/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
            $response
        } else {
            $uri = "https://$nsxtManager/api/v1/configs/central-config/node-config-profiles/"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
            $response.results
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtNodeProfile

Function Set-NsxtNodeProfileSyslogExporter {
    <#
        .SYNOPSIS
        Sets a node profile syslog exporter.

        .DESCRIPTION
        The Set-NsxtNodeProfileSyslogExporter cmdlet adds a syslog exporter to an NSX node profie for configuration
        of NSX components included in the node profile.

        .EXAMPLE
        Set-NsxtNodeProfileSyslogExporter -id "00000000-0000-0000-0000-000000000001" -server "sfo-vrli01.sfo.rainpole.io" -port 514 -protocol TCP -logLevel INFO
        This example add a single syslog exporter to the NSX node profile the id of the profile.

        Note: This function only supports a single syslog exporter.

        .PARAMETER id
        The id of the node profile.

        .PARAMETER server
        The syslog server.

        .PARAMETER port
        The syslog server port.

        .PARAMETER protocol
        The syslog protocol.

        .PARAMETER logLevel
        The syslog log level.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [int]$port,
        [Parameter (Mandatory = $true)] [ValidateSet('TCP', 'UDP', 'LI')] [ValidateNotNullOrEmpty()] [String]$protocol,
        [Parameter (Mandatory = $true)] [ValidateSet('EMERG', 'ALERT', 'CRIT', 'ERR', 'WARNING', 'NOTICE', 'INFO', 'DEBUG')] [ValidateNotNullOrEmpty()] [String]$logLevel
    )

    Try {
        $revision = (Get-NsxtNodeProfile -id $id)._revision
        $body = '{
                    "syslog" : {
                        "exporters" : [ {
                        "server" : "'
 + $server + '",
                        "port" : '
 + $port + ',
                        "protocol" : "'
 + $protocol + '",
                        "max_log_level" : "'
 + $logLevel + '"
                        } ]
                    },
                    "_revision" : '
 + $revision + '
                }'

        $uri = "https://$nsxtManager/api/v1/configs/central-config/node-config-profiles/$id"
        $response = Invoke-RestMethod -Method 'PUT' -Uri $uri -Headers $nsxtHeaders -Body $body
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Set-NsxtNodeProfileSyslogExporter

Function Remove-NsxtNodeProfileSyslogExporter {
    <#
        .SYNOPSIS
        Removes all node profile syslog exporters.

        .DESCRIPTION
        The Remove-NsxtNodeProfileSyslogExporter cmdlet removes all syslog exporters from an NSX node profie for configuration
        of NSX components included in the node profile.

        .EXAMPLE
        Remove-NsxtNodeProfileSyslogExporter -id "00000000-0000-0000-0000-000000000001"
        This example add a single syslog exporter to the NSX node profile the id of the profile.

        Note: This function only supports a single syslog exporter.

        .PARAMETER id
        The id of the node profile.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $revision = (Get-NsxtNodeProfile -id $id)._revision
        $body = '{
                    "syslog" : {
                        "exporters" : []
                    },
                    "_revision" : '
 + $revision + '
                }'

        $uri = "https://$nsxtManager/api/v1/configs/central-config/node-config-profiles/$id"
        $response = Invoke-RestMethod -Method 'PUT' -Uri $uri -Headers $nsxtHeaders -Body $body
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtNodeProfileSyslogExporter

Function Get-NsxtBackupConfiguration {
    <#
        .SYNOPSIS
        Return the backup configuration for an NSX Manager cluster.

        .DESCRIPTION
        The Get-NsxtBackupConfiguration cmdlet returns the backup configuration for an NSX Manager cluster

        .EXAMPLE
        Get-NsxtBackupConfiguration -fqdn sfo-w01-nsx01.sfo.rainpole.io
        This example returns the backup configuration for the NSX Manager cluster named 'sfo-w01-nsx01.sfo.rainpole.io'.

        .PARAMETER fqdn
        The fully qualified domain name of the NSX Manager cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn
    )

    Try {
        $uri = "https://$fqdn/api/v1/cluster/backups/config"
        # Note: NSX v3.2.0 and later use `/policy/api/v1/cluster/backups/config` or `/api/v1/cluster/backups/config`
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtBackupConfiguration

Function Get-NsxtBackupHistory {
    <#
        .SYNOPSIS
        Return the backup history for an NSX Manager cluster.

        .DESCRIPTION
        The Get-NsxtBackupHistory cmdlet returns the backup history for an NSX Manager cluster

        .EXAMPLE
        Get-NsxtBackupHistory -fqdn sfo-w01-nsx01.sfo.rainpole.io
        This example returns the backup history for the NSX Manager cluster named 'sfo-w01-nsx01.sfo.rainpole.io'.

        .PARAMETER fqdn
        The fully qualified domain name of the NSX Manager cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/cluster/backups/history"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtBackupHistory

Function Get-NsxtAlarm {
    <#
        .SYNOPSIS
        Return the triggered alarms for an NSX Manager cluster.

        .DESCRIPTION
        The Get-NsxtAlarm cmdlet returns all triggered alarms for an NSX Manager cluster.

        .EXAMPLE
        Get-NsxtAlarm -fqdn sfo-w01-nsx01.sfo.rainpole.io
        This example returns all triggered alarms for an NSX Manager cluster named sfo-w01-nsx01.sfo.rainpole.io.

        .PARAMETER fqdn
        The fully qualified domain name of the NSX Manager cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/alarms"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtAlarm

Function Get-NsxtEvent {
    <#
        .SYNOPSIS
        Return the events for an NSX Manager cluster.

        .DESCRIPTION
        The Get-NsxtEvent cmdlet returns the events for an NSX Manager cluster.

        .EXAMPLE
        Get-NsxtEvent -fqdn sfo-w01-nsx01.sfo.rainpole.io
        This example returns events for an NSX Manager cluster named sfo-w01-nsx01.sfo.rainpole.io.

        .PARAMETER fqdn
        The fully qualified domain name of the NSX Manager cluster.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/events"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtEvent

Function Get-NsxtTier0BgpStatus {
    <#
        .SYNOPSIS
        Returns the status of the BGP routing for NSX Tier-0 gateways.

        .DESCRIPTION
        The Get-NsxtTier0BgpStatus cmdlet returns the status of the BGP routing for NSX Tier-0 gateways.

        .EXAMPLE
        Get-NsxtTier0BgpStatus -id <guid>
        This example returns the status of the BGP routing for NSX Tier-0 gateway.

        .PARAMETER id
        The id of the NSX Tier-0 gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/policy/api/v1/infra/tier-0s/$id/locale-services/default/bgp/neighbors/status"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $nsxtHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTier0BgpStatus

Function New-NsxtTier0BgpNeighborConfig {
    <#
        .SYNOPSIS
        Create or update a BGP neighbor config for NSX Tier-0 gateways

        .DESCRIPTION
        The New-NsxtTier0BgpNeighborConfig cmdlet configures or updates the BGP neighbor config for NSX Tier-0 gateways

        .EXAMPLE
        New-NsxtTier0BgpNeighborConfig -id <guid> -localeservices $localeservices -neighborID $neighborID -json $bgpneighborJson
        This example configures or updates the BGP neighbor config for NSX Tier-0 gateways.

        .PARAMETER id
        The id of the NSX Tier-0 gateway.

        .PARAMETER localeservices
        The name of the locale services.

        .PARAMETER neighborID
        The id of the BGP neighbor.

        .PARAMETER json
        The JSON configuration for the BGP neighbor.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$localeservices,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$neighborID,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )
    
    Try {        
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-0s/$id/locale-services/$localeservices/bgp/neighbors/$neighborID"
        $response = Invoke-RestMethod -Method PATCH -URI $uri -headers $nsxtHeaders -ContentType application/json -body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-NsxtTier0BgpNeighborConfig

Function Get-NsxtEdgeNode {
    <#
        .SYNOPSIS
        Get details for NSX Edge.

        .DESCRIPTION
        The Get-NsxtEdgeNode cmdlet returns the details of an NSX Edge node

        .EXAMPLE
        Get-NsxtEdgeNode -transportNodeId 7740f2da-83b5-40de-bc4c-665ea779bbd0
        This example returns the details of an NSX Edge node.

        .PARAMETER transportNodeId
        The id of the NSX Edge node.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$transportNodeId
    )

    Try {
        $uri = "https://$nsxtmanager/api/v1/transport-nodes/$transportNodeId"
        Invoke-RestMethod -Method GET -URI $uri -headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtEdgeNode

Function Get-NsxtTier0LocaleServiceBgp {
    <#
        .SYNOPSIS
        Get details for BGP in the locale services.

        .DESCRIPTION
        The Get-NsxtTier0LocaleServiceBgp cmdlet returns the details for BGP in the locale services.

        .EXAMPLE
        Get-NsxtTier0LocaleServiceBgp -id <guid>
        This example returns the details for BGP in the locale services.

        .PARAMETER id
        The id of the NSX Tier-0 gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-0s/$id/locale-services/default/bgp"
        $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTier0LocaleServiceBgp

Function Get-NsxtLocaleService {
    <#
        .SYNOPSIS
        Get paginated list of all Tier-0 locale-services

        .DESCRIPTION
        The Get-NsxtLocaleService cmdlet returns a paginated list of all Tier-0 locale-services

        .EXAMPLE
        Get-NsxtLocaleservice -id <guid>
        This example will list all Tier-0 locale-services .

        .PARAMETER id
        The id of the NSX Tier-0 gateway.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/tier-0s/$id/locale-services/"
        $response = Invoke-RestMethod -Method GET -URI $uri -headers $nsxtHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtLocaleService

Function Get-NsxtVidmStatus {
    <#
        .SYNOPSIS
        Get the status of the Identity Manager integration.

        .DESCRIPTION
        The Get-NsxtVidmStatus cmdlet returns the status of the Identity Manager integration.

        .EXAMPLE
        Get-NsxtVidmStatus
        This example returns the status of the Identity Manager integration.
    #>


    Try {
        $uri = "https://$nsxtManager/api/v1/node/aaa/providers/vidm/status"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtVidmStatus

Function Get-NsxtTransportNode {
    <#
        .SYNOPSIS
        Returns information about all transport nodes with host or edge details.

        .DESCRIPTION
        The Get-NsxtTransportNode cmdlet returns information about all transport nodes with host or edge details.

        .EXAMPLE
        Get-NsxtTransportNode
        This example returns information about all transport nodes with host or edge details.

        .EXAMPLE
        Get-NsxtTransportNode -type edge
        This example returns information about all edge transport nodes with details.

        .EXAMPLE
        Get-NsxtTransportNode -type host
        This example returns information about all host transport nodes with details.

        .PARAMETER type
        The type of transport node.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet('host', 'edge')][ValidateNotNullOrEmpty()] [String]$type
    )

    Try {
        if ($PsBoundParameters.ContainsKey('type')) {
            if ($type -eq 'host') {
                $uri = "https://$nsxtManager/api/v1/transport-nodes?node_types=HostNode"
            } else {
                $uri = "https://$nsxtManager/api/v1/transport-nodes?node_types=EdgeNode"
            }
        } else {
            $uri = "https://$nsxtManager/api/v1/transport-nodes"
        }
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTransportNode

Function Get-NsxtTransportNodeStatus {
    <#
        .SYNOPSIS
        Get the status of the NSX transport nodes.

        .DESCRIPTION
        The Get-NsxtTransportNodeStatus cmdlet returns the status of the transport nodes.

        .EXAMPLE
        Get-NsxtTransportNodeStatus
        This example returns the status of all transport nodes.

        .EXAMPLE
        Get-NsxtTransportNodeStatus -type edge
        This example returns the status of the edge transport nodes.

        .EXAMPLE
        Get-NsxtTransportNodeStatus -type host
        This example returns the status of the host transport nodes. .

        .PARAMETER type
        The type of transport node.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet('host', 'edge')][ValidateNotNullOrEmpty()] [String]$type
    )

    Try {
        if ($PsBoundParameters.ContainsKey('type')) {
            $uri = "https://$nsxtManager/api/v1/transport-nodes/status?node_type=$($type.ToUpper())"
        } else {
            $uri = "https://$nsxtManager/api/v1/transport-nodes/status"
        }
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTransportNodeStatus

Function Get-NsxtTransportNodeTunnel {
    <#
        .SYNOPSIS
        Returns a list of tunnel connections to transport node.

        .DESCRIPTION
        The Get-NsxtTransportNodeTunnel cmdlet returns a list of tunnel connections to transport node.

        .EXAMPLE
        Get-NsxtTransportNodeTunnel -id <guid>
        This example returns a list of tunnel connections to transport node.

        .PARAMETER id
        The id of the transport node.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/transport-nodes/$id/tunnels"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTransportNodeTunnel

Function Get-NsxtTransportNodeTunnelStatus {
    <#
        .SYNOPSIS
        Returns the status of all transport nodes with tunnel connections to transport node.

        .DESCRIPTION
        The Get-NsxtTransportNodeTunnelStatus cmdlet returns the status of all transport nodes with tunnel connections to transport node.

        .EXAMPLE
        Get-NsxtTransportNodeTunnelStatus -id <guid>
        This example returns the status of all transport nodes with tunnel connections to transport node.

        .PARAMETER id
        The id of the transport node.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/transport-nodes/$id/remote-transport-node-status"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtTransportNodeTunnelStatus

Function Get-NsxtComputeManagerStatus {
    <#
        .SYNOPSIS
        Get the status of a compute manager registered to the NSX Manager cluster.

        .DESCRIPTION
        The Get-NsxtComputeManagerStatus cmdlet returns the status of a compute manager registered to the NSX Manager cluster.

        .EXAMPLE
        Get-NsxtComputeManagerStatus -id <guid>
        This example returns the status of a compute manager registered to the NSX Manager cluster.

        .PARAMETER id
        The id of the compute manager.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtManager/api/v1/fabric/compute-managers/$id/status"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtComputeManagerStatus

Function Get-NsxtApplianceUser {
    <#
        .SYNOPSIS
        Returns the list of users configued to log in to the NSX appliance.

        .DESCRIPTION
        The Get-NsxtApplianceUser cmdlet returns the list of users configued to log in to the NSX appliance.

        .EXAMPLE
        Get-NsxtApplianceUser
        This example returns a all users configued to log in to the NSX appliance.

        .EXAMPLE
        Get-NsxtApplianceUser -transportNodeId <guid>

        .EXAMPLE
        Get-NsxtApplianceUser -clusterNodeId <guid>.

        .PARAMETER transportNodeId
        The id of the transport node.

        .PARAMETER clusterNodeId
        The id of the cluster node.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$transportNodeId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$clusterNodeId
    )

    Try {
        if ($PsBoundParameters.ContainsKey("transportNodeId")) {
            $uri = "https://$nsxtmanager/api/v1/transport-nodes/$transportNodeId/node/users"
        } elseif ($PsBoundParameters.ContainsKey("clusterNodeId")) {
            $uri = "https://$nsxtmanager/api/v1/cluster/$clusterNodeId/node/users"
        } else {
            $uri = "https://$nsxtmanager/api/v1/node/users"
        }
        (Invoke-RestMethod $uri -Method 'GET' -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtApplianceUser

Function Set-NsxtApplianceUserExpirationPolicy {
    <#
        .SYNOPSIS
        Updates the password expiration policy for NSX appliance user.

        .DESCRIPTION
        The Set-NsxtApplianceUserExpirationPolicy cmdlet updates the password expiration policy for an NSX appliance user.

        .EXAMPLE
        Set-NsxtApplianceUserExpirationPolicy -userId 0 -days 9999
        This example updates the password expiration policy for the userId 0 (root) to 9999 days.

        .PARAMETER userId
        The id of the user.

        .PARAMETER maxDays
        The maximum number of days before the password expires.

        .PARAMETER transportNodeId
        The id of the transport node.

        .PARAMETER clusterNodeId
        The id of the cluster node.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateRange(0, 9999)] [Int]$maxDays,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$transportNodeId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$clusterNodeId
    )

    Try {
        $json = '{"password_change_frequency": ' + $maxDays + ' }'
        if ($PsBoundParameters.ContainsKey("transportNodeId")) {
            $uri = "https://$nsxtmanager/api/v1/transport-nodes/$transportNodeId/node/users/$userId"
        } elseif ($PsBoundParameters.ContainsKey("clusterNodeId")) {
            $uri = "https://$nsxtmanager/api/v1/cluster/$clusterNodeId/node/users/$userId"
        } else {
            $uri = "https://$nsxtmanager/api/v1/node/users/$userId"
        }
        (Invoke-RestMethod $uri -Method 'PUT' -Headers $nsxtHeaders -Body $json).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtApplianceUserExpirationPolicy

Function Set-NsxtApplianceUserPassword {
    <#
        .SYNOPSIS
        Updates the password for NSX appliance user.

        .DESCRIPTION
        The Set-NsxtApplianceUserPassword cmdlet updates the password for an NSX appliance user.

        .EXAMPLE
        Set-NsxtApplianceUserPassword -userId 0 -password VMw@re1!VMw@re1!
        This example updates the password for the userId 0 (root).

        .PARAMETER userId
        The id of the user.

        .PARAMETER password
        The password for the user.

        .PARAMETER transportNodeId
        The id of the transport node.

        .PARAMETER clusterNodeId
        The id of the cluster node.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()]  [String]$password,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$transportNodeId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$clusterNodeId
    )

    Try {
        $json = '{"password": "' + $password + '" }'
        if ($PsBoundParameters.ContainsKey("transportNodeId")) {
            $uri = "https://$nsxtmanager/api/v1/transport-nodes/$transportNodeId/node/users/$userId`?action=reset_password"
        } elseif ($PsBoundParameters.ContainsKey("clusterNodeId")) {
            $uri = "https://$nsxtmanager/api/v1/cluster/$clusterNodeId/node/users/$userId`?action=reset_password"
        } else {
            $uri = "https://$nsxtmanager/api/v1/node/users/$userId`?action=reset_password"
        }
        (Invoke-RestMethod $uri -Method 'POST' -Headers $nsxtHeaders -Body $json).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtApplianceUserPassword

Function Get-NsxtLogicalRouter {
    <#
        .SYNOPSIS
        Get Logical Routers
    
        .DESCRIPTION
        The Get-NsxtLogicalRouter cmdlet retrieves a list of logical routers
    
        .EXAMPLE
        Get-NsxtLogicalRouter
        This example gets all logical routers.
    #>


    Try {
        $uri = "https://$nsxtmanager/api/v1/logical-routers"
        (Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtLogicalRouter

Function Get-NsxtRoutingConfigRedistribution {
    <#
        .SYNOPSIS
        Get configured route redistribution
    
        .DESCRIPTION
        The Get-NsxtRoutingConfigRedistribution cmdlet returns information about configured route redistribution for the
        specified logical router.
    
        .EXAMPLE
        Get-NsxtRoutingConfigRedistribution -logicalRouterId <router-id>
        This example gets the configured route redistribution details for the supplied logical router.

        .PARAMETER logicalRouterId
        The id of the logical router.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$logicalRouterId
    )
    
    Try {
        $uri = "https://$nsxtmanager/api/v1/logical-routers/$logicalRouterId/routing/redistribution"
        Invoke-RestMethod -Method GET -URI $uri -headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtRoutingConfigRedistribution

Function Get-NsxtRoutingConfigRedistributionRule {
    <#
        .SYNOPSIS
        Get configured route redistribution

        .DESCRIPTION
        The Get-NsxtRoutingConfigRedistributionRule cmdlet returns all the route redistribution rules for the specified
        logical router.

        .EXAMPLE
        Get-NsxtRoutingConfigRedistributionRule -logicalRouterId
        This example gets the route redistribution rule details for the supplied logical router.

        .PARAMETER logicalRouterId
        The id of the logical router.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$logicalRouterId
    )
    
    Try {
        $uri = "https://$nsxtmanager/api/v1/logical-routers/$logicalRouterId/routing/redistribution/rules"
        Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtRoutingConfigRedistributionRule

Function Set-NsxtRoutingConfigRedistributionRule {
    <#
        .SYNOPSIS
        Set redistribution rule

        .DESCRIPTION
        The Set-NsxtRoutingConfigRedistributionRule cmdlet configures the route redistribution rules for the specified
        logical router.

        .EXAMPLE
        Get-NsxtRoutingConfigRedistributionRule -logicalRouterId <router-id> -json <file>
        This example gets the route redistribution rule details for the supplied logical router.

        .PARAMETER logicalRouterId
        The id of the logical router.

        .PARAMETER json
        The JSON configuration for the route redistribution rule.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$logicalRouterId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )
    
    Try {
        $myHeaders.Add("X-Allow-Overwrite", "true")
        $uri = "https://$nsxtmanager/api/v1/logical-routers/$logicalRouterId/routing/redistribution/rules"
        Invoke-RestMethod -Method PUT -URI $uri -Headers $nsxtHeaders -body $json
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-NsxtRoutingConfigRedistributionRule

Function Get-NsxtRoutingConfigRouteMap {
    <#
        .SYNOPSIS
        Get configured route maps

        .DESCRIPTION
        The Get-NsxtRoutingConfigRouteMap cmdlet returns a paginated list of RouteMaps

        .EXAMPLE
        Get-NsxtRoutingConfigRouteMap -logicalRouterId <router-id>
        This example gets the route map details for the supplied logical router.

        .PARAMETER logicalRouterId
        The id of the logical router.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$logicalRouterId
    )
    
    Try {
        $uri = "https://$nsxtmanager/api/v1/logical-routers/$logicalRouterId/routing/route-maps"
        (Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders).results
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtRoutingConfigRouteMap

Function Get-NsxtSecurityPolicy {
    <#
        .SYNOPSIS
        Get configured security policies

        .DESCRIPTION
        The Get-NsxtSecurityPolicy cmdlet returns a paginated list of security policies

        .EXAMPLE
        Get-NsxtSecurityPolicy
        This example retrieves a paginated list of all security policies

        .EXAMPLE
        Get-NsxtSecurityPolicy -id <id_name>
        This example retrieves the specified security policy.

        .PARAMETER id
        The id of the security policy.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/domains/default/security-policies/$id"
            Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders
        } else {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/domains/default/security-policies/"
            (Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders).Results
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtSecurityPolicy

Function Remove-NsxtSecurityPolicy {
    <#
        .SYNOPSIS
        Remove a security policy

        .DESCRIPTION
        The Remove-NsxtSecurityPolicy cmdlet removes a security policy

        .EXAMPLE
        Remove-NsxtSecurityPolicy -id <id_name>
        This example removes the specified security policy.

        .PARAMETER id
        The id of the security policy.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/domains/default/security-policies/$id"
        Invoke-RestMethod -Method DELETE -URI $uri -Headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtSecurityPolicy

Function Get-NsxtGroup {
    <#
        .SYNOPSIS
        Get groups

        .DESCRIPTION
        The Get-NsxtGroup cmdlet returns a paginated list of groups

        .EXAMPLE
        Get-NsxtGroup
        This example retrieves a paginated list of all groups

        .EXAMPLE
        Get-NsxtGroup -id <id>
        This example retrieves the specified group.

        .PARAMETER id
        The id of the group.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$nsxtmanager/policy/api/v1/infra/domains/default/groups/$id"
            Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders
        } else {
            #
            $uri = "https://$nsxtmanager/policy/api/v1/infra/domains/default/groups/"
            (Invoke-RestMethod -Method GET -URI $uri -Headers $nsxtHeaders).results
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-NsxtGroup

Function Remove-NsxtGroup {
    <#
        .SYNOPSIS
        Remove a group

        .DESCRIPTION
        The Remove-NsxtGroup cmdlet removes a group

        .EXAMPLE
        Remove-NsxtGroup -id <id_name>
        This example removes the specified security policy.

        .PARAMETER id
        The id of the group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$nsxtmanager/policy/api/v1/infra/domains/default/groups/$id"
        Invoke-RestMethod -Method DELETE -URI $uri -Headers $nsxtHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-NsxtGroup

#EndRegion End NSX Functions ######
###################################################################################

###################################################################################
#Region Begin vSphere with Tanzu Functions ######

Function Enable-WMRegistry {
    <#
        .SYNOPSIS
        Enable the embedded Harbor Registry on a Supervisor Cluster.

        .DESCRIPTION
        The Enable-WMRegistry cmdlet enables the embedded Harbor Registry on a Supervisor Cluster

        .EXAMPLE
        Enable-WMRegistry -cluster sfo-w01-cl01 -ctoragePolicy vsphere-with-tanzu-policy
        This example enables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01

        .EXAMPLE
        Get-WMCluster -cluster sfo-w01-cl01 | Enable-WMRegistry
        This example enables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01 via pipeline from Get-WMCluster with the default image storage policy for the Supervisor Cluster

        .EXAMPLE
        Get-WMCluster -cluster sfo-w01-cl01 | Enable-WMRegistry -storagePolicy vsphere-with-tanzu-policy
        
        .PARAMETER domain
        The name of the domain.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER storagePolicy
        The name of the image storage policy for the Supervisor Cluster.

        .PARAMETER inputObject
        The input object from the pipeline.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$storagePolicy,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [psObject]$inputObject
    )

    if ($inputObject) {
        $cluster = $inputObject.Name
    }

    if ($vCenterApi -ge 800) {
        Write-Warning "The embedded Harbor registry is not supported on vSphere 8.0 and higher: SKIPPED"
        Break
    }

    Try {
        if ($vCenterApi -le 701) {
            $getHarborInstalled = (Invoke-RestMethod -Method GET -URI https://$vcApiServer/rest/vcenter/content/registries/harbor -Headers $vcApiHeaders).value
        } elseif ($vCenterApi -ge 702) {
            $getHarborInstalled = Invoke-RestMethod -Method GET -URI https://$vcApiServer/api/vcenter/content/registries/harbor -Headers $vcApiHeaders
        }
    } Catch {
        Write-Error = $_.Exception
    }

    if (!$getHarborInstalled) {
        Try {
            $wmClusterId = (Invoke-RestMethod -Method GET -URI  https://$vcApiServer/api/vcenter/namespace-management/clusters -Headers $vcApiHeaders | Where-Object { $_.cluster_name -eq $Cluster }).cluster
        } Catch {
            Write-Error $_.Exception.Message
        }

        if (!$StoragePolicy) {
            Try {
                $storagePolicyId = (Invoke-RestMethod -Method GET -URI  https://$vcApiServer/api/vcenter/namespace-management/clusters/$wmClusterId -Headers $vcApiHeaders).image_storage.storage_policy
            } Catch {
                Write-Error $_.Exception.Message
            }
        } elseif ($StoragePolicy) {
            Try {
                if ($vCenterApi -ge 702) {
                    $storagePolicyId = ((Invoke-WebRequest -Method GET -URI https://$vcApiServer/api/vcenter/storage/policies -Headers $vcApiHeaders  -UseBasicParsing | ConvertFrom-Json) | Where-Object { $_.name -eq $StoragePolicy }).policy
                    $json = @"
{
    "cluster" : "$wmClusterId",
    "storage" :
    [
        {
            "policy" : "$storagePolicyId"
        }
    ]
}
"@

                } elseif ($vCenterApi -le 701) {
                    $storagePolicyId = ((Invoke-WebRequest -Method GET -URI https://$vcApiServer/rest/vcenter/storage/policies -Headers $vcApiHeaders -UseBasicParsing | ConvertFrom-Json).value | Where-Object { $_.name -eq $StoragePolicy }).policy
                    $json = @"
{
    "spec" :
    {
        "cluster" : "$wmClusterId",
        "storage" :
        [
            {
                "policy" : "$storagePolicyId"
            }
        ]
    }
}
"@

                }
            } Catch {
                Write-Error $_.Exception.Message
            }
        }
    }
    # Send a REST API call to vCenter Server to instantiate the new Harbor registry
        if ($vCenterApi -le 701) {
            Try {
                $installHarbor = Invoke-RestMethod -Method POST -URI https://$vcApiServer/rest/vcenter/content/registries/harbor -Headers $vcApiHeaders -Body $json -ContentType application/json
            } Catch {
                Write-Error $_.Exception.Message
            }

            if ($installHarbor) {
                $installHarborValue = $installHarbor.value
                Write-Output "Embedded registry $installHarborValue deployment successfully started on Supervisor Cluster $cluster"
            }
        } elseif ($vCenterApi -ge 702) {
            Try {
                $installHarbor = Invoke-RestMethod -Method POST -URI https://$vcApiServer/api/vcenter/content/registries/harbor -Headers $vcApiHeaders -Body $json -ContentType application/json
            } Catch {
                Write-Error $_.Exception.Message
            }

        if ($installHarbor) {
            Write-Output "Embedded registry $installHarbor deployment successfully started on Supervisor Cluster $cluster"
        }
    }
}
Export-ModuleMember -Function Enable-WMRegistry

Function Get-WMRegistry {
    <#
        .SYNOPSIS
        Retrieves the embedded Harbor Registry on a Supervisor Cluster.

        .DESCRIPTION
        The Get-WMRegistry cmdlet retrieves the embedded Harbor Registry on a Supervisor Cluster

        .EXAMPLE
        Get-WMRegistry
        This example retrieves all embedded Harbor Registries in vCenter Server inventory

        .EXAMPLE
        Get-WMRegistry -Cluster sfo-w01-cl01
        This example enables the embedded Harbor Registry on Supervisor Cluster "sfo-w01-cl01"

        .EXAMPLE
        Get-WMCluster -Cluster sfo-w01-cl01 | Get-WMRegistry
        This example enables the embedded Harbor Registry on Supervisor Cluster "sfo-w01-cl01" via pipeline from Get-WMCluster.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER inputObject
        The input object from the pipeline.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [ValidateNotNullOrEmpty()] [psObject]$inputObject
    )

    if ($inputObject) {
        $cluster = $inputObject.Name
    }

    if ($vCenterApi -ge 800) {
        Write-Warning "The embedded Harbor registry is not supported on vSphere 8.0 and higher: SKIPPED"
        Break
    }

    if ($Cluster) {
        Try {
            $wmClusterId = (Invoke-RestMethod -Method GET -URI  https://$vcApiServer/api/vcenter/namespace-management/clusters -Headers $vcApiHeaders | Where-Object { $_.cluster_name -eq $Cluster }).cluster
        } Catch {
            Write-Error $_.Exception.Message
        }
    }

    Try {
        if (!$PsBoundParameters.ContainsKey("Cluster")) {
            if ($vCenterApi -le 701) {
                $response = Invoke-RestMethod -Method GET -URI https://$vcApiServer/rest/vcenter/content/registries/harbor -ContentType application/json -headers $vcApiHeaders
                $response.value
            } elseif ($vCenterApi -ge 702) {
                $response = Invoke-RestMethod -Method GET -URI https://$vcApiServer/api/vcenter/content/registries/harbor -ContentType application/json -headers $vcApiHeaders
                $response
            }
        } elseif ($PsBoundParameters.ContainsKey("Cluster")) {
            if ($vCenterApi -le 701) {
                $response = Invoke-RestMethod -Method GET -URI https://$vcApiServer/rest/vcenter/content/registries/harbor -ContentType application/json -headers $vcApiHeaders
                $response.value | Where-Object { $_.cluster -eq $wmClusterId }
            } elseif ($vCenterApi -ge 702) {
                $response = Invoke-RestMethod -Method GET -URI https://$vcApiServer/api/vcenter/content/registries/harbor -ContentType application/json -headers $vcApiHeaders
                $response | Where-Object { $_.cluster -eq $wmClusterId }
            }
        }
    } Catch {
        Write-Error = $_.Exception
    }
}
Export-ModuleMember -Function Get-WMRegistry

Function Remove-WMRegistry {
    <#
        .SYNOPSIS
        Disable the embedded Harbor Registry on a Supervisor Cluster.

        .DESCRIPTION
        The Remove-WMRegistry cmdlet disables the embedded Harbor Registry on a Supervisor Cluster

        .EXAMPLE
        Get-WMRegistry -cluster sfo-w01-cl01 | Remove-WMRegistry
        This example disables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01 via pipeline from Get-WMCluster

        .EXAMPLE
        Remove-WMRegistry -cluster sfo-w01-cl01
        This example disables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER inputObject
        The input object from the pipeline.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [ValidateNotNullOrEmpty()] [psObject]$inputObject
    )

    Try {
        if ($vCenterApi -ge 800) {
            Write-Warning "The embedded Harbor registry is not supported on vSphere 8.0 and higher: SKIPPED"
            Break
        }

        if ($inputObject) {
            $harborRegistryId = $inputObject.registry
        } else {
            $harborRegistryId = (Get-WMRegistry -cluster $cluster).registry
        }

        if ($vCenterApi -le 701) {
            $uri = "https://$vcApiServer/rest/vcenter/content/registries/harbor/$harborRegistryId"
        } elseif ($vCenterApi -ge 702) {
            $uri = "https://$vcApiServer/api/vcenter/content/registries/harbor/$harborRegistryId"
        }
        $response = Invoke-WebRequest -Method DELETE -URI $uri -ContentType application/json -headers $vcApiHeaders -UseBasicParsing
        if ($response.StatusCode -eq 200 -or $response.StatusCode -eq 204) {
            Write-Output "Disable embedded Harbor Registry successfully started for Supervisor Cluster $cluster"
        }
    } Catch {
        Write-Error = $_.Exception
    }
}
Export-ModuleMember -Function Remove-WMRegistry

Function Get-WMRegistryHealth {
    <#
        .SYNOPSIS
        Retrieves the embedded Harbor Registry Health.

        .DESCRIPTION
        The Get-WMRegistry cmdlet retrieves the embedded Harbor Registry Health

        .EXAMPLE
        Get-WMRegistryHealth -registry <regestry_id>
        This example gets the health status of the embedded Harbor Registry

        .EXAMPLE
        Get-WMRegistry -cluster sfo-w01-cl01 | Get-WMRegistryHealth
        This example enables the embedded Harbor Registry on Supervisor Cluster sfo-w01-cl01 via pipeline from Get-WMCluster.

        .PARAMETER registry
        The id of the registry.

        .PARAMETER inputObject
        The input object from the pipeline.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$registry,
        [Parameter (ValueFromPipeline, Mandatory = $false)] [ValidateNotNullOrEmpty()] [psObject]$inputObject
    )

    Try {
        if ($vCenterApi -ge 800) {
            Write-Warning "The embedded Harbor registry is not supported on vSphere 8.0 and higher: SKIPPED"
            Break
        }

        if ($inputObject) {
            $registry = $inputObject.registry
        }
        $uri = "https://$vcApiServer/rest/vcenter/content/registries/$registry/health"
        $response = Invoke-RestMethod -Method 'GET' -URI $uri -Headers $vcApiHeaders -ContentType application/json
        $response.value.status
    } Catch {
        Write-Error = $_.Exception
    }
}
Export-ModuleMember -Function Get-WMRegistryHealth

Function Connect-WMCluster {
    <#
        .SYNOPSIS
        Connect to the Supervisor Cluster.

        .DESCRIPTION
        The Connect-WMCluster cmdlet connect to the Supervisor Cluster

        .EXAMPLE
        Connect-WMCluster -cluster sfo-w01-cl01 -user administrator@vsphere.local -pass VMw@re1!
        This example connects with the vSphere SSO user administrator@vsphere.local to the Supervisor Cluster sfo-w01-cl01.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER user
        The vSphere SSO user.

        .PARAMETER pass
        The vSphere SSO user password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        $server = (Get-WMCluster -Cluster $cluster).KubernetesHostname
        $env:KUBECTL_VSPHERE_PASSWORD = $pass
        Invoke-Expression "kubectl vsphere login --server $server --vsphere-username $user --insecure-skip-tls-verify" | Out-Null
        if (Invoke-Expression "kubectl get nodes") {
            Write-Output "Successfully connected to Supervisor Cluster: $server"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Connect-WMCluster

Function Disconnect-WMCluster {
    <#
        .SYNOPSIS
        Disconnect from o the Supervisor Cluster.

        .DESCRIPTION
        The Disconnect-WMCluster cmdlet disconnects from the Supervisor Cluster

        .EXAMPLE
        Disconnect-WMCluster
        This example disconnects from the Supervisor Cluster.
    #>


    Try {
        Invoke-Expression "kubectl vsphere logout" | Out-Null
        $env:KUBECTL_VSPHERE_PASSWORD = $null
        Write-Output "Successfully disconnected from Supervisor Cluster"
    } Catch {
        Write-Error = $_.Exception
    }
}
Export-ModuleMember -Function Disconnect-WMCluster

Function New-TanzuKubernetesCluster {
    <#
        .SYNOPSIS
        Adds a Tanzu Kubernetes Cluster based on the specified YAML file.

        .DESCRIPTION
        The New-TanzuKubernetesCluster cmdlet adds a Tanzu Kubernetes Cluster based on the specified YAML file.

        .EXAMPLE
        New-TanzuKubernetesCluster -YAML .\SampleYaml\sfo-w01-tkc01-cluster.yaml
        This example creates a Tanzu Kubernetes Cluster based on the yaml file.

        .PARAMETER YAML
        The path to the YAML file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$YAML
    )

    Try {
        Invoke-Expression "kubectl apply -f $YAML"
    } Catch {
        Write-Error = $_.Exception
    }
}
Export-ModuleMember -Function New-TanzuKubernetesCluster

Function Get-TanzuKubernetesCluster {
    <#
        .SYNOPSIS
        Retrieves a Tanzu Kubernetes Cluster.

        .DESCRIPTION
        The Get-TanzuKuberntesCluster cmdlet retrieves a Tanzu Kubernetes Cluster

        .EXAMPLE
        Get-TanzuKubernetesCluster
        This example retrieves all Tanzu Kubernetes Clusters from all Namespaces

        .EXAMPLE
        Get-TanzuKubernetesCluster -namespace sfo-w01-tkc01 -tkc sfo-w01-tkc01
        This example retrieves a Tanzu Kubernetes Cluster named "sfo-w01-tkc01" from the Namespace specified "sfo-w01-tkc01".

        .PARAMETER namespace
        The name of the Namespace.

        .PARAMETER tkc
        The name of the Tanzu Kubernetes Cluster.

        .PARAMETER detail
        The detailed information of the Tanzu Kubernetes Cluster.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tkc,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$detail
    )

    Try {
        if ($PsBoundParameters.ContainsKey("detail")) {
            if (!$tkc -and !$namespace) {
                Invoke-Expression "kubectl describe tkc --all-namespaces"
            } elseif (!$tkc -and $namespace) {
                Invoke-Expression "kubectl describe tkc -n $namespace"
            } elseif ($tkc -and !$namespace) {
                Write-Error "A resource cannot be retrieved by tkc name across all namespaces"
            } elseif ($tkc -and $namespace) {
                Invoke-Expression "kubectl describe tkc $tkc -n $namespace"
            }
        } else {
            if (!$tkc -and !$namespace) {
                Invoke-Expression "kubectl get tkc --all-namespaces"
            } elseif (!$tkc -and $namespace) {
                Invoke-Expression "kubectl get tkc -n $namespace"
            } elseif ($tkc -and !$namespace) {
                Write-Error "A resource cannot be retrieved by name across all namespaces"
            } elseif ($tkc -and $namespace) {
                Invoke-Expression "kubectl get tkc $tkc -n $namespace"
            }
        }
    } Catch {
        Write-Error = $_.Exception
    }
}
Export-ModuleMember -Function Get-TanzuKubernetesCluster

Function Remove-TanzuKubernetesCluster {
    <#
        .SYNOPSIS
        Remove a Tanzu Kubernetes cluster.

        .DESCRIPTION
        The Remove-TanzuKubernetesCluster cmdlet removes a Tanzu Kubernetes cluster

        .EXAMPLE
        Remove-TanzuKubernetesCluster -cluster sfo-w01-tkc01 -namespace sfo-w01-tkc01
        This example removes the Tanzu Kubernetes cluster.

        .PARAMETER cluster
        The name of the Tanzu Kubernetes cluster.

        .PARAMETER namespace
        The name of the Namespace.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace
    )

    Try {
        Invoke-Expression "kubectl delete tkc $cluster -n $namespace"
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-TanzuKubernetesCluster

Function Get-VMClass {
    <#
        .SYNOPSIS
        Retrieves information on a Virtual Machine class.

        .DESCRIPTION
        The Get-VMClass cmdlet retrieves information on a Virtual Machine class

        .EXAMPLE
        Get-VMClass
        This example retrieves all Virtual Machine classes

        .EXAMPLE
        Get-VMClass -vmClass guaranteed-small
        This example retrieves information on the Virtual Machine Class guaranteed-small

        .EXAMPLE
        Get-VMClass -namespace sfo-w01-tkc01
        This example retrieves Virtual Machine Classes assigned to the namespace sfo-w01-tkc01.

        .PARAMETER vmClass
        The name of the Virtual Machine class.

        .PARAMETER namespace
        The name of the Namespace.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet("guaranteed-medium", "guaranteed-large", "guaranteed-xlarge", "best-effort-4xlarge", "guaranteed-small", "best-effort-medium", "best-effort-2xlarge", "guaranteed-2xlarge", "best-effort-large", "guaranteed-4xlarge", "best-effort-8xlarge", "best-effort-xsmall", "guaranteed-xsmall", "best-effort-xlarge", "guaranteed-8xlarge", "best-effort-small")] [String]$vmClass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$namespace
    )

    Try {
        if ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$vcApiServer/api/vcenter/namespace-management/virtual-machine-classes/$vmClass"
            $response = Invoke-RestMethod -Method 'GET' -URI $uri -Headers $vcApiHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("namespace")) {
            $uri = "https://$vcApiServer/api/vcenter/namespaces/instances/$namespace"
            $response = Invoke-RestMethod -Method 'GET' -URI $uri -Headers $vcApiHeaders
            $response.vm_service_spec.vm_classes
        } else {
            $uri = " https://$vcApiServer/api/vcenter/namespace-management/virtual-machine-classes"
            $response = Invoke-RestMethod -Method 'GET' -URI $uri -Headers $vcApiHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-VMClass

Function Add-VMClass {
    <#
        .SYNOPSIS
        Retrieves information on a Virtual Machine class.

        .DESCRIPTION
        The Add-VMClass cmdlet retrieves information on a Virtual Machine class

        .EXAMPLE
        Add-VMClass -namespace sfo-w01-tkc01 -vmClass guaranteed-small
        This example retrieves all Virtual Machine classes.

        .PARAMETER vmClass
        The name of the Virtual Machine class.

        .PARAMETER namespace
        The name of the Namespace.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$namespace,
        [Parameter (Mandatory = $false)] [ValidateSet("guaranteed-medium", "guaranteed-large", "guaranteed-xlarge", "best-effort-4xlarge", "guaranteed-small", "best-effort-medium", "best-effort-2xlarge", "guaranteed-2xlarge", "best-effort-large", "guaranteed-4xlarge", "best-effort-8xlarge", "best-effort-xsmall", "guaranteed-xsmall", "best-effort-xlarge", "guaranteed-8xlarge", "best-effort-small")] [String]$vmClass
    )

    Try {
        $existingVmClass = Get-VMClass -namespace $namespace -ErrorAction Ignore
        if ($existingVmClass) {
            $newVmClass = New-Object System.Collections.Generic.List[System.Object]
            foreach ($assignedVMclass in $existingVmClass) {
                if (!($assignedVMclass -eq $vmClass)) {
                    $newVmClass += $assignedVMclass
                }
            }
            $newVmClass += $vmClass
            $jsonFormat = ConvertTo-Json $newVmClass

            $body = '{"vm_service_spec": { "vm_classes": '+ $jsonFormat +'}}'
        } else {
            $body = '{ "vm_service_spec": { "vm_classes": [ "' + $vmClass + '" ] }}'
        }

        $uri = "https://$vcApiServer/api/vcenter/namespaces/instances/$namespace"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vcApiHeaders -body $body 
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-VMClass

Function Get-WMLicenseStatus {
    <#
        .SYNOPSIS
        Get Workload Management license status.

        .DESCRIPTION
        The Get-WMLicenseStatus cmdlet gets the license status from vCenter Server for Workload Management

        .EXAMPLE
        Get-WMLicenseStatus
        This example gets the vSphere with Tanzu licenses status from vCenter Server for Workload Management.
    #>


    Try {
        $uri = "https://$vcApiServer/api/vcenter/namespace-management/capability"
        $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $vcApiHeaders
        $response

    } Catch {
        Debug-ExceptionWriter -object $_ 
    }
}
Export-ModuleMember -Function Get-WMLicenseStatus

Function Request-WMClusterCSR {
    <#
        .SYNOPSIS
        Request Certificate Signing Request filr.

        .DESCRIPTION
        The Request-WMClusterCSR cmdlet requests a Certificate Signing Request file for the Supervisor Cluster

        .EXAMPLE
        Request-WMClusterCSR -cluster sfo-w01-cl01 -commonName sfo-w01-cl01.sfo.rainpole.io -organization Rainpole -organizationalUnit Rainpole -country US -stateOrProvince California -locality "Palo Alto" -adminEmailAddress admin@rainpole.io -keySize 2048 -filePath ".\SupervisorCluster.csr"
        This example requetes a Certificate Signing Request file for the Supervisor Cluster sfo-w01-cl01.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER commonName
        The common name of the Supervisor Cluster.

        .PARAMETER organization
        The organization name of the Supervisor Cluster.

        .PARAMETER organizationalUnit
        The organizational unit name of the Supervisor Cluster.

        .PARAMETER country
        The country of the Supervisor Cluster.

        .PARAMETER stateOrProvince
        The state or province of the Supervisor Cluster.

        .PARAMETER locality
        The locality of the Supervisor Cluster.

        .PARAMETER adminEmailAddress
        The email address of the Supervisor Cluster administrator.

        .PARAMETER keySize
        The key size of the Supervisor Cluster.

        .PARAMETER filePath
        The path to the Certificate Signing Request file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$commonName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$organization,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$organizationalUnit,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$country,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$stateOrProvince,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$locality,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adminEmailAddress,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$keySize,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$filePath
    )

    Try {
        $uri = "https://$vcApiServer/api/vcenter/namespace-management/clusters"
        $clusterId = (Invoke-RestMethod -Method GET -URI $uri -Headers $vcApiHeaders | Where-Object { $_.cluster_name -eq $cluster }).cluster
        
        $output = New-Object -TypeName PSCustomObject
        $output | Add-Member -notepropertyname 'common_name' -notepropertyvalue $commonName
        $output | Add-Member -notepropertyname 'organization_name' -notepropertyvalue $organization
        $output | Add-Member -notepropertyname 'organization_unit_name' -notepropertyvalue $organizationalUnit
        $output | Add-Member -notepropertyname 'country' -notepropertyvalue $country
        $output | Add-Member -notepropertyname 'state_or_province' -notepropertyvalue $stateOrProvince
        $output | Add-Member -notepropertyname 'locality' -notepropertyvalue $locality
        $output | Add-Member -notepropertyname 'email_address' -notepropertyvalue $adminEmailAddress
        if ($PsBoundParameters.ContainsKey("keySize")) {
            $output | Add-Member -notepropertyname 'keySize' -notepropertyvalue $keySize
        }
        $body = $output | ConvertTo-Json
        $uri = "https://$vcApiServer/api/$clusterId/csr/tls-endpoint/"
        $response = Invoke-RestMethod -Method POST -Uri $uri -Headers $vcApiHeaders -body $body
        $response | Out-File -FilePath $filePath
        Write-Output "Certificate Signing Request (.csr) file for ($commonName) has been successfully saved to file ($filePath)"
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-WMClusterCSR

Function Install-WMClusterCertificate {
    <#
        .SYNOPSIS
        Installs a signed TLS certificate for the defined Supervisor Cluster.

        .DESCRIPTION
        The Install-WMClusterCertificate cmdlet installs a signed TLS certificate for the defined Supervisor Cluster

        .EXAMPLE
        Install-WMClusterCertificate -cluster sfo-w01-cl01 -filePath ".\SupervisorCluster.cer"
        This example installs the signed TLS certificate to Supervisor Cluster sfo-w01-cl01 in Workload domain sfo-w01.

        .PARAMETER cluster
        The name of the Supervisor Cluster.

        .PARAMETER filePath
        The path to the signed TLS certificate file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$cluster,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$filePath
    )

    Try {
        if ($PsBoundParameters.ContainsKey("filepath")) {
            if (!(Test-Path $filepath)) {
                Throw "Certificate File Not Found"
            } else {
                $certificate = Get-Content -Path $filePath -Raw -ErrorAction SilentlyContinue
                $inputFileName = Split-Path -Path $filePath -Leaf -ErrorAction SilentlyContinue
            }
        }
        if ($isMacOS -eq $true -or $isLinux -eq $true) {
            $certificateFormatted = $Certificate -Replace "`n","\n"
        } elseif ($isWindows -eq $true -or $PSEdition -eq "Desktop") {
            $certificateFormatted = $Certificate -Replace "`r`n","\n"
        } else {
            Write-Error "Unsupported Operating System"
            Break
        }
        if (($certificateFormatted | Measure-object -Line).Count -ne 1) {
            Write-Error "Error parsing TLS certificate"
            Break
        }
        $body = '{ "tls_endpoint_certificate": "' + $certificateFormatted + '" }' 
        $uri = "https://$vcApiServer/api/vcenter/namespace-management/clusters"
        $clusterId = (Invoke-RestMethod -Method GET -URI $uri -Headers $vcApiHeaders | Where-Object { $_.cluster_name -eq $cluster }).cluster
        $uri = "https://$vcApiServer/api/vcenter/namespace-management/clusters/$clusterId/"
        if ($PSEdition -eq 'Core') {
            $response = Invoke-WebRequest -Method PATCH -Uri $uri -Headers $vcApiHeaders -body $body -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented
        } else {
            $response = Invoke-WebRequest -Method PATCH -Uri $uri -Headers $vcApiHeaders -body $body -UseBasicParsing
        }
        if ($response.StatusCode -lt 300) {
            if ($inputFileName) {
                Write-Output "Signed Certificate ($inputFileName) has been successfully applied to Supervisor Cluster ($cluster)"
            } else {
                Write-Output "Signed Certificate has been successfully applied to Supervisor Cluster ($cluster)"
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-WMClusterCertificate

Function Watch-WmClusterConfigStatus {
    <#
        .SYNOPSIS
        Poll request.

        .DESCRIPTION
        The Watch-WmClusterConfigStatus cmdlet polls the status of wmCluster

        .EXAMPLE
        Watch-WmClusterConfigStatus -wmClusterName <wmCluster name>
        This example polls the status of wmCluster.

        .PARAMETER wmClusterName
        The name of the wmCluster.

        .PARAMETER retriesCount
        The number of retries.

        .PARAMETER sleepTime
        The sleep time between retries.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$wmClusterName,
        [Parameter (Mandatory = $false)]  [int]$retriesCount = 10,
        [Parameter (Mandatory = $false)]  [int]$sleepTime = 30
    )

    Try {
        $try = 1
        Do {
            $wmCluster = (Get-WMCluster -Cluster $wmClusterName -ErrorAction SilentlyContinue)
            Start-Sleep $sleepTime
            $try++
        } 
        Until (($wmCluster.ConfigStatus -ne "Configuring") -or ($try -gt $retriesCount))
        if ($try -gt $retriesCount) {
            Write-Error "Retries exeeded max count $retriesCount : CONFIGURATION_FAILED"
        }
        if ($wmCluster.ConfigStatus -ne "Running") {
            Write-Error "Workload management on cluster: $wmClusterName status: $($wmCluster.ConfigStatus)"
            write-Error "Workload management on cluster: $wmClusterName status messages: $($wmCluster.StatusMessages.Messages)"
        } else {
            Write-Output "Workload Management on cluster: $wmClusterName completed with status: $($wmCluster.ConfigStatus)"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Watch-WmClusterConfigStatus

#EndRegion End vSphere with Tanzu Functions ######
###################################################################################

###################################################################################
#Region Start VMware Aria Suite Lifecycle Functions ######

Function Request-vRSLCMToken {
    <#
        .SYNOPSIS
        Connects to the specified VMware Aria Suite Lifecycle and obtains authorization token.

        .DESCRIPTION
        The Request-vRSLCMToken cmdlet connects to the specified VMware Aria Suite Lifecycle and obtains an
        authorization token. It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-vRSLCMToken -fqdn xint-vrslcm01.rainpole.io -username vcfadmin@local -password VMw@re1!
        This example shows how to connect to the VMware Aria Suite Lifecycle appliance.

        .PARAMETER fqdn
        The fully qualified domain name of the VMware Aria Suite Lifecycle appliance.

        .PARAMETER username
        The username of the VMware Aria Suite Lifecycle appliance.

        .PARAMETER password
        The password of the VMware Aria Suite Lifecycle appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    $Global:vrslcmHeaders = createBasicAuthHeader $username $password
    $Global:vrslcmAppliance = $fqdn

    Try {
        # Validate credentials by executing an API call
        $uri = "https://$vrslcmAppliance/lcmversion"
        if ($PSEdition -eq 'Core') {
            $vrslcmResponse = Invoke-WebRequest -Method GET -Uri $uri -Headers $vrslcmHeaders -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vrslcmResponse = Invoke-WebRequest -Method GET -Uri $uri -Headers $vrslcmHeaders -UseBasicParsing
        }
        if ($vrslcmResponse.StatusCode -eq 200) {
            Write-Output "Successfully connected to the VMware Aria Suite Lifecycle Appliance: $vrslcmAppliance"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-vRSLCMToken

Function Get-vRSLCMHealth {
    <#
        .SYNOPSIS
        Check VMware Aria Suite Lifecycle Health Status.

        .DESCRIPTION
        The Get-vRSLCMHealth cmdlet checks VMware Aria Suite Lifecycle Health Status

        .EXAMPLE
        Get-vRSLCMHealth
        This example checks VMware Aria Suite Lifecycle Health Status.
    #>


    Try {
        $uri = "https://$vrslcmAppliance/lcm/health/api/v2/status"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMHealth

Function Get-vRSLCMLockerPassword {
    <#
        .SYNOPSIS
        Get paginated list of Passwords available in the Store.

        .DESCRIPTION
        The Get-vRSLCMLockerPassword cmdlet gets a paginated list of passwords available in the locker

        .EXAMPLE
        Get-vRSLCMLockerPassword
        This example gets all passwords in the locker

        .EXAMPLE
        Get-vRSLCMLockerPassword -vmid 83abd0fd-c92d-4d8f-a5e8-9a1fc4fa6009
        This example gets the details of a password based on the vmid

        .EXAMPLE
        Get-vRSLCMLockerPassword -alias xint-env-admin
        This example gets the details of a password based on the alias.

        .PARAMETER vmid
        The vmid of the password.

        .PARAMETER alias
        The alias of the password.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmid,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if ($PsBoundParameters.ContainsKey("vmid")) {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/passwords/$vmid"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("alias")){
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/passwords?aliasQuery=$alias"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response.passwords
        } else {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/passwords?size=19"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response.passwords
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMLockerPassword

Function Add-vRSLCMLockerPassword {
    <#
        .SYNOPSIS
        Creates a new Password in the locker.

        .DESCRIPTION
        The Add-vRSLCMLockerPassword cmdlet add as new passwords to the locker

        .EXAMPLE
        Add-vRSLCMLockerPassword -userName admin -alias xint-admin -password VMw@re1! -description "Password for Cross-Instance Admin"
        This example adda a password to the locker.

        .PARAMETER userName
        The username of the password.

        .PARAMETER alias
        The alias of the password.

        .PARAMETER password
        The password of the password.

        .PARAMETER description
        The description of the password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$description
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/passwords"
        if ($PsBoundParameters.ContainsKey("description")) {
            $body = '{
                "alias": "'
+ $alias + '",
                "password": "'
+ $password + '",
                "passwordDescription": "'
+ $description + '",
                "userName": "'
+ $userName + '"
            }'

        } else {
            $body = '{
                "alias": "'
+ $alias + '",
                "password": "'
+ $password + '",
                "userName": "'
+ $userName + '"
            }'
           
        }
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMLockerPassword

Function Remove-vRSLCMLockerPassword {
    <#
        .SYNOPSIS
        Delete a password based on vmid.

        .DESCRIPTION
        The Remove-vRSLCMLockerPassword cmdlet deletes a password from the locker

        .EXAMPLE
        Remove-vRSLCMLockerPassword -vmid
        This example delets the password with the vmid.

        .PARAMETER vmid
        The vmid of the password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmid
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/passwords/$vmid"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMLockerPassword

Function Get-vRSLCMLockerCertificate {
    <#
        .SYNOPSIS
        Get paginated list of certificates available in the locker.

        .DESCRIPTION
        The Get-vRSLCMLockerCertificate cmdlet gets a paginated list of certificates available in the locker

        .EXAMPLE
        Get-vRSLCMLockerCertificate
        This example gets all certificates in the locker

        .EXAMPLE
        Get-vRSLCMLockerCertificate -vmid 83abd0fd-c92d-4d8f-a5e8-9a1fc4fa6009
        This example gets the details of a certificate based on the vmid

        .EXAMPLE
        Get-vRSLCMLockerCertificate -alias xint-vrops01
        This example gets the details of a certificate based on the vmid.

        .PARAMETER vmid
        The vmid of the certificate.

        .PARAMETER alias
        The alias of the certificate.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmid,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if ($PsBoundParameters.ContainsKey("vmid")) {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/certificates/$vmid"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("alias")) {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/certificates"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response.certificates | Where-Object {$_.alias -eq $alias}
        } else {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/certificates"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response.certificates
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMLockerCertificate

Function Add-vRSLCMLockerCertificate {
    <#
        .SYNOPSIS
        Add a certificate to the VMware Aria Suite Lifecycle locker.

        .DESCRIPTION
        The Add-vRSLCMLockerCertificate cmdlet adds a certificate to the VMware Aria Suite Lifecycle locker

        .EXAMPLE
        Add-vRSLCMLockerCertificate
        This example gets all certificates in the locker

        .EXAMPLE
        Add-vRSLCMLockerCertificate -vrslcmFQDN xreg-vrslcm.rainpole.io -certificateAlias xint-vrops01 -certificatePassphrase VMware1! -certChainPath ".\vrops01.rainpole.io.cer".

        .PARAMETER vrslcmFQDN
        The fully qualified domain name of the VMware Aria Suite Lifecycle appliance.

        .PARAMETER certificateAlias
        The alias of the certificate.

        .PARAMETER certificatePassphrase
        The passphrase of the certificate.

        .PARAMETER certChainPath
        The path to the certificate chain file.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrslcmFQDN,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certificateAlias,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certificatePassphrase,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certChainPath
    )

    Try {
        $newPEMString
        foreach ($line in Get-Content $certChainPath) {
            $stringToAdd = $line + '\n'
            $newPEMString += $stringToAdd
        }
        $chain = [regex]::split($newPEMString, "-----BEGIN RSA PRIVATE KEY-----")[0] -replace ".{2}$"
        $key = [regex]::split($newPEMString, "-----END CERTIFICATE-----")[-1].substring(2)
        if (!$PsBoundParameters.ContainsKey("certificatePassphrase")) {
            $body = '{
                "alias": "'
+$certificateAlias+'",
                "certificateChain": "'
+$chain+'",
                "privateKey": "'
+$key+'"
            }'

        } else {
            $body = '{
                "alias": "'
+$certificateAlias+'",
                "certificateChain": "'
+$chain+'",
                "certificatePassphrase": "'
+$certificatePassphrase+'",
                "privateKey": "'
+$key+'"
            }'

            }
        $uri = "https://$vrslcmFQDN/lcm/locker/api/v2/certificates/import"
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -ContentType application/json -body $body
        $response.certInfo
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMLockerCertificate

Function Remove-vRSLCMLockerCertificate {
    <#
        .SYNOPSIS
        Delete a certificate based on vmid.

        .DESCRIPTION
        The Remove-vRSLCMLockerCertificate cmdlet deletes a certificate from the locker

        .EXAMPLE
        Remove-vRSLCMLockerCertificate -vmid
        This example delets the certificate with the vmid.

        .PARAMETER vmid
        The vmid of the certificate.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmid
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/certificates/$vmid"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMLockerCertificate

Function Get-vRSLCMLockerLicense {
    <#
        .SYNOPSIS
        Get paginated list of licenses available in the locker.

        .DESCRIPTION
        The Get-vRSLCMLockerLicense cmdlet gets a paginated list of licenses available in the locker

        .EXAMPLE
        Get-vRSLCMLockerLicense
        This example gets all licenses in the locker

        .EXAMPLE
        Get-vRSLCMLockerLicense -vmid 2b54b028-9eba-4d2f-b6ee-66428ea2b297
        This example gets the details of a license based on the vmid

        .EXAMPLE
        Get-vRSLCMLockerLicense -alias "VMware Aria Operations"
        This example gets the details of a license based on the alias name.

        .PARAMETER vmid
        The vmid of the license.

        .PARAMETER alias
        The alias of the license.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmid,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if ($PsBoundParameters.ContainsKey("vmid")) {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/licenses/detail/$vmid"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("alias")) {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/licenses/alias/$alias"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } else {
            $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/licenses"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMLockerLicense

Function Add-vRSLCMLockerLicense {
    <#
        .SYNOPSIS
        Creates a new license in the locker.

        .DESCRIPTION
        The Add-vRSLCMLockerLicense cmdlet adds as new license to the locker

        .EXAMPLE
        Add-vRSLCMLockerLicense -alias "VMware Aria Operations" -license "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
        This example adds a license to the locker.

        .PARAMETER alias
        The alias of the license.

        .PARAMETER license
        The license of the license.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$license
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/locker/api/v2/license/validate-and-add"
        $body = '{
            "alias": "'
+ $alias + '",
            "serialKey": "'
+ $license + '"
        }'
           

        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMLockerLicense

Function Remove-vRSLCMLockerLicense {
    <#
        .SYNOPSIS
        Delete a License based on vmid.

        .DESCRIPTION
        The Remove-vRSLCMLockerLicense cmdlet deletes a license from the locker

        .EXAMPLE
        Remove-vRSLCMLockerLicense -vmid
        This example delets the license with the vmid.

        .PARAMETER vmid
        The vmid of the license.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmid
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/locker/api/licenses/$vmid"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMLockerLicense

Function Get-vRSLCMDatacenter {
    <#
        .SYNOPSIS
        Get paginated list of datacenters in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMDatacenter cmdlet gets a paginated list of datacenters in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMDatacenter
        This example gets all datacenters in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMDatacenter -vmid 2b54b028-9eba-4d2f-b6ee-66428ea2b297
        This example gets the details of a datacenter based on the vmid

        .EXAMPLE
        Get-vRSLCMDatacenter -name sfo-m01-dc01
        This example gets the details of a datacenter based on the name.

        .PARAMETER vmid
        The vmid of the datacenter.

        .PARAMETER datacenterName
        The name of the datacenter.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmid,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$datacenterName
    )

    Try {
        if ($PsBoundParameters.ContainsKey("vmid")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$vmid"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("datacenterName")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterName"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMDatacenter

Function Add-vRSLCMDatacenter {
    <#
        .SYNOPSIS
        Add a datacenter in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Add-vRSLCMDatacenter cmdlet adds a datacenter in VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMDatacenter -datacenterName xint-m01-dc01 -location "San Francisco;California;US;37.77493;-122.41942"
        This example adds a datacenter in VMware Aria Suite Lifecycle.

        .PARAMETER datacenterName
        The name of the datacenter.

        .PARAMETER location
        The location of the datacenter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$location
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters"
        $body = '{
            "dataCenterName": "'
+ $datacenterName + '",
            "primaryLocation": "'
+ $location + '"
        }'
  
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMDatacenter

Function Remove-vRSLCMDatacenter {
    <#
        .SYNOPSIS
        Remove a datacenter from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Remove-vRSLCMDatacenter cmdlet removes a datacenter from VMware Aria Suite Lifecycle

        .EXAMPLE
        Remove-vRSLCMDatacenter -datacenterVmid <datacenter_vmid>
        This example removes a datacenter from VMware Aria Suite Lifecycle.

        .PARAMETER datacenterVmid
        The vmid of the datacenter.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterVmid
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterVmid"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMDatacenter

Function Get-vRSLCMDatacenterVcenter {
    <#
        .SYNOPSIS
        Get paginated list of vCenter Servers in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMDatacenterVcenter cmdlet gets a paginated list of vCenter Servers in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMDatacenterVcenter -datacenterVmid <datacenter_vmid>
        This example gets all vCenter Servers for a Datacenter

        .EXAMPLE
        Get-vRSLCMDatacenterVcenter -datacenterVmid <datacenter_vmid> -vcenterName sfo-m01-vc01
        This example gets a named vCenter Server for a datacenter

        .EXAMPLE
        Get-vRSLCMDatacenterVcenter -datacenterVmid <datacenter_vmid> -vcenterName sfo-m01-vc01 -environments
        This example gets all vCenter Servers for a Datacenter that is assigned to an Environemnt.

        .PARAMETER datacenterVmid
        The vmid of the datacenter.

        .PARAMETER vcenterName
        The name of the vCenter Server.

        .PARAMETER environments
        Switch to get all vCenter Servers for a Datacenter that is assigned to an Environemnt.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterVmid,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vcenterName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$environments
    )

    Try {
        if ($PsBoundParameters.ContainsKey("datacenterVmid") -and $PsBoundParameters.ContainsKey("vcenterName")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterVmid/vcenters/$vcenterName"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("datacenterVmid") -and $PsBoundParameters.ContainsKey("vcenterName") -and $PsBoundParameters.ContainsKey("environments")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterVmid/vcenters/$vcenterName/environments"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterVmid/vcenters"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMDatacenterVcenter

Function Add-vRSLCMDatacenterVcenter {
    <#
        .SYNOPSIS
        Add a vCenter Server to a Datacenter in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Add-vRSLCMDatacenterVcenter cmdlet adds a vCenter Servers to a Datacenter in VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMDatacenterVcenter -datacenterVmid <datacenter_vmid> -vcenterFqdn <vcenter_fqdn> -userLockerAlias <user_alias>
        This example adds a vCenter Server to a Datacenter.

        .PARAMETER datacenterVmid
        The vmid of the datacenter.

        .PARAMETER vcenterFqdn
        The fully qualified domain name of the vCenter Server.

        .PARAMETER userLockerAlias
        The alias of the user in the locker.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterVmid,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userLockerAlias
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterVmid/vcenters"
        $body = '{
            "vCenterHost": "'
 + $vcenterFqdn + '",
            "vCenterName": "'
 + ($vcenterFqdn.Split("."))[0] + '",
            "vcPassword": "locker:password:'
 + (Get-vRSLCMLockerPassword -alias $userLockerAlias).vmid + ':' + $userLockerAlias + '",
            "vcUsedAs": "MANAGEMENT",
            "vcUsername": "'
 + (Get-vRSLCMLockerPassword -alias $userLockerAlias).userName + '"
        }'

        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMDatacenterVcenter

Function Sync-vRSLCMDatacenterVcenter {
    <#
        .SYNOPSIS
        Trigger a vCenter Server inventory sync in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Sync-vRSLCMDatacenterVcenter cmdlet triggers a vCenter Server inventory sync VMware Aria Suite Lifecycle

        .EXAMPLE
        Sync-vRSLCMDatacenterVcenter -datacenterVmid <datacenter_vmid> -vcenterName <vcenter_name>
        This example triggers a vCenter Server inventory sync.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$datacenterVmid,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterName
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/datacenters/$datacenterVmid/vcenters/$vcenterName/data-collection"
        Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Sync-vRSLCMDatacenterVcenter

Function Get-vRSLCMEnvironment {
    <#
        .SYNOPSIS
        Get paginated list of environments in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMEnvironment cmdlet gets a paginated list of environments in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMEnvironment
        This example gets all environments in VMware Aria Suite Lifecycle.

        .PARAMETER vmid
        The vmid of the environment.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmid
    )

    Try {
        if ($PsBoundParameters.ContainsKey("vmid")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$vmid"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMEnvironment

Function Add-vRSLCMEnvironment {
    <#
        .SYNOPSIS
        Create an environment in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Add-vRSLCMEnvironment cmdlet to create an environment in VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMEnvironment -json (Get-Content -Raw .\vrli.json)
        This example creates an environment in VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMEnvironment -json (Get-Content -Raw .\vrli.json) -vmid c907c25b-1c61-465b-b7cb-4100ac1ce331 -addProduct
        This example adds a new product to an existing environment in VMware Aria Suite Lifecycle.

        .PARAMETER json
        The json file to create the environment.

        .PARAMETER vmid
        The vmid of the environment.

        .PARAMETER addProduct
        Switch to add a product to an existing environment.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json,
        [Parameter (Mandatory = $false, ParameterSetName = 'growth')] [ValidateNotNullOrEmpty()] [String]$environmentId,
        [Parameter (Mandatory = $false, ParameterSetName = 'growth')] [ValidateNotNullOrEmpty()] [Switch]$addProduct
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json") -and ($PsBoundParameters.ContainsKey("addProduct")) -and ($PsBoundParameters.ContainsKey("environmentId"))) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environmentId/products"
            $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $json
            $response
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments"
            $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $json
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMEnvironment

Function Remove-vRSLCMEnvironment {
    <#
        .SYNOPSIS
        Remove an environment from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Remove-vRSLCMEnvironment cmdlet removes an environment from VMware Aria Suite Lifecycle

        .EXAMPLE
        Remove-vRSLCMEnvironment -environmentId <environmentId>
        This example removes an environment from VMware Aria Suite Lifecycle.

        .PARAMETER environmentId
        The vmid of the environment.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentId,
        [Parameter (Mandatory = $false)] [ValidateSet('vrops','vra','vrni','vidm')] [String]$productId
    )

    Try {
        
        if ($PsBoundParameters.ContainsKey("productId")) {
            if ($productId -eq "vidm") {
                $body = '{ "deleteFromVcenter": false, "deleteLbFromSddc": true, "deleteWindowsVMs": false }'
            } else {
                $body = '{ "deleteFromVcenter": true, "deleteLbFromSddc": true, "deleteWindowsVMs": true }'
            }
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environmentId/products/$productId"
        } else {
            $body = '{ "deleteFromInventory": true, "deleteFromVcenter": true, "deleteLbFromSddc": true, "deleteWindowsVMs": true }'
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environmentId"
            
        }
        Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMEnvironment

Function Get-vRSLCMLoadbalancer {
    <#
        .SYNOPSIS
        Get paginated list of load balancers from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMLoadbalancer cmdlet gets a paginated list of load balancers from VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMLoadbalancer -type NSX_T
        This example gets all load balancers in VMware Aria Suite Lifecycle with a type of NSX_T.

        .PARAMETER type
        The type of load balancer.

        .PARAMETER available
        Switch to get only available load balancers.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('NSX_T','NSX_ALB','OTHERS')] [String]$type,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Bool]$available=$false
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/controller/all?isAvailable=$available&type=$type"
        Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMLoadbalancer

Function New-vRSLCMLoadbalancer {
    <#
        .SYNOPSIS
        Add a load balancer to VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRSLCMLoadbalancer cmdlet adds a new loadbalancers to VMware Aria Suite Lifecycle

        .EXAMPLE
        New-vRSLCMLoadbalancer -type NSX_T -loadBalancerIp 192.168.11.60 -loadBalancerFqdn xint-wsa01.rainpole.io
        This example adds load balancers in VMware Aria Suite Lifecycle with a type of NSX_T.

        .PARAMETER type
        The type of load balancer.

        .PARAMETER loadBalancerIp
        The IP address of the load balancer.

        .PARAMETER loadBalancerFqdn
        The fully qualified domain name of the load balancer.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('NSX_T')] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$loadBalancerIp,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$loadBalancerFqdn
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/controller/save"
        $Global:body = ' {
            "type": "'
+ $type +'",
            "userName": "",
            "controllerFqdn": "",
            "passwordReference": "",
            "loadBalancerFQDN": "'
+ $loadBalancerFqdn +'",
            "loadBalancerIP": "'
+ $loadBalancerIp +'",
            "controllerMeta": {},
            "loadBalancerMeta": {},
            "controllerIP": "",
            "controllerID": ""
        }'

        Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMLoadbalancer

Function Remove-vRSLCMLoadbalancer {
    <#
        .SYNOPSIS
        Delete a load balancer from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Remove-vRSLCMLoadbalancer cmdlet removes a load balancer from VMware Aria Suite Lifecycle

        .EXAMPLE
        Remove-vRSLCMLoadbalancer -type NSX_T -loadBalancerFqdn xint-wsa01.rainpole.io
        This example deletes the load balancer from VMware Aria Suite Lifecycle.

        .PARAMETER type
        The type of load balancer.

        .PARAMETER loadBalancerFqdn
        The fully qualified domain name of the load balancer.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('NSX_T','NSX_ALB','OTHERS')] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$loadBalancerFqdn
    )

    Try {
        $controllerId = ((Get-vRSLCMLoadbalancer -type $type) | Where-Object {$_.loadBalancerDetails -match $loadBalancerFqdn}).controller_id
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/controller/loadbalancer/delete?controllerID=$controllerId&loadBalancerFQDN=$loadBalancerFqdn"
        Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMLoadbalancer

Function Get-vRSLCMRequest {
    <#
        .SYNOPSIS
        Get all Requests.

        .DESCRIPTION
        The Get-vRSLCMRequest cmdlet gets all requests in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMRequest
        This example gets all requests VMware Aria Suite Lifecycle
        
        .EXAMPLE
        Get-vRSLCMRequest -requestId 0ee1a4a0-203a-4c87-a40e-65d9a450e398
        This example gets the request by id from VMware Aria Suite Lifecycle
        
        .EXAMPLE
        Get-vRSLCMRequest -requestId 0ee1a4a0-203a-4c87-a40e-65d9a450e398 -errorCauses
        This example gets the errors for a request by id from VMware Aria Suite Lifecycle.

        .PARAMETER requestId
        The requestId of the request.

        .PARAMETER errorCauses
        Switch to get the errors for a request by id.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$requestId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$errorCauses
    )

    Try {
        if ($PsBoundParameters.ContainsKey("requestId")) {
            $uri = "https://$vrslcmAppliance/lcm/request/api/v2/requests/$requestId"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("errorCauses")) {
            $uri = "https://$vrslcmAppliance/lcm/request/api/v2/requests/$requestId/error-causes"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        } else {
            $uri = "https://$vrslcmAppliance/lcm/request/api/v2/requests"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response | Select-Object -Property vmid, state, requestReason, requestType
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMRequest

Function Remove-vRSLCMRequest {
    <#
        .SYNOPSIS
        Delete a request .

        .DESCRIPTION
        The Remove-vRSLCMRequest cmdlet removes a request from VMware Aria Suite Lifecycle

        .EXAMPLE
        Remove-vRSLCMRequest -requestId <id>
        This example removes a request from VMware Aria Suite Lifecycle.

        .PARAMETER requestId
        The requestId of the request.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$requestId    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/request/requests/$requestId"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMRequest

Function Watch-vRSLCMRequest {
    <#
        .SYNOPSIS
        Poll request.

        .DESCRIPTION
        The Watch-vRSLCMRequest cmdlet polls a request in VMware Aria Suite Lifecycle

        .EXAMPLE
        Watch-vRSLCMRequest -vmid <vmid>
        This example polls the request in VMware Aria Suite Lifecycle.

        .PARAMETER vmid
        The vmid of the request.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmid
    )

    Try {
        Do {
            $requestStatus = (Get-vRSLCMRequest | Where-Object { $_.vmid -eq $vmid }).state
        } 
        Until ($requestStatus -ne "INPROGRESS")
        Write-Output "VMware Aria Suite Lifecycle request: $vmid completed with the following state: $requestStatus"
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Watch-vRSLCMRequest

Function Resume-vRSLCMRequest {
    <#
        .SYNOPSIS
        Retry a request.

        .DESCRIPTION
        The Resume-vRSLCMRequest cmdlet reties a request

        .EXAMPLE
        Resume-vRSLCMRequest -requestId 0ee1a4a0-203a-4c87-a40e-65d9a450e398
        This example reties the request based on the request ID provided.

        .PARAMETER requestId
        The requestId of the request.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$requestId
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/request/api/v2/requests/$requestId/retry"
        $response = Invoke-RestMethod $uri -Method 'PATCH' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Resume-vRSLCMRequest

Function Set-WorkspaceOneApplianceNtpConfig {
    <#
        .SYNOPSIS
        Configure Workspace ONE Access appliance NTP servers.

        .DESCRIPTION
        The Set-WorkspaceOneApplianceNtpConfig cmdlet configures Workspace ONE Access appliance NTP servers

        .EXAMPLE
        Set-WorkspaceOneApplianceNtpConfig -vmName sfo-wsa01 -rootPass VMw@re1! -ntpServer "ntp.sfo.rainpole.io,ntp.lax.rainpole.io"
        This example sets the NTP servers for Workspace ONE Access node sfo-wsa01 to ntp.sfo.rainpole.io and ntp.lax.rainpole.io.
        
        .PARAMETER vmName
        The name of the Workspace ONE Access node.

        .PARAMETER rootPass
        The root password of the Workspace ONE Access node.

        .PARAMETER ntpServer
        The NTP server to set on the Workspace ONE Access node.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rootPass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ntpServer
    )

    Try {
        $scriptCommand = '/usr/local/horizon/scripts/ntpServer.hzn --get'
        $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
        if ($output.ScriptOutput -match "^server=$ntpServer$") {
            Write-Warning "Configuring NTP on Workspace ONE Access Instance ($vmName) to NTP Server ($ntpServer), already performed: SKIPPED"
        } else {
            $scriptCommand = '/usr/local/horizon/scripts/ntpServer.hzn --set ' + $ntpServer
            $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
            $scriptCommand = '/usr/local/horizon/scripts/ntpServer.hzn --get'
            $output = Invoke-VMScript -VM $vmName -ScriptText $scriptCommand -GuestUser root -GuestPassword $rootPass -Server $vcfVcenterDetails.fqdn
            if ($output.ScriptOutput -match "^server=$ntpServer$") {
                Write-Output "Configuring NTP on Workspace ONE Access Instance ($vmName) to NTP Server ($ntpServer): SUCCESSFUL"
            } else {
                Write-Error "Configuring NTP on Workspace ONE Access Instance ($vmName) to NTP Server ($ntpServer): POST_VALIDATION_FAILED"
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-WorkspaceOneApplianceNtpConfig

Function New-vRSLCMAdapterOperation {
    <#
        .SYNOPSIS
        Add a VMware Aria Operations adapter via VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRSLCMAdapterOperation cmdlet to create a VMware Aria Operations adapter in VMware Aria Suite Lifecycle

        .EXAMPLE
        New-vRSLCMAdapterOperation -json .\addAdapter.json
        This example creates an adapter in VMware Aria Operations via VMware Aria Suite Lifecycle.

        .PARAMETER json
        The JSON file to use to create the adapter in VMware Aria Operations via VMware Aria Suite Lifecycle.

        .PARAMETER environmentId
        The environment ID to use to create the adapter in VMware Aria Operations via VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentId
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environmentId/vrops/adapterOperation"
        $response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMAdapterOperation

Function Get-vRSLCMProductNtpServer {
    <#
        .SYNOPSIS
        Get paginated list of product NTP servers in VMare Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMProductNtpServer cmdlet gets a paginated list of product NTP servers in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMProductNtpServer
        This example gets all product NTP servers in VMware Aria Suite Lifecycle.

        .PARAMETER ntpServer
        The NTP server to get from the product NTP configuration in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ntpServer
    )

    Try {
        if ($PsBoundParameters.ContainsKey("ntpServer")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/ntp-servers"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response | Where-Object {$_.hostName -match $ntpServer}
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/ntp-servers"
            $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMProductNtpServer

Function Remove-vRSLCMProductNtpServer {
    <#
        .SYNOPSIS
        Removes a specified NTP server from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Remove-vRSLCMProductNtpServer cmdlet removes a specified NTP server from VMware Aria Suite Lifecycle

        .EXAMPLE
        Remove-vRSLCMProductNtpServer -ntpServer ntp.lax.rainpole.io
        This example gets all product NTP servers in VMware Aria Suite Lifecycle.

        .PARAMETER ntpServer
        The NTP server to remove from the product NTP configuration in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$ntpServer
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v3/settings/ntp-servers?ntpHostname=$ntpServer"
        $response = Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMProductNtpServer

Function Get-vRSLCMApplianceNtpConfig {
    <#
        .SYNOPSIS
        Get appliance NTP configuration in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMApplianceNtpConfig cmdlet gets appliance NTP configuration in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMApplianceNtpConfig
        This example gets the appliance NTP configuration in VMware Aria Suite Lifecycle.
    #>


    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/system-details/time"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMApplianceNtpConfig

Function Add-vRSLCMProductNtpServer {
    <#
        .SYNOPSIS
        Add a server to product NTP configuration in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Add-vRSLCMProductNtpServer cmdlet adds a server tp product NTP configuration in VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMProductNtpServer -ntpServer "ntp.lax.rainpole.io" -ntpServerDesc "VCF NTP Server 2"
        This adds the server ntp.lax.rainpole.io to the product NTP configuration in VMware Aria Suite Lifecycle.

        .PARAMETER ntpServer
        The NTP server to add to the product NTP configuration in VMware Aria Suite Lifecycle.

        .PARAMETER ntpServerDesc
        The description of the NTP server to add to the product NTP configuration in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServerDesc
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/ntp-servers"
        $body = '{
            "hostName": "'
+ $ntpServer +'",
            "name": "'
+ $ntpServerDesc +'"
        }'

        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMProductNtpServer

Function Add-vRSLCMApplianceNtpConfig {
    <#
        .SYNOPSIS
        Add a server to appliance NTP configuration in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Add-vRSLCMApplianceNtpConfig cmdlet adds a server to appliance NTP configuration in VMware Aria Suite Lifecycle

        .EXAMPLE
        Add-vRSLCMApplianceNtpConfig -ntpServer ntp.lax.rainpole.io
        This adds the server ntp.lax.rainpole.io to the appliance NTP configuration in VMware Aria Suite Lifecycle.

        .PARAMETER ntpServer
        The NTP server to add to the appliance NTP configuration in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServer
    )

    $existingNtpServers = (Get-vRSLCMApplianceNtpConfig).ntpServers

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/settings/ntpsetting"
        $body = '{
                "syncWithHost": false,
                "ntpServerEnabled": true,
                "ntpServers": "'
+ $existingNtpServers +','+ $ntpServer+'"
            }'

        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRSLCMApplianceNtpConfig

Function Set-vRSLCMApplianceNtpConfig {
    <#
        .SYNOPSIS
        Sets the appliance NTP configuration in VMware Aria Suite Lifecycle to use only a specified NTP server.

        .DESCRIPTION
        The Set-vRSLCMApplianceNtpConfig cmdlet sets the appliance NTP configuration in VMware Aria Suite Lifecycle to use only a specified NTP server

        .EXAMPLE
        Add-vRSLCMApplianceNtpConfig -ntpServer ntp.sfo.rainpole.io
        This sets the appliance NTP configuration in VMware Aria Suite Lifecycle to use only NTP server ntp.sfo.rainpole.io.

        .PARAMETER ntpServer
        The NTP server to set the appliance NTP configuration in VMware Aria Suite Lifecycle to use.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ntpServer
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/settings/ntpsetting"
        $body = '{
                "syncWithHost": false,
                "ntpServerEnabled": true,
                "ntpServers": "'
+ $ntpServer +'"
            }'

        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRSLCMApplianceNtpConfig

Function Get-vRSLCMProductNode {
    <#
        .SYNOPSIS
        Gets the nodes in the VMware Aria Suite Lifecycle inventory for a specified environment and product.

        .DESCRIPTION
        The Get-vRSLCMProductNode cmdlet gets the nodes in the VMware Aria Suite Lifecycle inventory for a specified environment and product

        .EXAMPLE
        Get-vRSLCMProductNode -environmentName globalenvironment -product vidm
        This returns a list of nodes in the Workspace ONE Access instance managed by VMware Aria Suite Lifecycle.

        .PARAMETER environmentName
        The name of the environment in VMware Aria Suite Lifecycle.

        .PARAMETER product
        The name of the product in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environmentName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$product
    )

    $environmentId = (Get-vRSLCMEnvironment | Where-Object { $_.environmentName -match $environmentName }).environmentId

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environmentId/products/$product/deployed-vms"
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        $response
        }
    Catch [System.Net.WebException] {
        $PSCmdlet.ThrowTerminatingError($PSItem)
    }
}
Export-ModuleMember -Function Get-vRSLCMProductNode

Function Stop-vRSLCMProductNode {
    <#
        .SYNOPSIS
        Shuts down nodes in a VMware Aria Suite Lifecycle-managed product.

        .DESCRIPTION
        The Stop-vRSLCMProductNode cmdlet shuts down nodes in a VMware Aria Suite Lifecycle-managed product

        .EXAMPLE
        Stop-vRSLCMProductNode -environment globalenvironment -product vidm
        This example shuts down all nodes in the Workspace ONE Access instance managed by VMware Aria Suite Lifecycle.

        .PARAMETER environment
        The name of the environment in VMware Aria Suite Lifecycle.

        .PARAMETER product
        The name of the product in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environment,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$product
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environment/products/$product/power-off"
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Stop-vRSLCMProductNode

Function Start-vRSLCMProductNode {
    <#
        .SYNOPSIS
        Starts nodes in a VMware Aria Suite Lifecycle-managed product.

        .DESCRIPTION
        The Start-vRSLCMProductNode cmdlet starts nodes in a VMware Aria Suite Lifecycle-managed product

        .EXAMPLE
        Start-vRSLCMProductNode -environment globalenvironment -product vidm
        This example starts all nodes in the Workspace ONE Access instance managed by VMware Aria Suite Lifecycle.

        .PARAMETER environment
        The name of the environment in VMware Aria Suite Lifecycle.

        .PARAMETER product
        The name of the product in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$environment,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$product
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/environments/$environment/products/$product/power-on"
        $response = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Start-vRSLCMProductNode

Function Get-vRSLCMPSPack {
    <#
        .SYNOPSIS
        Get list of Product Support Packs.

        .DESCRIPTION
        The Get-vRSLCMPSPack cmdlet retrieves a list of available Product Support Packs for VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMPSPack
        This example retrieves a list of available Product Support Packs for VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMPSPack -checkOnline
        This example update the manifest of available Product Support Packs online for VMware Aria Suite Lifecycle.

        .PARAMETER checkOnline
        The switch to update the manifest of available Product Support Packs online for VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$checkOnline
    )

    Try {
        if ($PsBoundParameters.ContainsKey("checkOnline")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-pspack"
            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-pspack"
            Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMPSPack

Function Install-vRSLCMPSPack {
    <#
        .SYNOPSIS
        Install a Product Support Pack.

        .DESCRIPTION
        The Install-vRSLCMPSPack cmdlet installs a Product Support Pack on VMware Aria Suite Lifecycle

        .EXAMPLE
        Install-vRSLCMPSPack -pspackId 8b96b2fa-ec34-491c-a7aa-ef81103f089f
        This example installs a Product Support Pack on VMware Aria Suite Lifecycle.

        .PARAMETER pspackId
        The Product Support Pack ID to install on VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pspackId
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-pspack/$pspackId"
        Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Install-vRSLCMPSPack

Function Get-vRSLCMProductBinariesMapped {
    <#
        .SYNOPSIS
        Get list of mapped product binaries.

        .DESCRIPTION
        The Get-vRSLCMProductBinariesMapped cmdlet retrieves a list of mapped product binaries in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMProductBinariesMapped
        This example retrieves a list of mapped Product Binaries in VMware Aria Suite Lifecycle.
    #>


    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/product-binaries"
        Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMProductBinariesMapped

Function Get-vRSLCMProductBinaries {
    <#
        .SYNOPSIS
        Get list of product binaries.

        .DESCRIPTION
        The Get-vRSLCMProductBinaries cmdlet retrieves a list of product binaries in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMProductBinaries -sourceLocation /data -sourceType Local
        This example retrieves a list of product binaries in VMware Aria Suite Lifecycle located in the absolute path /data.

        .PARAMETER sourceLocation
        The absolute path to the product binaries in VMware Aria Suite Lifecycle.

        .PARAMETER sourceType
        The type of source for the product binaries in VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sourceLocation,
        [Parameter (Mandatory = $true)] [ValidateSet('Local', 'NFS')] [String]$sourceType
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/product-binaries"
        $body = '{
            "sourceLocation": "'
 + $sourceLocation + '",
            "sourceType": "'
 + $sourceType + '"
        }'

        Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMProductBinaries

Function Register-vRSLCMProductBinary {
    <#
        .SYNOPSIS
        Get list of product binaries.

        .DESCRIPTION
        The Register-vRSLCMProductBinary cmdlet retrieves a list of mapped product binaries in VMware Aria Suite Lifecycle

        .EXAMPLE
        Register-vRSLCMProductBinary -ovaName vRealize-Operations-Manager-Appliance-8.10.2.21178503_OVF10.ova -ovaPath /data/vRealize-Operations-Manager-Appliance-8.10.2.21178503_OVF10.ova -ovaType install
        This example adds the binary to VMware Aria Suite Lifecycle.

        .PARAMETER ovaName
        The name of the OVA to add to VMware Aria Suite Lifecycle.

        .PARAMETER ovaPath
        The absolute path to the OVA to add to VMware Aria Suite Lifecycle.

        .PARAMETER ovaType
        The type of OVA to add to VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ovaName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ovaPath,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ovaType
    )

    Try {
        $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/product-binaries/download"
        $body = '[ {
            "name": "'
 + $ovaName + '",
            "filePath":"'
 + $ovaPath + '",
            "type": "'
 + $ovaType + '"
        }]'

        $responseid = Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        Start-Sleep 10
        Do {
            $response = Get-vRSLCMRequest -requestId $responseid.requestId
        } Until ($response.state -ne "INPROGRESS")
        Write-Host "Product Source Mapping Request Finished With Status: $($response.state)"
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Register-vRSLCMProductBinary

Function Get-vRSLCMMyVmwareAccount {
    <#
        .SYNOPSIS
        Get My VMware accounts from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMMyVmwareAccount cmdlet retrieves the My VMware accounts assigned in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMMyVmwareAccount
        This example retrieves all the My VMware Accounts assigned in VMware Aria Suite Lifecycle.
    #>


    Try {
        if ($vrslcmAppliance) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/my-vmware/accounts"
            Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMMyVmwareAccount

Function New-vRSLCMMyVmwareAccount {
    <#
        .SYNOPSIS
        Add a My VMware account to VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The New-vRSLCMMyVmwareAccount cmdlet adds a My VMware account to VMware Aria Suite Lifecycle

        .EXAMPLE
        New-vRSLCMMyVmwareAccount -alias rainpole
        This example adds a new My VMware account to VMware Aria Suite Lifecycle.

        .PARAMETER alias
        The alias of the My VMware account to add to VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if ($vrslcmAppliance) {
            if ($password = Get-vRSLCMLockerPassword -alias $alias) {
                $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/my-vmware/accounts"
                $body = '{
                    "password": "locker:password:'
+ $password.vmid + ':' + $alias + '",
                    "userName": "'
+ $password.userName + '"
                    }'

                Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
            }
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRSLCMMyVmwareAccount

Function Remove-vRSLCMMyVmwareAccount {
    <#
        .SYNOPSIS
        Remove a My VMware account from VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Remove-vRSLCMMyVmwareAccount cmdlet removes a My VMware account from VMware Aria Suite Lifecycle

        .EXAMPLE
        Remove-vRSLCMMyVmwareAccount -alias rainpole
        This example removes a My VMware account from VMware Aria Suite Lifecycle.

        .PARAMETER alias
        The alias of the My VMware account to remove from VMware Aria Suite Lifecycle.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alias
    )

    Try {
        if ($vrslcmAppliance) {
            if ($password = Get-vRSLCMLockerPassword -alias $alias) {
                $uri = "https://$vrslcmAppliance/lcm/lcops/api/settings/myvmwaresetting/delete"
                $body = '{
                    "password": "locker:password:'
+ $password.vmid + ':' + $alias + '",
                    "userName": "'
+ $password.userName + '"
                    }'

                Invoke-RestMethod $uri -Method 'DELETE' -Headers $vrslcmHeaders -Body $body
            }
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRSLCMMyVmwareAccount

Function Get-vRSLCMProductVersion {
    <#
        .SYNOPSIS
        Get supported version for a product.

        .DESCRIPTION
        The Get-vRSLCMProductVersion cmdlet retrieves supported versions of a product from VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMProductVersion -productId vra
        This example retrieves the supported versions for VMware Aria Automation.

        .PARAMETER productId
        The product to get the supported versions for.
    #>

    
    Param (
        [Parameter (Mandatory = $false)] [ValidateSet("vidm", "vra", "vrli", "vrni", "vrops", "vro", "vssc")][ValidateNotNullOrEmpty()] [String]$productId
    )

    Try {
        if ($vrslcmAppliance) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/policy/products/$productId/versions"
            Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMProductVersion

Function Request-vRSLCMProductBinary {
    <#
        .SYNOPSIS
        Downloads a VMware Aria Suite binary.

        .DESCRIPTION
        The Request-vRSLCMProductBinary cmdlet downloads a VMware Aria suite product binary through the My VMware
        account to VMware Aria Suite Lifecycle

        .EXAMPLE
        Request-vRSLCMProductBinary -version 8.14.0 -productId "vra" -productDownloadType "Install"
        This example will download the VMware Aria Automation install binary for verison 8.14.0

        .EXAMPLE
        Request-vRSLCMProductBinary -version 8.14.0 -productId "vra" -productDownloadType "upgrade"
        This example will download the VMware Aria Automation upgrade binary for verison 8.14.0.

        .PARAMETER version
        The version of the product binary to download.

        .PARAMETER productId
        The product ID of the product binary to download.

        .PARAMETER productDownloadType
        The type of product binary to download.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$version,
        [Parameter (Mandatory = $false)] [ValidateSet("vidm", "vra", "vrli", "vrni", "vrops", "vro", "vssc")][ValidateNotNullOrEmpty()] [String]$productId,
        [Parameter (Mandatory = $true)] [ValidateSet("Install", "upgrade")][ValidateNotNullOrEmpty()] [String]$productDownloadType

    )

    Switch ($productId) {
        "vra" { $productName = "VMware Aria Automation" }
        "vssc" { $productName = "VMware Aria Automation Config" }
        "vrops" { $productName = "VMware Aria Operations" }
        "vrli" { $productName = "VMware Aria Operations for Logs" }
        "vidm" { $productName = "VMware Identity Manager" }
        "vrni" { $productName = "VMware Aria Operations for Networks" }
    }

    Try {
        if ($vrslcmAppliance) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/my-vmware/product-binaries/download"
            $body = '{
                "productId": "'
+ $productId + '",
                "productVersion": "'
+ $version + '",
                "productName": "'
+ $productName + '",
                "productBinaryType": "'
+ $productDownloadType + '"
            }'

            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-vRSLCMProductBinary

Function Get-vRSLCMSshStatus {
    <#
        .SYNOPSIS
        Get the status of the SSH service in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Get-vRSLCMSshStatus cmdlet gets the status of the SSH Server in VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMSshStatus
        This example gets the SSH services.
    #>


    Try {
        if ($vrslcmAppliance) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/ssh"
            Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMSshStatus

Function Set-vRSLCMSshStatus {
    <#
        .SYNOPSIS
        Set the status of the SSH service in VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Set-vRSLCMSshStatus cmdlet sets the status of the SSH Server in VMware Aria Suite Lifecycle

        .EXAMPLE
        Set-vRSLCMSshStatus -enabled false
        This example disables the SSH services.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('true','false')] [String]$enabled
    )

    Try {
        if ($vrslcmAppliance) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/settings/ssh"
            $body = '{"sshStatus": "'+ $enabled +'"}'
            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRSLCMSshStatus

Function Start-vRSLCMSnapshot {
    <#
        .SYNOPSIS
        Create snapshot of the VMware Aria Suite Lifecycle appliance

        .DESCRIPTION
        The Start-vRSLCMSnapshot cmdlet starts the operation to create a snapshot of the VMware Aria Suite Lifecycle
        appliance.

        .EXAMPLE
        Start-vRSLCMSnapshot -vcenterFqdn sfo-m01-vc01.sfo.rainpole.io -vcenterName sfo-m01-vc01 -username svc-xint-vrslcm01-sfo-m01-vc01@vsphere.local
        This example creates a snapshot of the VMware Aria Suite Lifecycle appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username
    )

    Try {
        if ($vrslcmAppliance) {
            $userDetails = Get-vRSLCMLockerPassword | Where-Object {$_.userName -eq $username}
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-snapshot"
            $body = '{
                "vCenterHost": "'
 + $vcenterFqdn + '",
                "vCenterName": "'
 + $vcenterName + '",
                "vcPassword": "locker:password:'
 + $userDetails.vmid + ':' + $userDetails.alias + '",
                "vcUsedAs": "MANAGEMENT",
                "vcUsername": "'
 + $username + '"
            }'

            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        } else {
            Write-Error "Not connected to VMware Aria Suite Lifecycle, run Request-vRSLCMToken and try again"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Start-vRSLCMSnapshot

Function Get-vRSLCMUpgradeStatus {
    <#
        .SYNOPSIS
        Check an upgrade status for VMware Aria Suite Lifecycle

        .DESCRIPTION
        The Get-vRSLCMUpgradeStatus cmdlet checks the upgrade status for VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMUpgradeStatus
        This example retrieves the upgrade status for VMware Aria Suite Lifecycle

        .EXAMPLE
        Get-vRSLCMUpgradeStatus -history
        This example retrieves the upgrade history for VMware Aria Suite Lifecycle

        .PARAMETER history
        Displays the upgrade history.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$history
    )

    Try {
        if ($PsBoundParameters.ContainsKey("history")) {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-upgrade/history"
        } else {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/upgradeLcmVa"
        }
        Invoke-RestMethod $uri -Method 'GET' -Headers $vrslcmHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRSLCMUpgradeStatus

Function Start-vRSLCMUpgrade {
    <#
        .SYNOPSIS
        Perform upgrade operations on VMware Aria Suite Lifecycle.

        .DESCRIPTION
        The Start-vRSLCMUpgrade cmdlet performs a number of upgrade related operations on VMware Aria Suite Lifecycle.
        These include checking for upgrade binares, performing pre-validaion and starting the upgrade.

        .EXAMPLE
        Start-vRSLCMUpgrade -type CDROM -userName vcfadmin@local -password VMw@re1! -action check
        This example checks the CDROM for an upgrade package

        .EXAMPLE
        Start-vRSLCMUpgrade -type CDROM -username vcfadmin@local -password VMw@re1! -action prevalidate
        This example starts an upgrade precheck

        .EXAMPLE
        Start-vRSLCMUpgrade -type CDROM -username vcfadmin@local -password VMw@re1! -action upgrade
        This example starts the upgrade

        .PARAMETER type
        The location for the upgrade ISO file (Options are CDROM, URL).

        .PARAMETER username
        The VMware Aria Suite Lifecycle administrative user (e.g. vcfadmin@local).

        .PARAMETER password
        The VMware Aria Suite Lifecycle administrative user.

        .PARAMETER action
        The operation to perform (Options are check, upgrade, prevalidate or prepare).

        .PARAMETER url
        The url of the upgrade ISO if type is url.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('CDROM','URL')] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $true)] [ValidateSet('check','upgrade','prevalidate','prepare')] [String]$action,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$url
    )

    Try {
        if ($action -eq "prevalidate") {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-upgrade/prevalidate"
            $body = '{
                "repositoryType": "'
+ $type + '",
                "repositoryUrl": "'
+ $url + '",
                "repositoryUserName": "'
+ $userName + '",
                "repositoryPassword": "'
+ $password + '",
                "actionType": "'
+ $action + '"
            }'

            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        } elseif ($action -eq "check") {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/upgradeLcmVa"
            $body = '{
                "repositoryType": "'
+ $type + '",
                "repositoryUrl": "'
+ $url + '",
                "repositoryUserName": "'
+ $userName + '",
                "repositoryPassword": "'
+ $password + '",
                "actionType": "'
+ $action + '"
            }'

            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        } elseif ($action -eq "upgrade") {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/upgradeLcmVa"
            $body = '{
                "repositoryType": "'
+ $type + '",
                "repositoryUrl": "'
+ $url + '",
                "repositoryUserName": "'
+ $userName + '",
                "repositoryPassword": "'
+ $password + '",
                "actionType": "'
+ $action + '"
            }'

            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders -Body $body
        } elseif ($action -eq "prepare") {
            $uri = "https://$vrslcmAppliance/lcm/lcops/api/v2/system-upgrade/prepare"
            Invoke-RestMethod $uri -Method 'POST' -Headers $vrslcmHeaders
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Start-vRSLCMUpgrade

#EndRegion End VMware Aria Suite Lifecycle Functions ######
###################################################################################

###################################################################################
#Region Start VMware Aria Automation Functions ######

Function Request-vRAToken {
    <#
        .SYNOPSIS
        Connects to the specified VMware Aria Automation and obtains authorization token.

        .DESCRIPTION
        The Request-vRAToken cmdlet connects to the specified VMware Aria Automation and obtains an authorization token.
        It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-vRAToken -fqdn xreg-vra01.rainpole.io -username configadmin -password VMware1!
        This example shows how to connect to the VMware Aria Automation appliance

        .EXAMPLE
        Request-vRAToken -fqdn xreg-vra01.rainpole.io -username configadmin -password VMware1! -displayToken
        This example shows how to connect to the VMware Aria Automation appliance and display the token needed for Terraform.

        .PARAMETER fqdn
        The fully qualified domain name of the VMware Aria Automation appliance.

        .PARAMETER username
        The username to connect to the VMware Aria Automation appliance.

        .PARAMETER password
        The password to connect to the VMware Aria Automation appliance.

        .PARAMETER tenant
        The tenant to connect to the VMware Aria Automation appliance.

        .PARAMETER displayToken
        Displays the token needed for Terraform.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tenant,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$displayToken
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    $vraBasicHeaders = createBasicAuthHeader $username $password
    $Global:vraAppliance = $fqdn

    Try {
        # Validate credentials by executing an API call
        $uri = "https://$vraAppliance/csp/gateway/am/api/login?access_token"
        if ($PsBoundParameters.ContainsKey("tenant")) {
            $body = "{ ""username"":""$username"",""password"":""$password"",""domain"":""$tenant""}"
        } else {
            $body = "{ ""username"":""$username"",""password"":""$password""}"
        }

        if ($PSEdition -eq 'Core') {
            $vraResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $vraBasicHeaders -Body $body -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vraResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $vraBasicHeaders -Body $body -UseBasicParsing
        }

        if ($vraResponse.StatusCode -eq 200) {
            $Global:vraHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
            $vraHeaders.Add("Accept", "application/json")
            $vraHeaders.Add("Content-Type", "application/json")
            $vraHeaders.Add("Authorization", "Bearer " + $vraResponse.Headers.'Csp-Auth-Token')
            Write-Output "Successfully connected to VMware Aria Automation: $vraAppliance"
            if ($PsBoundParameters.ContainsKey("displayToken")) {
                Write-Output "`n---------Refresh Token---------"
                ((Select-String -InputObject $vraResponse -Pattern '"refresh_token":') -Split ('"'))[3]
                Write-Output "-------------------------------`n"
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-vRAToken

Function Get-vRAOrganizationId {
    <#
        .SYNOPSIS
        Get the organization ID for the logged in user.

        .DESCRIPTION
        The Get-vRAOrganizationId cmdlet gets the organization Id for the logged in user

        .EXAMPLE
        Get-vRAOrganizationId
        This example gets organization Id for the logged in user.
    #>


    Try {
        $uri = "https://$vraAppliance/csp/gateway/am/api/loggedin/user/orgs"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response.refLinks
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRAOrganizationId

Function Get-vRAOrganizationDisplayName {
    <#
        .SYNOPSIS
        Get the organization display name.

        .DESCRIPTION
        The Get-vRAOrganizationDisplayName cmdlet gets the organization display name

        .EXAMPLE
        Get-vRAOrganizationDisplayName -orgId <orgid>
        This example gets organization display name for the organization Id provided.

        .PARAMETER orgId
        The organization Id to get the display name for.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/am/api/orgs/$orgId"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRAOrganizationDisplayName

Function Set-vRAOrganizationDisplayName {
    <#
        .SYNOPSIS
        Configures the organization display name.

        .DESCRIPTION
        The Set-vRAOrganizationDisplayName cmdlet sets the organization display name

        .EXAMPLE
        Set-vRAOrganizationDisplayName -orgId <orgid> -displayName
        This example configures the organization display name for the organization Id provided.

        .PARAMETER orgId
        The organization Id to configure.

        .PARAMETER displayName
        The display name to configure.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$displayName
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/am/api/orgs/$orgId"
        $json = '{ "displayName": "' + $displayName + '" }'
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $json
        $response.refLink
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRAOrganizationDisplayName

Function Get-vRACloudAccount {
    <#
        .SYNOPSIS
        Get cloud accounts.

        .DESCRIPTION
        The Get-vRACloudAccount cmdlet all cloud accounts within the current organization

        .EXAMPLE
        Get-vRACloudAccount
        This example gets all cloud accounts within the current organization

        .EXAMPLE
        Get-vRACloudAccount -type vsphere
        This example gets all vsphere cloud accounts within the current organization, supports vsphere, vmw, gcp, nsx-v, nsx-t, aws and azure.

        .PARAMETER type
        The type of cloud account to get.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet("vsphere", "vmc", "gcp", "nsx-v", "nsx-t", "aws", "azure")] [ValidateNotNullOrEmpty()] [String]$type
    )

    Try {
        if ($PsBoundParameters.ContainsKey("type")) {
            if ($type -eq "vsphere") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-vsphere" }
            if ($type -eq "vmc") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-vmc" }
            if ($type -eq "gcp") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-gcp" }
            if ($type -eq "nsx-v") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-nsx-v" }
            if ($type -eq "nsx-t") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-nsx-t" }
            if ($type -eq "aws") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-aws" }
            if ($type -eq "azure") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-azure" }
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response.content
        } else {
            $uri = "https://$vraAppliance/iaas/api/cloud-accounts"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response.content
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRACloudAccount

Function Add-vRACloudAccount {
    <#
        .SYNOPSIS
        Add a cloud account.

        .DESCRIPTION
        The Add-vRACloudAccount cmdlet adds a cloud accounts within the current organization

        .EXAMPLE
        Add-vRACloudAccount -type vsphere -json (Get-Content -raw .\vsphereCloudAccount.json)
        This example adds a vSphere cloud account within the current organization

        .EXAMPLE
        Add-vRACloudAccount -type nsx-t -json (Get-Content -raw .\nsxCloudAccount.json)
        This example adds a NSX cloud account within the current organization.

        .PARAMETER type
        The type of cloud account to add.

        .PARAMETER json
        The json file to use to add the cloud account.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vsphere", "vmc", "gcp", "nsx-v", "nsx-t", "aws", "azure")] [ValidateNotNullOrEmpty()] [String]$type,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        if ($type -eq "vsphere") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-vsphere" }
        if ($type -eq "vmc") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-vmc" }
        if ($type -eq "gcp") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-gcp" }
        if ($type -eq "nsx-v") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-nsx-v" }
        if ($type -eq "nsx-t") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-nsx-t" }
        if ($type -eq "aws") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-aws" }
        if ($type -eq "azure") { $uri = "https://$vraAppliance/iaas/api/cloud-accounts-azure" }
        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vraHeaders -Body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRACloudAccount

Function Remove-vRACloudAccount {
    <#
        .SYNOPSIS
        Remove a cloud account.

        .DESCRIPTION
        The Remove-vRACloudAccount cmdlet removes a cloud account within the current organization

        .EXAMPLE
        Remove-vRACloudAccount -id <id>
        This example removes the cloud account with the ID within the current organization.

        .PARAMETER id
        The ID of the cloud account to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vraAppliance/iaas/api/cloud-accounts/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRACloudAccount

Function Get-vRANotification {
    <#
        .SYNOPSIS
        Get notification configuration.

        .DESCRIPTION
        The Get-vRANotification cmdlet gets the notification configuation from VMware Aria Automation

        .EXAMPLE
        Get-vRANotification
        This example gets the current notification configuration from VMware Aria Automation.
    #>


    Try {
        $uri = "https://$vraAppliance/notification/api/email-config"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRANotification

Function New-vRANotification {
    <#
        .SYNOPSIS
        Add notification configuration.

        .DESCRIPTION
        The New-vRANotification cmdlet adds the notification configuation in VMware Aria Automation

        .EXAMPLE
        New-vRANotification -name smtp.rainpole.io -serverName smtp.rainpole.io -emailAddress vra-no-reply@rainpole.io -sender administrator -trustCert true -connection NONE -authentication false
        This example adds the notification configuration in VMware Aria Automation without authentication

        .EXAMPLE
        New-vRANotification -name smtp.rainpole.io -serverName smtp.rainpole.io -emailAddress vra-no-reply@rainpole.io -sender administrator -trustCert true -connection NONE -authentication true -username administrator -password VMw@re1!
        This example adds the notification configuration in VMware Aria Automation with authentication.

        .PARAMETER name
        The name of the notification configuration.

        .PARAMETER serverName
        The name of the SMTP server.

        .PARAMETER emailAddress
        The email address to send notifications from.

        .PARAMETER sender
        The name of the sender.

        .PARAMETER trustCert
        Trust the certificate of the SMTP server.

        .PARAMETER connection
        The connection type, NONE, SSL or STARTTLS.

        .PARAMETER authentication
        Enable authentication.

        .PARAMETER userName
        The username to authenticate with.

        .PARAMETER password
        The password to authenticate with.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serverName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$emailAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sender,
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [ValidateNotNullOrEmpty()] [String]$trustCert,
        [Parameter (Mandatory = $true)] [ValidateSet("SSL", "STARTTLS", "NONE")] [ValidateNotNullOrEmpty()] [String]$connection,
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [ValidateNotNullOrEmpty()] [String]$authentication,
        [Parameter (ParameterSetName = "auth", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$userName,
        [Parameter (ParameterSetName = "auth", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
        
    )

    Try {
        if ($connection -eq "SSL") { $port = "465" } elseif ($connection -eq "STARTTLS") { $port = "587" } else { $port = "25" }
        $uri = "https://$vraAppliance/notification/api/email-config"
        $body = '{
            "name": "'
 + $name + '",
            "host": "'
 + $serverName + '",
            "port": '
 + $port + ',
            "sender": "'
 + $emailAddress + '",
            "senderName": "'
 + $sender + '",
            "connectionSecurity": "'
 + $connection + '",
            "authenticationRequired": '
 + $authentication + ',
            "userName": "'
 + $userName + '",
            "password": "'
 + $password + '",
            "trustHost": '
 + $trustCert + '
        }'

        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vraHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRANotification

Function Remove-vRANotification {
    <#
        .SYNOPSIS
        Remove notification configuration.

        .DESCRIPTION
        The Remove-vRANotification cmdlet removes the notification configuation from VMware Aria Automation

        .EXAMPLE
        Remove-vRANotification
        This example removes the current notification configuration from VMware Aria Automation.
    #>


    Try {
        $uri = "https://$vraAppliance/notification/api/email-config"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRANotification

Function Get-vRAResourceCompute {
    <#
        .SYNOPSIS
        Get compute resources.

        .DESCRIPTION
        The Get-vRAResourceCompute cmdlet gets a list of known compute resources from VMware Aria Automation

        .EXAMPLE
        Get-vRAResourceCompute
        This example gets all known compute resources from VMware Aria Automation

        .EXAMPLE
        Get-vRAResourceCompute -id <compute_resource_id>
        This example gets a compute resource from VMware Aria Automation by id.

        .PARAMETER id
        The compute resource id to get.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vraAppliance/iaas/api/fabric-computes/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response
        } else {
            $uri = "https://$vraAppliance/iaas/api/fabric-computes"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response.content
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRAResourceCompute

Function Add-vRAResourceComputeTag {
    <#
        .SYNOPSIS
        Add a compute resource tag.

        .DESCRIPTION
        The Add-vRAResourceComputeTag cmdlet adds a tag to a compute resources in VMware Aria Automation

        .EXAMPLE
        Add-vRAResourceComputeTag -id <compute_resource_id> -tagKey enabled -tagValue true
        This example adds a new tag to a compute resourcein VMware Aria Automation.

        .PARAMETER id
        The compute resource id to add the tag to.

        .PARAMETER tagKey
        The tag key to add.

        .PARAMETER tagValue
        The tag value to add.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tagKey,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tagValue
    )

    Try {
        $existingTags = (Get-vRAResourceCompute -id $id | Select-Object tags).tags
        $tagObject = @()
        foreach ($tag in $existingTags) {
            if ($tag.key -ne $tagKey) {
                $tagObject += [pscustomobject]@{
                    'key'   = $tag.key
                    'value' = $tag.value
                }
            } elseif ($tag.key -eq $tagKey) {
                $tagObject += [pscustomobject]@{
                    'key'   = $tagkey
                    'value' = $tagvalue
                }
            }
        }
        if (!($tagObject.key -eq $tagKey)) {
            $tagObject += [pscustomobject]@{
                'key'   = $tagkey
                'value' = $tagvalue
            }
        }
        $allTagsObject = @()
        $allTagsObject += [pscustomobject]@{
            'tags' = $tagObject
        }
        $json = $allTagsObject | ConvertTo-Json -Depth 3
        $uri = "https://$vraAppliance/iaas/api/fabric-computes/$id"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRAResourceComputeTag

Function Get-vRACloudZone {
    <#
        .SYNOPSIS
        Get Cloud Zones.

        .DESCRIPTION
        The Get-vRACloudZone cmdlet gets a list of known Cloud Zones from VMware Aria Automation

        .EXAMPLE
        Get-vRACloudZone
        This example gets all known Cloud Zones from VMware Aria Automation

        .EXAMPLE
        Get-vRACloudZone -id <cloud_zone_id>
        This example gets a Cloud Zone from VMware Aria Automation by id

        .EXAMPLE
        Get-vRACloudZone -id <cloud_zone_id> -compute
        This example gets a Cloud Zone Compute details from VMware Aria Automation.

        .PARAMETER id
        The Cloud Zone id to get.

        .PARAMETER compute
        Get the compute details for the Cloud Zone.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$compute
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id") -and $PsBoundParameters.ContainsKey("compute")) {
            $uri = "https://$vraAppliance/iaas/api/zones/$id/computes"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response.content
        } elseif ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vraAppliance/iaas/api/zones/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response
        } else {
            $uri = "https://$vraAppliance/iaas/api/zones"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
            $response.content
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRACloudZone

Function Get-vRAAPIVersion {
    <#
        .SYNOPSIS
        Retrieve the VMware Aria Automation version information
        
        .DESCRIPTION
        The Get-vRAAPIVersion cmdlet returns the latest version of the API

        .EXAMPLE
        Get-vRAAPIVersion.
    #>


    Try {
        $uri = "https://$vraAppliance/iaas/api/about"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response.latestApiVersion         
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRAAPIVersion

Function Get-vRAIntegrationDetail {
    <#
        .SYNOPSIS
        Get an integration detail of an item from VMware Aria Automation.

        .DESCRIPTION
        The Get-vRAIntegrationDetail cmdlet returns an integration details of an item from VMware Aria Automation

        .EXAMPLE
        Get-vRAIntegrationDetail -integrationType "vrops" -getVCID
        This example returns the ids of the vCenter Server instances managed by the VMware Aria Operations

        .EXAMPLE
        Get-vRAIntegrationDetail -integrationType "vrops" -integrationName "VMware Aria Operations" -getIntegrationID
        This example returns the integration id of "VMware Aria Operations" which is integrated with the VMwareAria Automation.

        .PARAMETER integrationType
        The integration type to get details for, supports vrops.

        .PARAMETER integrationName
        The integration name to get details for.

        .PARAMETER getVCID
        Get the vCenter Server instance ids managed by the VMware Aria Operations.

        .PARAMETER getIntegrationID
        Get the integration id of the integration name provided.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vrops")] [ValidateNotNullOrEmpty()] [String]$integrationType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$integrationName,
        [switch]$getVCID,
        [switch]$getIntegrationID
    )

    Try {
        $vraapiVersion = "apiVersion=" + (Get-vRAAPIVersion)
        $uri = "https://$vraAppliance/iaas/api/integrations?$vraapiVersion"        
        $response = Invoke-RestMethod -Method Get -Uri $uri -Headers $vraHeaders
        if ($getVCID) {
            ($response.content | Where-Object integrationType -Match $integrationType).customProperties.vcIds
        }
        if ($getIntegrationID) {
            if (($PsBoundParameters.ContainsKey("integrationType")) -and ($PsBoundParameters.ContainsKey("integrationName"))) {
                (($response.content | Where-Object integrationType -Match $integrationType) | Where-Object name -Match "\b$integrationName\b").id        
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRAIntegrationDetail

Function Update-vRACloudZone {
    <#
        .SYNOPSIS
        Update a Cloud Zones.

        .DESCRIPTION
        The Update-vRACloudZone cmdlet updates a Cloud Zones in VMware Aria Automation

        .EXAMPLE
        Update-vRACloudZone -id <cloud_zone_id> -folder sfo-w01-fd-workload
        This example adds a folder to theCloud Zone in VMware Aria Automation by id

        .EXAMPLE
        Update-vRACloudZone -id <cloud_zone_id> -tagKey enabled -tagValue true
        This example adds tags that should be used to dynamically obtain resources for a Cloud Zone in VMware Aria Automation by id

        .EXAMPLE
        Update-vRACloudZone -id <cloud_zone_id> placementPolicy ADVANCED
        This example updates the placement policy for Cloud Zones to ADVANCED in VMware Aria Automation by id.

        .PARAMETER id
        The Cloud Zone id to update.

        .PARAMETER folder
        The folder to add to the Cloud Zone.

        .PARAMETER tagKey
        The tag key to add to the Cloud Zone.

        .PARAMETER tagValue
        The tag value to add to the Cloud Zone.

        .PARAMETER placementPolicy
        The placement policy to update the Cloud Zone to.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (ParameterSetName = "folder", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$folder,
        [Parameter (ParameterSetName = "tag", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tagKey,
        [Parameter (ParameterSetName = "tag", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$tagValue,
        [Parameter (ParameterSetName = "placementPolicy", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$placementPolicy
    )

    Try {
        $cloudZoneDetails = Get-VRACloudZone -id $id
        if ($PsBoundParameters.ContainsKey("id") -and $PsBoundParameters.ContainsKey("folder")) {
            $json = '{ "name": "' + $($cloudZoneDetails.name) + '", "folder": "' + $folder + '" }'
        }
        if ($PsBoundParameters.ContainsKey("id") -and $PsBoundParameters.ContainsKey("tagKey") -and $PsBoundParameters.ContainsKey("tagValue")) {
            $json = '{ "name": "' + $($cloudZoneDetails.name) + '", "tagsToMatch": [ { "key": "' + $tagKey + '", "value": "' + $tagValue + '" } ] }'
        }
        if ($PsBoundParameters.ContainsKey("id") -and $PsBoundParameters.ContainsKey("placementPolicy")) {
            if ($placementPolicy -eq "ADVANCED") {
                if (((Get-vRAIntegrationDetail -integrationType vrops -getVCID).split(',')).contains(((Get-vRACloudAccount -type vsphere).customProperties.vcUuid))) {
                    $cloudZoneDetails.placementPolicy = $placementPolicy
                    $cloudZoneDetails.customProperties | Add-Member -Type NoteProperty  -Name "__ignoreAdvancedPolicyFailure" -Value "true" -Force
                    $json = $cloudZoneDetails | ConvertTo-Json -Depth 4
                } else {
                    Write-Error "VMware Aria Operations is not integrated with VMware Aria Automation for the vCenter Server configured in CloudZone(id :$id) , check the integration: PRE_VALIDATION_FAILED"
                    Break
                }
            } else {   
                $cloudZoneDetails.placementPolicy = $placementPolicy
                $cloudZoneDetails.customProperties.PSObject.Properties.Remove('__ignoreAdvancedPolicyFailure')
                $json = $cloudZoneDetails | ConvertTo-Json -Depth 4
            }
        }
        $uri = "https://$vraAppliance/iaas/api/zones/$id"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $json
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Update-vRACloudZone

Function Remove-vRACloudZone {
    <#
        .SYNOPSIS
        Remove Cloud Zones.

        .DESCRIPTION
        The Remove-vRACloudZone cmdlet deletes a Cloud Zones from VMware Aria Automation

        .EXAMPLE
        Remove-vRACloudZone -id <cloud_zone_id>
        This example deletes a Cloud Zone from VMware Aria Automation by id.

        .PARAMETER id
        The Cloud Zone id to delete.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vraAppliance/iaas/api/zones/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRACloudZone

Function Get-vRAServices {
    <#
        .SYNOPSIS
        Get the services.

        .DESCRIPTION
        The Get-vRAServices cmdlet returns the services information from an organization in VMware Aria Automation.

        .EXAMPLE
        Get-vRAServices
        This example returns the services information from VMware Aria Automation by orgId.

        .PARAMETER orgId
        The organization Id to get the services for.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/slc/api/v2/orgs/$orgId/services"
        $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $vraHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Get-vRAServices

Function Get-vRAUser {
    <#
        .SYNOPSIS
        Get the user in an organization.

        .DESCRIPTION
        The Get-vRAUser cmdlet returns the user information from an organization in VMware Aria Automation.

        .EXAMPLE
        Get-vRAUser -orgId $orgId -email jdoe@rainpole.io
        This example returns the user information for an organization in VMware Aria Automation by orgId and email.

        .PARAMETER orgId
        The organization Id to get the user for.

        .PARAMETER email
        The email address of the user to get.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$email
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/am/api/orgs/$orgId/users/search?userSearchTerm=$email"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Get-vRAUser

Function New-vRAUser {
    <#
        .SYNOPSIS
        Adds a user in an organization.

        .DESCRIPTION
        The New-vRAUser cmdlet adds a user in VMware Aria Automation.

        .EXAMPLE
        New-vRAUser -userId $userId -orgId $serviceRole -serviceDefinitionId $serviceDefinitionId -orgRole $orgRole> -serviceRole $serviceRole>
        This example adds a user to VMware Aria Automation by userId and orgId and assisgnes the required orgRole and serviceRole.

        .PARAMETER userId
        The userId to add.

        .PARAMETER orgId
        The organization Id to add the user to.

        .PARAMETER serviceDefinitionId
        The service definition Id to add the user to.

        .PARAMETER orgRole
        The organization role to assign to the user.

        .PARAMETER serviceRole
        The service role to assign to the user.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceDefinitionId,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner", "org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole,
        [Parameter (Mandatory = $false)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        $body = '{
                    "organizationRoles": {
                        "roleNamesToAdd": [
                        "'
 + $orgRole + '"
                        ],
                        "roleNamesToRemove": []
                    },
                    "serviceRoles": [
                        {
                        "serviceDefinitionId": "'
 + $serviceDefinitionId + '",
                        "roleNamesToAdd": [
                            "'
 + $serviceRole + '"
                        ],
                        "roleNamesToRemove": []
                        }
                    ]
                }'

        $uri = "https://$vraAppliance/csp/gateway/am/api/v3/users/$userId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function New-vRAUser

Function Get-vRAGroup {
    <#
        .SYNOPSIS
        Get the group in an organization.

        .DESCRIPTION
        The Get-vRAGroup cmdlet returns the group information from an organization in VMware Aria Automation.

        .EXAMPLE
        Get-vRAGroup -orgId $orgId -displayName gg-vra-cloud-assemhly-admins@rainpole.io
        This example returns the group information from VMware Aria Automation by orgId and displayName.

        .PARAMETER orgId
        The organization Id to get the group for.

        .PARAMETER displayName
        The displayName of the group to get.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$displayName
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/am/api/orgs/$orgId/groups-search?groupSearchTerm=$displayName"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response.results
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Get-vRAGroup

Function New-vRAGroup {
    <#
        .SYNOPSIS
        Adds a group in an organization.

        .DESCRIPTION
        The New-vRAGroup cmdlet adds a group in VMware Aria Automation.

        .EXAMPLE
        New-vRAGroup -groupId $groupId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -orgRole $orgRole-serviceRole $serviceRole
        This example adds a group in VMware Aria Automation by groupId and orgId and assisgnes both the required orgRole and serviceRole.

        .EXAMPLE
        New-vRAGroup -groupId $orgId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -orgRole $orgRole -serviceRole $serviceRole
        This example adds a group in VMware Aria Automation by groupId and orgId and assisgnes the required orgRole only.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER groupId
        The groupId to add.

        .PARAMETER orgId
        The organization Id to add the group to.

        .PARAMETER serviceDefinitionId
        The service definition Id to add the group to.

        .PARAMETER orgRole
        The organization role to assign to the group.

        .PARAMETER serviceRole
        The service role to assign to the group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner", "org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole,
        [Parameter (ParameterSetName = "serviceRole", Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$serviceDefinitionId,
        [Parameter (ParameterSetName = "serviceRole", Mandatory = $false)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        if ($PsBoundParameters.ContainsKey("serviceRole") -and $PsBoundParameters.ContainsKey("serviceDefinitionId")) {
            $body = '{
                    "ids":[
                        "'
 + $groupId + '"
                        ],
                    "organizationRoleNames":[
                        "'
 + $orgRole + '"
                        ],
                    "serviceRoles":[
                        {
                            "serviceDefinitionId":"'
 + $serviceDefinitionId + '",
                            "serviceRoleNames":[
                                "'
 + $serviceRole + '"
                            ]
                        }
                        ]
                    }'

            $uri = "https://$vraAppliance/csp/gateway/portal/api/orgs/$orgId/groups"
            $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vraHeaders -Body $body
        } elseif ($PsBoundParameters.ContainsKey("serviceRole") -or $PsBoundParameters.ContainsKey("serviceDefinitionId")) {
            Write-Error "Only one of serviceRole and serviceDefinitionId provided."
        } else {
            $body = '{
                    "ids":[
                        "'
 + $groupId + '"
                        ],
                    "organizationRoleNames":[
                        "'
 + $orgRole + '"
                        ]
                    }'

            $uri = "https://$vraAppliance/csp/gateway/portal/api/orgs/$orgId/groups"
            $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vraHeaders -Body $body
        }
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function New-vRAGroup

Function Get-vRAUserRoles {
    <#
        .SYNOPSIS
        Get the user roles.

        .DESCRIPTION
        The Get-vRAUser Roles cmdlet returns a user's roles in VMware Aria Automation.

        .EXAMPLE
        Get-vRAUserRoles -userId $userId -orgId $orgId
        This example returns a user's roles from VMware Aria Automation by userId and orgId.

        .PARAMETER userId
        The userId to get the roles for.

        .PARAMETER orgId
        The organization Id to get the roles for.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/am/api/users/$userid/orgs/$orgId/access"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Get-vRAUserRoles

Function Get-vRAGroupRoles {
    <#
        .SYNOPSIS
        Get the group roles.

        .DESCRIPTION
        The Get-vRAGroupRoles cmdlet returns a group's roles in VMware Aria Automation.

        .EXAMPLE
        Get-vRAGroupRoles -groupId $groupId -orgId $orgId
        This example returns a group's roles from VMware Aria Automation by groupId and orgId.

        .PARAMETER groupId
        The groupId to get the roles for.

        .PARAMETER orgId
        The organization Id to get the roles for.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId
    )

    Try {
        $uri = "https://$vraAppliance/csp/gateway/portal/api/groups/$groupId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vraHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Get-vRAGroupRoles

Function Remove-vRAGroupRoles {
    <#
        .SYNOPSIS
        Remove the group roles.

        .DESCRIPTION
        The Remove-vRAGroupRoles cmdlet removes a group's roles in VMware Aria Automation.

        .EXAMPLE
        Remove-vRAGroupRoles -groupId <group_id> -orgId <org_id>
        This example removes a group's roles from VMware Aria Automation by groupId and orgId.

        .PARAMETER groupId
        The groupId to remove the roles for.

        .PARAMETER orgId
        The organization Id to remove the roles for.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId
    )

    Try {
        $body = '{
                    "ids": [
                        "'
 + $groupId + '"
                    ]
                }'

        $uri = "https://$vraAppliance/csp/gateway/portal/api/orgs/$orgId/groups"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Remove-vRAGroupRoles

Function Set-vRAGroupOrgRole {
    <#
        .SYNOPSIS
        Set the group organization role.

        .DESCRIPTION
        The Set-vRAGroupOrgRole cmdlet sets a group's organization roles in VMware Aria Automation.

        .EXAMPLE
        Set-vRAGroupOrgRole -groupId $groupId -orgId $orgId -orgRole org_owner
        This example sets the group as an organization owner in VMware Aria Automation by groupId and orgId.

        .EXAMPLE
        Set-vRAGroupOrgRole -groupId $groupId -orgId $orgId -orgRole org_member
        This example sets the group as an organization member in VMware Aria Automation by groupId and orgId.

        .PARAMETER groupId
        The groupId to set the organization role for.

        .PARAMETER orgId
        The organization Id to set the organization role for.

        .PARAMETER orgRole
        The organization role to set.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner", "org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole
    )

    Try {
        $body = '{
                    "organizationRoles": {
                        "roleNamesToAdd": [
                            "'
 + $orgRole + '"
                        ],
                        "roleNamesToRemove": []
                    }
                }'

        $uri = "https://$vraAppliance/csp/gateway/portal/api/groups/$groupId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Set-vRAGroupOrgRole

Function Remove-vRAGroupOrgRole {
    <#
        .SYNOPSIS
        Remove the group organization role.

        .DESCRIPTION
        The Remove-vRAGroupOrgRole cmdlet a removes a group's organization role in VMware Aria Automation.

        .EXAMPLE
        Remove-vRAGroupOrgRole -groupId $groupId -orgId $orgId -orgRole org_owner
        This example removes the group as an organization owner in VMware Aria Automation by groupId and orgId.

        .EXAMPLE
        Remove-vRAGroupOrgRole -groupId $groupId -orgId $orgId -orgRole org_member
        This example removes the group as an organization member in VMware Aria Automation by groupId and orgId.

        .PARAMETER groupId
        The groupId to remove the organization role for.

        .PARAMETER orgId
        The organization Id to remove the organization role for.

        .PARAMETER orgRole
        The organization role to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner", "org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole
    )

    Try {
        $body = '{
            "organizationRoles": {
                "roleNamesToAdd": [],
                "roleNamesToRemove": [
                    "'
 + $orgRole + '"
                ]
            }
        }'

        $uri = "https://$vraAppliance/csp/gateway/portal/api/groups/$groupId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRAGroupOrgRole

Function Set-vRAGroupServiceRole {
    <#
        .SYNOPSIS
        Set the group service role.

        .DESCRIPTION
        The Set-vRAGroupServiceRole cmdlet adds a group's service role in VMware Aria Automation.

        .EXAMPLE
        Set-vRAGroupServiceRole -groupId $groupId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -serviceRole $serviceRole
        This example adds the group to a service role in VMware Aria Automation by groupId and orgId.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER serviceRole
        The service role to be added. Valid values are automationservice:cloud_admin, automationservice:user, automationservice:viewer, catalog:admin, catalog:user, catalog:viewer, CodeStream:administrator, CodeStream:developer, CodeStream:executor, CodeStream:user, CodeStream:viewer, migration:admin, migration:viewer, orchestration:admin, orchestration:designer, orchestration:viewer, saltstack:admin.

        .PARAMETER serviceDefinitionId
        The service definition id to be added.

        .PARAMETER orgId
        The organization id to be added.

        .PARAMETER groupId
        The group id to be added.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceDefinitionId,
        [Parameter (Mandatory = $true)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        $body = '{
                    "serviceRoles": [
                        {
                            "serviceDefinitionId": "'
 + $serviceDefinitionId + '",
                            "roleNamesToAdd": [
                                "'
 + $serviceRole + '"
                            ],
                            "roleNamesToRemove": []
                        }
                    ],
                    "organizationRoles": {
                        "roleNamesToAdd": [],
                        "roleNamesToRemove": []
                    }
                }'

        $uri = "https://$vraAppliance/csp/gateway/portal/api/groups/$groupId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Set-vRAGroupServiceRole

Function Remove-vRAGroupServiceRole {
    <#
        .SYNOPSIS
        Remove the group service role.

        .DESCRIPTION
        The Remove-vRAGroupServiceRole cmdlet removes a group's service role in VMware Aria Automation.

        .EXAMPLE
        Remove-vRAGroupServiceRole -groupId $groupId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -serviceRole $serviceRole
        This example removes the group from a service role in VMware Aria Automation by groupId and orgId.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER serviceRole
        The service role to be removed. Valid values are automationservice:cloud_admin, automationservice:user, automationservice:viewer, catalog:admin, catalog:user, catalog:viewer, CodeStream:administrator, CodeStream:developer, CodeStream:executor, CodeStream:user, CodeStream:viewer, migration:admin, migration:viewer, orchestration:admin, orchestration:designer, orchestration:viewer, saltstack:admin.

        .PARAMETER serviceDefinitionId
        The service definition id to be removed.

        .PARAMETER orgId
        The organization id to be removed.

        .PARAMETER groupId
        The group id to be removed.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceDefinitionId,
        [Parameter (Mandatory = $true)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        $body = '{
                    "serviceRoles": [
                        {
                            "serviceDefinitionId": "'
 + $serviceDefinitionId + '",
                            "roleNamesToAdd": [],
                            "roleNamesToRemove": [
                                "'
 + $serviceRole + '"
                            ]
                        }
                    ],
                    "organizationRoles": {
                        "roleNamesToAdd": [],
                        "roleNamesToRemove": []
                    }
                }'

        $uri = "https://$vraAppliance/csp/gateway/portal/api/groups/$groupId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Remove-vRAGroupServiceRole

Function Set-vRAUserOrgRole {
    <#
        .SYNOPSIS
        Set the user organization role.

        .DESCRIPTION
        The Set-vRAUserOrgRole cmdlet sets a user's organization role in VMware Aria Automation.

        .EXAMPLE
        Set-vRAUserOrgRole -userId $userId -orgId $orgId -orgRole org_owner
        This example sets the user as an organization owner in VMware Aria Automation by userId and orgId.

        .EXAMPLE
        Set-vRAUserOrgRole -userId $userId -orgId $orgId -orgRole org_member
        This example sets the user as an organization member in VMware Aria Automation by userId and orgId.

        Note: This cmdlet currently only supports a single orgRole.

        .PARAMETER orgRole
        The organization role to be added. Valid values are org_owner, org_member.

        .PARAMETER orgId
        The organization id to be added.

        .PARAMETER userId
        The user id to be added.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner", "org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole
    )

    Try {
        $body = '{
            "organizationRoles": {
                "roleNamesToAdd": [
                "'
 + $orgRole + '"
                ],
                "roleNamesToRemove": []
            }
        }'

        $uri = "https://$vraAppliance/csp/gateway/am/api/v3/users/$userId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Set-vRAUserOrgRole

Function Remove-vRAUserOrgRole {
    <#
        .SYNOPSIS
        Remove the user organization role.

        .DESCRIPTION
        The Remove-vRAUserOrgRole cmdlet a user's organization role in VMware Aria Automation.

        .EXAMPLE
        Remove-vRAUserOrgRole -userId $userId -orgId $orgId -orgRole org_owner
        This example removes the user as an organization owner in VMware Aria Automation by userId and orgId.

        .EXAMPLE
        Remove-vRAUserOrgRole -userId $userId -orgId $orgId -orgRole org_member
        This example removes the user as an organization member in VMware Aria Automation by userId and orgId.

        .PARAMETER orgRole
        The organization role to be removed. Valid values are org_owner, org_member.

        .PARAMETER orgId
        The organization id to be removed.

        .PARAMETER userId
        The user id to be removed.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateSet("org_owner", "org_member")] [ValidateNotNullOrEmpty()] [String]$orgRole
    )

    Try {
        $body = '{
            "organizationRoles": {
                "roleNamesToAdd": [],
                "roleNamesToRemove": [
                "'
 + $orgRole + '"
                ]
            }
        }'

        $uri = "https://$vraAppliance/csp/gateway/am/api/v3/users/$userId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Remove-vRAUserOrgRole

Function Set-vRAUserServiceRole {
    <#
        .SYNOPSIS
        Set the user service role.

        .DESCRIPTION
        The Set-vRAUserServiceRole cmdlet adds a user's service role in VMware Aria Automation.

        .EXAMPLE
        Set-vRAUserServiceRole -userId $userId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -serviceRole $serviceRole
        This example adds the user to a service role in VMware Aria Automation by userId and orgId.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER serviceRole
        The service role to be added. Valid values are automationservice:cloud_admin, automationservice:user, automationservice:viewer, catalog:admin, catalog:user, catalog:viewer, CodeStream:administrator, CodeStream:developer, CodeStream:executor, CodeStream:user, CodeStream:viewer, migration:admin, migration:viewer, orchestration:admin, orchestration:designer, orchestration:viewer, saltstack:admin.

        .PARAMETER serviceDefinitionId
        The service definition id to be added.

        .PARAMETER orgId
        The organization id to be added.

        .PARAMETER userId
        The user id to be added.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceDefinitionId,
        [Parameter (Mandatory = $true)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        $body = '{
                    "serviceRoles": [
                        {
                        "serviceDefinitionId": "'
 + $serviceDefinitionId + '",
                        "roleNamesToAdd": [
                            "'
 + $serviceRole + '"
                        ],
                        "roleNamesToRemove": []
                        }
                    ]
                }'

        $uri = "https://$vraAppliance/csp/gateway/am/api/v3/users/$userId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Set-vRAUserServiceRole

Function Remove-vRAUserServiceRole {
    <#
        .SYNOPSIS
        Remove the user service role.

        .DESCRIPTION
        The Remove-vRAUserServiceRole cmdlet removes a user's service role in VMware Aria Automation.

        .EXAMPLE
        Remove-vRAUserServiceRole -userId $userId -orgId $orgId -serviceDefinitionId $serviceDefinitionId -serviceRole $serviceRole
        This example removes the user from a service role in VMware Aria Automation by userId and orgId.

        Note: This cmdlet currently only supports a single serviceRole.

        .PARAMETER serviceRole
        The service role to be removed. Valid values are automationservice:cloud_admin, automationservice:user, automationservice:viewer, catalog:admin, catalog:user, catalog:viewer, CodeStream:administrator, CodeStream:developer, CodeStream:executor, CodeStream:user, CodeStream:viewer, migration:admin, migration:viewer, orchestration:admin, orchestration:designer, orchestration:viewer, saltstack:admin.

        .PARAMETER serviceDefinitionId
        The service definition id to be removed.

        .PARAMETER orgId
        The organization id to be removed.

        .PARAMETER userId
        The user id to be removed.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$orgId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceDefinitionId,
        [Parameter (Mandatory = $true)] [ValidateSet('automationservice:cloud_admin', 'automationservice:user', 'automationservice:viewer', 'catalog:admin', 'catalog:user', 'catalog:viewer', 'CodeStream:administrator', 'CodeStream:developer', 'CodeStream:executor', 'CodeStream:user', 'CodeStream:viewer', 'migration:admin', 'migration:viewer', 'orchestration:admin', 'orchestration:designer', 'orchestration:viewer', 'saltstack:admin')] [ValidateNotNullOrEmpty()] [String]$serviceRole
    )

    Try {
        $body = '{
                    "serviceRoles": [
                        {
                        "serviceDefinitionId": "'
 + $serviceDefinitionId + '",
                        "roleNamesToAdd": [],
                        "roleNamesToRemove": [
                            "'
 + $serviceRole + '"
                        ]
                        }
                    ]
                }'

        $uri = "https://$vraAppliance/csp/gateway/am/api/v3/users/$userId/orgs/$orgId/roles"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vraHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Remove-vRAUserServiceRole

Function Add-vRAIntegrationItem {
    <#
        .SYNOPSIS
        Add external systems to VMware Aria Automation.

        .DESCRIPTION
        The Add-vRAIntegrationItem cmdlet adds external systems to VMware Aria Automation

        .EXAMPLE
        Add-vRAIntegrationItem -integrationType "vrops" -integrationName "VMware Aria Operations" -integrationUser "svc-vra-vrops@sfo.rainpole.io@vIDMAuthSource" -integrationPassword "VMw@re1!"
        This example creates VMware Aria Operations integration with name "VMware Aria Operations".

        .PARAMETER integrationType
        The type of integration to be added. Valid values are vrops.

        .PARAMETER integrationName
        The name of the integration to be added.

        .PARAMETER integrationUser
        The username of the integration to be added.

        .PARAMETER integrationPassword
        The password of the integration to be added.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vrops")] [ValidateNotNullOrEmpty()] [String]$integrationType,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$integrationName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$integrationUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$integrationPassword
    )
    
    Try {
        $json = Test-vRAIntegrationItem -integrationType $integrationType -integrationName $integrationName -integrationUser $integrationUser -integrationPassword $integrationPassword 
        $vraapiVersion = "apiVersion=" + (Get-vRAAPIVersion)
        $uri = "https://$vraAppliance/iaas/api/integrations?$vraapiVersion"
        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vraHeaders -Body $json
        Start-Sleep 5
        $id = $response.selfLink
        $uri = "https://$vraAppliance$id"
        (Invoke-RestMethod -Method Get -Uri $uri -Headers $vraHeaders)
    } Catch {
        Write-Error $_.Exception.Message
    }

}
Export-ModuleMember -Function Add-vRAIntegrationItem

Function Test-vRAIntegrationItem {
    <#
        .SYNOPSIS
        Test an Integration Item in VMware Aria Automation.

        .DESCRIPTION
        The Test-vRAIntegrationItem cmdlet validates the given credential and certificate of an intergarion item

        .EXAMPLE
        Test-vRAIntegrationItem -integrationType "vrops" -integrationName "VMware Aria Operations" -integrationUser "svc-vra-vrops@sfo.rainpole.io@vIDMAuthSource" -integrationPassword "VMw@re1!"
        This example validates VMware Aria Operations integration in VMware Aria Automation.

        .PARAMETER integrationType
        The type of integration to be tested. Valid values are vrops.

        .PARAMETER integrationName
        The name of the integration to be tested.

        .PARAMETER integrationUser
        The username of the integration to be tested.

        .PARAMETER integrationPassword
        The password of the integration to be tested.
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vrops")] [ValidateNotNullOrEmpty()] [String]$integrationType,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$integrationName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$integrationUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$integrationPassword
    )

    if ($PsBoundParameters.ContainsKey("integrationType")) {
        if ($integrationType -eq "vrops") { $vropsuri = "https://$vropsAppliance/suite-api" } 
        $jsonObj = [PSCustomObject]@{
            integrationType       = $integrationType
            name                  = $integrationName
            privateKeyId          = $integrationUser
            privateKey            = $integrationPassword
            integrationProperties = @{hostName = $vropsuri }
        }
        $json = $jsonObj | ConvertTo-Json -Depth 2
        Try { 
            $vraapiVersion = "apiVersion=" + (Get-vRAAPIVersion)
            $uri = "https://$vraAppliance/iaas/api/integrations?validateOnly&$vraapiVersion"        
            $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vraHeaders -Body $json
            Start-Sleep 5
            $id = $response.selfLink
            $uri = "https://$vraAppliance$id"   
            $response = Invoke-RestMethod -Method Get -Uri $uri -Headers $vraHeaders
            if (($response.status -eq "FAILED") -and ($response.message -eq "unable to find valid certification")) {        
                $certid = $response.resources 
                $uri = "https://$vraAppliance$certid" + "?$vraapiVersion" 
                $response = Invoke-RestMethod -Method Get -Uri $uri -Headers $vraHeaders
                $certificatevalue = $response.certificate 
                Write-Host (($response.certificateErrorDetail) + ($response.properties | Out-String ))
                $certinput = Read-Host "Do you want to accept the above certificate (yes/no)"
                if (($certinput -eq "yes") -or ($certinput -eq "y")) {
                    $jsonObj.integrationProperties += @{certificate = $certificatevalue }
                    $json = $jsonObj | ConvertTo-Json -Depth 2 
                    return  $json    
                } else {
                    Write-Output "Exiting..." 
                    Break 
                }               
            } elseif ($response.status -eq "FINISHED") { 
                Write-Host "Certificate is already present in the system..."  
                $json = $jsonObj | ConvertTo-Json -Depth 2 
                return  $json     
            } else {
                Write-Error "Error "$response.message
                Break        
            }
        } Catch {
            Write-Error $_.Exception.Message
            Break  
        }
    }
}
Export-ModuleMember -Function Test-vRAIntegrationItem

Function Remove-vRAIntegrationItem {
    <#
        .SYNOPSIS
        Remove an Integration Item from VMware Aria Automation.

        .DESCRIPTION
        The Remove-vRAIntegrationItem cmdlet removes the given Integration Item from VMware Aria Automation

        .EXAMPLE
        Remove-vRAIntegrationItem -integrationType vrops -integrationId "instacenID"
        This example removes VMware Aria Operations integration from VMware Aria Automation.

        .PARAMETER integrationType
        The type of integration to be removed. Valid values are vrops.

        .PARAMETER integrationId
        The ID of the integration to be removed.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vrops")] [ValidateNotNullOrEmpty()] [String]$integrationType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$integrationId
    )

    Try {
        $vraapiVersion = "apiVersion=" + (Get-vRAAPIVersion)
        $uri = "https://$vraAppliance/iaas/api/integrations/$integrationId" + "?$vraapiVersion"     
        $response = Invoke-RestMethod -Method Delete -Uri $uri -Headers $vraHeaders
        Start-Sleep 5
        $id = $response.selfLink
        $uri = "https://$vraAppliance$id"
        $response = Invoke-RestMethod -Method Get -Uri $uri -Headers $vraHeaders
        if ( $response.status -eq "FAILED") {
            Write-Host "Error "$response.message
            Break        
        }
        if ( $response.status -eq "FINISHED") {
            $response.message
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRAIntegrationItem

#EndRegion End VMware Aria Automation Functions ######
###################################################################################

###################################################################################
#Region Start VMware Aria Automation Orchestrator (Embedded) Functions ######

Function Invoke-vRORestMethod {
    <#
        .SYNOPSIS
        A wrapper for Invoke-RestMethod for use with VMware Aria Automation Orchestrator.

        .DESCRIPTION
        The Invoke-RestMethod cmdlet is a wrapper for Invoke-RestMethod use with VMware Aria Automation Orchestrator
        
        .EXAMPLE
        Invoke-vRORestMethod -Method 'GET' -Uri '/vco/api/workflows'
        
        .EXAMPLE

        $method = "POST"
        $uri = "/vco/api/workflows/$($ID)/executions/"
        $body = @"
        {"parameters":
            [
                {
                    "value": {"string":{ "value": "bar"}},
                    "type": "string",
                    "name": "foo",
                    "scope": "local"
                },
                {
                    "value": {"number":{ "value": 2022}},
                    "type": "number",
                    "name": "bar",
                    "scope": "local"
                }
            ]
        }
        "@
        Invoke-vRORestMethod -method $method -uri $uri -body $body -webRequest

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER method
        The HTTP method to use. Valid values are GET, POST, PUT, and DELETE.

        .PARAMETER uri
        The URI to send the request to.

        .PARAMETER body
        The body of the request.

        .PARAMETER outFile
        The file to write the response to.

        .PARAMETER webRequest
        Use Invoke-WebRequest instead of Invoke-RestMethod.
    #>


    [CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("GET", "POST", "PUT", "DELETE")] [String]$method,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$uri,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] $body,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$outFile,
        [Parameter (Mandatory = $false)] [Switch]$webRequest
    )

    $fullUri = "https://$vraAppliance$uri"

    $Params = @{
        method  = $method
        headers = $vraHeaders
        uri     = $fullUri
    }

    if ($PSBoundParameters.ContainsKey("body")) {
        $Params.Add("body", $body)
        Write-Debug -message $body
    } elseif ($PSBoundParameters.ContainsKey("outFile")) {
        $Params.Add("outFile", $outFile)
    }

    Try {
        if ($PSEdition -eq 'Core') {
            if ($PSBoundParameters.ContainsKey("webRequest")) {
                Invoke-WebRequest @Params -SkipCertificateCheck -UseBasicParsing
            } else {
                Invoke-RestMethod @Params -SkipCertificateCheck -UseBasicParsing
            }
        } else {
            if ($PSBoundParameters.ContainsKey("webRequest")) {
                Invoke-WebRequest @Params -UseBasicParsing
            } else {
                Invoke-RestMethod @Params -UseBasicParsing
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Invoke-vRORestMethod

function Get-vROVersion {
    <#
        .SYNOPSIS
        Retrieve the VMware Aria Automation Orchestrator version information
        
        .DESCRIPTION
        The Get-vROVersion cmdlest retrieves the VMware Aria Automation Orchestrator version information

        .EXAMPLE
        Get-vROVersion

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).
    #>


    [CmdletBinding()][OutputType('System.Management.Automation.PSObject')]
    
    Param (

    )

    Try {
        $uri = "/vco/api/about"
        $response = Invoke-vRORestMethod -method 'GET' -uri $uri
        $version = $response.version
        [pscustomobject] @{
            Version     = $version
            BuildNumber = $response."build-number"
            BuildDate   = $response."build-date"
            APIVersion  = $response."api-version"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROVersion

Function Get-vROWorkflow {
    <#
        .SYNOPSIS
        Get VMware Aria Automation Orchestrator workflows.

        .DESCRIPTION
        The Get-vROWorkflow cmdlet returns details for VMware Aria Automation Orchestrator workflows

        .EXAMPLE
        Get-vROWorkflow

        .EXAMPLE
        Get-vROWorkflow -categoryName foo

        .EXAMPLE
        Get-vROWorkflow -categoryId 3f23f186158a4869b464b7271fc216ba

        .EXAMPLE
        Get-vROWorkflow -id '3f23f186-158a-4869-b464-b7271fc216ba'

        .EXAMPLE
        Get-vROWorkflow -name 'foo'

        .EXAMPLE
        Get-vROWorkflow -name 'Add' -wildcard

        .EXAMPLE
        Get-vROWorkflow -tag 'foo'

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER categoryName
        The name of the category to filter by.

        .PARAMETER categoryId
        The ID of the category to filter by.

        .PARAMETER id
        The ID of the workflow to retrieve.

        .PARAMETER name
        The name of the workflow to retrieve.

        .PARAMETER wildcard
        Use wildcard matching for the name parameter.

        .PARAMETER tag
        The tag to filter by.
    #>


    [CmdletBinding(DefaultParametersetName = "All")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $false, ParameterSetName = "categoryName")] [Alias("Category")] [String]$categoryName,
        [Parameter (Mandatory = $false, ParameterSetName = "categoryId")] [String]$categoryId,
        [Parameter (Mandatory = $false, ParameterSetName = "id")] [String]$id,
        [Parameter (Mandatory = $false, ParameterSetName = "name")] [String]$name,
        [Parameter (Mandatory = $false, ParameterSetName = "name")] [Switch]$wildcard,
        [Parameter (Mandatory = $false, ParameterSetName = "all")]
        [Parameter (Mandatory = $false, ParameterSetName = "categoryName")]
        [Parameter (Mandatory = $false, ParameterSetName = "category")] [String[]]$tag
    )

    Try {
        Switch ($PsCmdlet.ParameterSetName) {
            "all" {
                $uri = "/vco/api/workflows"
                break
            }
            "categoryName" {
                $uri = "/vco/api/workflows/?conditions=categoryName=$($categoryName)"
                break
            }
            "categoryId" {
                $uri = "/vco/api/catalog/System/WorkflowCategory/$($categoryId)/workflows"
                break
            }
            "id" {
                $uri = "/vco/api/workflows/$($id)"
                break
            }
            "name" {
                if ($PSBoundParameters.ContainsKey('wildcard')) {
                    $uri = "/vco/api/workflows/?conditions=name~$($name)"
                } else {
                    $uri = "/vco/api/workflows/?conditions=name=$($name)"
                }
                break
            }
        }
        # Filter by tag, if needed
        if ($PSBoundParameters.ContainsKey('tag')) {
            $uri += if ($PSCmdlet.ParameterSetName -eq 'all') { '?' } else { '&' }
            $newParams = @()
            foreach ($tagAttr in $tag) {
                $newParams += "tags=$($tagAttr)"
            }
            $uri += $newParams -join '&'
        }
        Switch ($PsCmdlet.ParameterSetName) {
            "id" {
                $workflow = Invoke-vRORestMethod -method 'GET' -uri $uri -Verbose:$VerbosePreference
                [pscustomobject]@{
                    Name         = $workflow.name
                    ID           = $workflow.id
                    Description  = $workflow.description
                    ItemHref     = $workflow.href
                    Version      = $workflow.version
                    CategoryName = $null
                    CategoryHref = $null
                    CustomIcon   = $workflow.'customized-icon'
                    CanExecute   = $null
                    CanEdit      = $null
                }
            }
            "categoryId" {
                $workflows = Invoke-vRORestMethod -method 'GET' -uri $uri -Verbose:$VerbosePreference
                foreach ($workflow in $workflows.link) {
                    $returnObject = @{
                        Name         = ($workflow.attributes | Where-Object { $_.name -eq 'name' }).value
                        ID           = ($workflow.attributes | Where-Object { $_.name -eq 'id' }).value
                        Description  = ($workflow.attributes | Where-Object { $_.name -eq 'description' }).value
                        ItemHref     = $workflow.href
                        Version      = ($workflow.attributes | Where-Object { $_.name -eq 'version' }).value
                        CategoryName = ($workflow.attributes | Where-Object { $_.name -eq 'categoryName' }).value
                        CategoryHref = ($workflow.attributes | Where-Object { $_.name -eq 'categoryHref' }).value
                        CustomIcon   = ($workflow.attributes | Where-Object { $_.name -eq 'customIcon' }).value
                        CanExecute   = ($workflow.attributes | Where-Object { $_.name -eq 'canExecute' }).value
                        CanEdit      = ($workflow.attributes | Where-Object { $_.name -eq 'canEdit' }).value
                    }
                    # Add tags if needed
                    $tags = $workflow.attributes | Where-Object { $_.name -eq 'globalTags' } | Select-Object -ExpandProperty 'value'
                    if ($tags) {
                        $tagsArray = ($tags -replace ':__SYSTEM_TAG__|.$', '').Split(' ')
                        $returnObject.Add('tags', $tagsArray)
                    }
                    [PSCustomObject]$returnObject
                }
            }
            Default {
                $workflows = Invoke-vRORestMethod -method 'GET' -uri $uri -verbose:$VerbosePreference
                Foreach ($workflow in $workflows.link) {
                    $returnObject = @{
                        Name         = ($workflow.attributes | Where-Object { $_.name -eq 'name' }).value
                        ID           = ($workflow.attributes | Where-Object { $_.name -eq 'id' }).value
                        Description  = ($workflow.attributes | Where-Object { $_.name -eq 'description' }).value
                        ItemHref     = ($workflow.attributes | Where-Object { $_.name -eq 'itemHref' }).value
                        Version      = ($workflow.attributes | Where-Object { $_.name -eq 'version' }).value
                        CategoryName = ($workflow.attributes | Where-Object { $_.name -eq 'categoryName' }).value
                        CategoryHref = ($workflow.attributes | Where-Object { $_.name -eq 'categoryHref' }).value
                        CustomIcon   = ($workflow.attributes | Where-Object { $_.name -eq 'customIcon' }).value
                        CanExecute   = ($workflow.attributes | Where-Object { $_.name -eq 'canExecute' }).value
                        CanEdit      = ($workflow.attributes | Where-Object { $_.name -eq 'canEdit' }).value
                    }
                    # Add tags, if needed
                    $tags = $workflow.attributes | Where-Object { $_.name -eq 'globalTags' } | Select-Object -ExpandProperty 'value'
                    if ($tags) {
                        $tagsArray = ($tags -replace ':__SYSTEM_TAG__|.$', '').Split(' ')
                        $returnObject.Add('tags', $tagsArray)
                    }
                    [PSCustomObject]$returnObject
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROWorkflow

Function Invoke-vROWorkflow {
    <#
        .SYNOPSIS
        Invoke a VMware Aria Automation Orchestrator workflow.

        .DESCRIPTION
        The Invoke-vROWorkflow cmdlet starts a VMware Aria Automation Orchestrator workflow

        .EXAMPLE
        Invoke-vROWorkflow -ID 3f23f186-158a-4869-b464-b7271fc216ba

        .EXAMPLE
        Invoke-vROWorkflow -ID 3f23f186-158a-4869-b464-b7271fc216ba -parameterName 'text' -parameterValue 'foo' -parameterType 'string'

        .EXAMPLE
        $Parameters = @"
        {"parameters":
            [
                {
                    "value": {"string":{ "value": "bar"}},
                    "type": "string",
                    "name": "foo",
                    "scope": "local"
                },
                {
                    "value": {"number":{ "value": 2022}},
                    "type": "number",
                    "name": "year",
                    "scope": "local"
                }
            ]
        }
        "@

        Invoke-vROWorkflow -id 3f23f186-158a-4869-b464-b7271fc216ba -parameters ($parameters | ConvertFrom-Json).parameters

        .EXAMPLE
        $param1 = New-vROParameterDefinition -name 'foo' -value 'bar' -type string -scope LOCAL
        Invoke-vROWorkflow -id 3f23f186-158a-4869-b464-b7271fc216ba -parameters $param1

        .EXAMPLE
        Get-vROWorkflow -name 'foo' | Invoke-vROWorkflow -parameterName 'foo' -parameterValue 'bar' -parameterType string

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER ID
        The ID of the workflow to invoke.

        .PARAMETER parameterName
        The name of the parameter.

        .PARAMETER parameterValue
        The value of the parameter.

        .PARAMETER parameterType
        The type of the parameter.

        .PARAMETER parameters
        An array of parameters to pass to the workflow.
    #>


    [CmdletBinding(DefaultParametersetName = "A")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = "A")]
        [Parameter (Mandatory = $true, ParameterSetName = "B")] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false, ParameterSetName = "A")] [Parameter (ParameterSetName = "C")] [ValidateNotNullOrEmpty()] [String]$parameterName,
        [Parameter (Mandatory = $false, ParameterSetName = "A")] [Parameter (ParameterSetName = "C")] [String]$parameterValue,
        [Parameter (Mandatory = $false, ParameterSetName = "A")] [Parameter (ParameterSetName = "C")] [ValidateNotNullOrEmpty()] [String]$parameterType,
        [Parameter (Mandatory = $false, ParameterSetName = "B")] [Parameter (ParameterSetName = "D")] [ValidateNotNullOrEmpty()] [PSCustomObject[]]$parameters
    )

    Begin {}
    Process {
        Try {
            if ($PSBoundParameters.ContainsKey('parameterType')) {
                $parameterType = $parameterType.ToLower()
                $body = @"
{"parameters":
    [
        {
            "value": {"$($parameterType)":{ "value": "$($parameterValue)"}},
            "type": "$($parameterType)",
            "name": "$($parameterName)",
            "scope": "local"
        }
    ]
}
"@

            }
            elseif ($PSBoundParameters.ContainsKey('parameters')) {
                $object = [PSCustomObject]@{
                    parameters = @()
                }
                foreach ($parameter in $parameters) {
                    $object.parameters += $parameter
                }
                $body = $object | ConvertTo-Json -Depth 100
            } else {
                $body = @"
{"parameters":
[
]
}
"@

            }
            $uri = "/vco/api/workflows/$($id)/executions/"
            $response = Invoke-vRORestMethod -method 'POST' -uri $uri -body $body -webRequest -verbose:$VerbosePreference

            if ($PSEdition -eq 'Core') {
                [pscustomobject]@{
                    StatusCode        = $response.StatusCode
                    StatusDescription = $response.StatusDescription
                    Execution         = ([System.Uri]$response.Headers.Location[0]).LocalPath
                }
            } else {
                [pscustomobject]@{
                    StatusCode        = $response.StatusCode
                    StatusDescription = $response.StatusDescription
                    Execution         = ([System.Uri]$response.Headers.Location).LocalPath
                }
            }
        } Catch {
            Write-Error $_.Exception.Message
        }
    }
}
Export-ModuleMember -Function Invoke-vROWorkflow

Function New-vROParameterDefinition {
    <#
        .SYNOPSIS
        Create a parameter definition for use with a VMware Aria Automation Orchestrator workflow
        
        .DESCRIPTION
        The New-vROParameterDefinition cmdlet create a parameter definition for use with a VMware Aria Automation Orchestrator workflow

        .EXAMPLE
        $param1 = New-vROParameterDefinition -name 'foo' -value 'bar' -type string -scope LOCAL

        Invoke-vROWorkflow -id 697c8755-15c0-44fc-b409-5c562cf2984e -parameters $param1

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER name
        The name of the parameter.

        .PARAMETER value
        The value of the parameter.

        .PARAMETER type
        The type of the parameter.

        .PARAMETER scope
        The scope of the parameter.
    #>


    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$value,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$type,   
        [Parameter (Mandatory = $false)] [ValidateSet("LOCAL", "TOKEN")] [String]$scope = "LOCAL"
    )  

    Begin {} 
    Process {
        Try {
            if ($PSCmdlet.ShouldProcess("WorkflowParameterDefinition")) {
                $parameterDefinition = @"
{
    "name": "$($name)",
    "type": "$($type.ToLower())",
    "scope": "$($scope.ToLower())",
    "value": {
        "$($type.ToLower())":{ "value": "$($value)"}
    }
}
"@

                $parameterDefinition | ConvertFrom-Json
            }
        } Catch {
            Write-Error $_.Exception.Message
        }
    }
    End {    
    }
}
Export-ModuleMember -Function New-vROParameterDefinition

Function Get-vROWorkflowExecution {
    <#
        .SYNOPSIS
        Get VMware Aria Automation Orchestrator workflow executions.

        .DESCRIPTION
        The Get-vROWorkflowExecution cmdlet returns the execution runs for a VMware Aria Automation Orchestrator workflow

        .EXAMPLE
        Get-vROWorkflowExecution -id 697c8755-15c0-44fc-b409-5c562cf2984e

        .EXAMPLE
        Get-vROWorkflowExecution -name 'foo'

        .EXAMPLE
        Get-vROWorkflow -name 'foo' | Get-vROWorkflowExecution

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER id
        The ID of the workflow.

        .PARAMETER name
        The name of the workflow.
    #>


    [CmdletBinding(DefaultParametersetName = "Name")][OutputType('System.Management.Automation.PSObject')]

    Param (   
        [Parameter (Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = "id")] [String]$id,
        [Parameter (Mandatory = $true, ParameterSetName = "name")] [String]$name
    )    

    Begin {}
    Process {
        Try {
            if ($PSCmdlet.ParameterSetName -eq "name") {
                $id = (Get-vROWorkflow -name $name).id
            }
            $uri = "/vco/api/workflows/$($id)/executions"
            $response = Invoke-vRORestMethod -method 'GET' -uri $uri -verbose:$VerbosePreference
            $data = $response.relations.link | Where-Object { $_.attributes }
            Foreach ($execution in $data) {
                [PSCustomObject]@{                                
                    Name      = ($execution.attributes | Where-Object { $_.name -eq 'name' }).value
                    ID        = ($execution.attributes | Where-Object { $_.name -eq 'id' }).value
                    Execution = "$uri/$(($execution.attributes | Where-Object {$_.name -eq 'id'}).value)/"
                    State     = ($execution.attributes | Where-Object { $_.name -eq 'state' }).value
                    StartedBy = ($execution.attributes | Where-Object { $_.name -eq 'startedBy' }).value
                    StartDate = ($execution.attributes | Where-Object { $_.name -eq 'StartDate' }).value
                    EndDate   = ($execution.attributes | Where-Object { $_.name -eq 'EndDate' }).value
                }
            }
        } Catch {
            Write-Error $_.Exception.Message
        }
    }
    End {
    }
}
Export-ModuleMember -Function Get-vROWorkflowExecution

Function Get-vROWorkflowExecutionState {
    <#
        .SYNOPSIS
        Get VMware Aria Automation Orchestrator workflow execution state.

        .DESCRIPTION
        The Get-vROWorkflowExecutionState cmdlet returns the status of VMware Aria Automation Orchestrator workflow execution runs

        .EXAMPLE
        Get-vROWorkflowExecutionState -executionStateRef '/vco/api/workflows/697c8755-15c0-44fc-b409-5c562cf2984e/executions/cda43353730b4f8ba1815979ef8a932a'

        .EXAMPLE
        Get-vROWorkflowExecution -id 697c8755-15c0-44fc-b409-5c562cf2984e | Select-Object -last 1 | Get-vROWorkflowExecutionState

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER executionStateRef
        The execution state reference of the workflow execution.
    #>


    [CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

    Param (   
        [Parameter (Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelinebyPropertyName = $true)] [Alias("execution")] [ValidateNotNullOrEmpty()][String]$executionStateRef
    )

    Begin {}
    Process {
        Try {
            Foreach ($reference in $executionStateRef) {        
                $uri = $reference + "state"
                $response = Invoke-vRORestMethod -method 'GET' -uri $uri -webRequest -verbose:$VerbosePreference
                [pscustomobject]@{                                             
                    ExecutionStateRef = $reference         
                    StatusCode        = $response.StatusCode
                    StatusDescription = $response.StatusDescription
                    Execution         = ($response.Content | ConvertFrom-Json).Value
                }
            }
        } Catch {
            Write-Error $_.Exception.Message
        }
    }
    End {
    }
}
Export-ModuleMember -Function Get-vROWorkflowExecutionState

Function Get-vROWorkflowExecutionResult {
    <#
        .SYNOPSIS
        Get VMware Aria Automation Orchestrator workflow execution result.

        .DESCRIPTION
        The Get-vROWorkflowExecutionResult cmdlet returns the results of VMware Aria Automation Orchestrator workflow execution runs

        .EXAMPLE
        Get-vROWorkflowExecutionResult -executionRef '/vco/api/workflows/697c8755-15c0-44fc-b409-5c562cf2984e/executions/cda43353730b4f8ba1815979ef8a932a'

        .EXAMPLE
        Get-vROWorkflow -name 'foo' | Get-vROWorkflowExecution | Select-Object -last 1 | Get-vROWorkflowExecutionResult

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER executionRef
        The execution reference of the workflow execution.
    #>


    [CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelinebyPropertyName = $true)] [Alias("execution")] [ValidateNotNullOrEmpty()] [String]$executionRef 
    )

    Begin {}
    Process {  
        Try {
            Foreach ($reference in $executionRef) {   
                $response = Invoke-vRORestMethod -method 'GET' -uri $reference -webRequest -verbose:$VerbosePreference
                $json = $response.Content | ConvertFrom-Json
                Foreach ($outputParameter in $json.'output-parameters') {
                    $type = $outputParameter.type
                    [pscustomobject]@{                                 
                        ExecutionRef = $reference      
                        Name         = $outputParameter.name
                        Scope        = $outputParameter.scope
                        Type         = $outputParameter.type
                        Value        = $outputParameter.value.$type.value
                    }
                } 
            }
        } Catch {
            Write-Error $_.Exception.Message
        }
    }
    End {
    }
}
Export-ModuleMember -Function Get-vROWorkflowExecutionResult

#EndRegion End VMware Aria Automation Orchestrator (Embedded) Functions ######
###################################################################################

###################################################################################
#Region Start VMware Aria Operations Functions ######

Function Request-vROPSToken {
    <#
        .SYNOPSIS
        Connects to the specified VMware Aria Operations and obtains authorization token.

        .DESCRIPTION
        The Request-vROPSToken cmdlet connects to the specified VMware Aria Operations and obtains an authorization token.
        It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-vROPSToken -fqdn xint-vrops01.rainpole.io -username admin -password VMw@re1!
        This example shows how to connect to the VMware Aria Operations appliance.

        .PARAMETER fqdn
        The fully qualified domain name of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to use for authentication.

        .PARAMETER password
        The password to use for authentication.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    Try {
        $Global:vropsAppliance = $fqdn
        $Global:vropsHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vropsHeaders.Add("Accept", "application/json")
        $vropsHeaders.Add("Content-Type", "application/json")
        $uri = "https://$vropsAppliance/suite-api/api/auth/token/acquire"
        $body = "{
        `n `"username`" : `"$username`",
        `n `"authSource`" : `"LOCAL`",
        `n `"password`" : `"$password`"
        `n}"

        if ($PSEdition -eq 'Core') {
            $vropsResponse = Invoke-RestMethod -Uri $uri -Method 'POST' -Headers $vropsHeaders -Body $body -SkipCertificateCheck # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vropsResponse = Invoke-RestMethod -Uri $uri -Method 'POST' -Headers $vropsHeaders -Body $body
        }
        if ($vropsResponse.token) {
            $vropsHeaders.Add("Authorization", "vRealizeOpsToken " + $vropsResponse.token)
            Write-Output "Successfully connected to VMware Aria Operations: $vropsAppliance"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-vROPSToken

Function Get-vROPSVersion {
    <#
        .SYNOPSIS
        Get version informartion.

        .DESCRIPTION
        The Get-vROPSVersion cmdlet gets version information for VMware Aria Operations

        .EXAMPLE
        Get-vROPSVersion
        This example gets the current version of the service

        .EXAMPLE
        Get-vROPSVersion -all
        This example gets a list of all versions supported by the service.

        .PARAMETER all
        Get all versions supported by the service.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$all
    )

    Try {
        if ($PsBoundParameters.ContainsKey("all")) {
            $uri = "https://$vropsAppliance/suite-api/api/versions"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.values
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/versions/current"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSVersion

Function Get-vROPSCollector {
    <#
        .SYNOPSIS
        Get list of collectors.

        .DESCRIPTION
        The Get-vROPSCollector cmdlet gets a list of collectors in VMware Aria Operations

        .EXAMPLE
        Get-vROPSCollector
        This example gets a list of collectors

        .EXAMPLE
        Get-vROPSCollector -id <id>
        This example gets details of a collector by its ID.

        .PARAMETER id
        The ID of the collector to get details for.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/collectors/$id/adapters"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.adapterInstancesInfoDto
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/collectors"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.collector
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSCollector

Function Get-vROPSCollectorGroup {
    <#
        .SYNOPSIS
        Get list of collector groups.

        .DESCRIPTION
        The Get-vROPSCollectorGroup cmdlet gets a list of collector groups in VMware Aria Operations

        .EXAMPLE
        Get-vROPSCollectorGroup
        This example gets a list of collector groups

        .EXAMPLE
        Get-vROPSCollectorGroup -id <id>
        This example gets details of a collector by its ID.

        .PARAMETER id
        The ID of the collector group to get details for.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/collectorgroups/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/collectorgroups"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.collectorGroups
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSCollectorGroup

Function Add-vROPSCollectorGroup {
    <#
        .SYNOPSIS
        Add a collector group.

        .DESCRIPTION
        The Add-vROPSCollectorGroup cmdlet adds a collector group in VMware Aria Operations

        .EXAMPLE
        Add-vROPSCollectorGroup -name sfo-remote-collectors -description "Collector Group for SFO" -collectorIds "1,2"
        This example gets a list of collector groups.

        .PARAMETER name
        The name of the collector group.

        .PARAMETER description
        The description of the collector group.

        .PARAMETER collectorIds
        The IDs of the collectors to add to the group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$description,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$collectorIds
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/collectorgroups"
        if ($description) {
            $body = '{ "name" : "'+ $name +'", "description" : "'+ $description +'", "collectorId" : ['+ $collectorIds +'], "systemDefined" : false }'
        } else {
            $body = '{ "name" : "'+ $name +'", "collectorId" : ['+ $collectorIds +'], "systemDefined" : false }'
        }
        $response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vropsHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vROPSCollectorGroup

Function Remove-vROPSCollectorGroup {
    <#
        .SYNOPSIS
        Delete a collector group.

        .DESCRIPTION
        The Remove-vROPSCollectorGroup cmdlet deletes a collector group in VMware Aria Operations

        .EXAMPLE
        Remove-vROPSCollectorGroup -id
        This example deletes a gollector group.

        .PARAMETER id
        The ID of the collector group to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/collectorgroups/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $Uri -Headers $vropsHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSCollectorGroup

Function Get-vROPSAdapter {
    <#
        .SYNOPSIS
        Get list of adapters.

        .DESCRIPTION
        The Get-vROPSAdapter cmdlet gets a list of adapters in VMware Aria Operations

        .EXAMPLE
        Get-vROPSAdapter
        This example gets a list of all adapters

        .EXAMPLE
        Get-vROPSAdapter -id <id>
        This example gets details of an adapter by its ID.

        .PARAMETER id
        The ID of the adapter to get details for.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/adapters/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/adapters"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.adapterInstancesInfoDto
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSAdapter

Function Set-vROPSAdapter {
    <#
        .SYNOPSIS
        Update an adapter.

        .DESCRIPTION
        The Set-vROPSAdapter cmdlet updates the adapters configuration in VMware Aria Operations

        .EXAMPLE
        Set-vROPSAdapter -json .\adapterJson
        This example updates the details of an adapter.

        .PARAMETER json
        The JSON file to use for the update.

        .PARAMETER patch
        Patch the adapter based on the response from the test.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$patch
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }
        if ($PsBoundParameters.ContainsKey("patch")) {
            $uri = "https://$vropsAppliance/suite-api/api/adapters"
            Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vropsHeaders -Body $body
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/adapters"
            $response = Invoke-RestMethod -Method 'PUT' -Uri $uri -Headers $vropsHeaders -Body $body
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vROPSAdapter

Function Add-vROPSAdapter {
    <#
        .SYNOPSIS
        Add an adapter.

        .DESCRIPTION
        The Add-vROPSAdapter cmdlet adds an adapter to VMware Aria Operations

        .EXAMPLE
        Add-vROPSAdapter -json .\addAdapter.json
        This example adds an adapter useing the json specification file.

        .PARAMETER json
        The JSON file to use for the add.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }
        $uri = "https://$vropsAppliance/suite-api/api/adapters"
        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vROPSAdapter

Function Remove-vROPSAdapter {
    <#
        .SYNOPSIS
        Delete an adapters.

        .DESCRIPTION
        The Remove-vROPSAdapter cmdlet deletes an adapters from VMware Aria Operations

        .EXAMPLE
        Remove-vROPSAdapter -id <id>
        This example deletes the adapter based on its ID.

        .PARAMETER id
        The ID of the adapter to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/adapters/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSAdapter

Function Test-vROPSAdapterConnection {
    <#
        .SYNOPSIS
        Test adapter connection.

        .DESCRIPTION
        The Test-vROPSAdapterConnection cmdlet tests the connection in VMware Aria Operations

        .EXAMPLE
        Test-vROPSAdapterConnection -json <json>
        This example tests the connection based on the JSON file provided

        .EXAMPLE
        Test-vROPSAdapterConnection -json <json> -patch
        This example patches the adapter based on the response from the test in JSON format.

        .PARAMETER json
        The JSON file to use for the test.

        .PARAMETER patch
        Patch the adapter based on the response from the test.
    #>



    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$patch
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }
        if ($PsBoundParameters.ContainsKey("patch")) {
            $uri = "https://$vropsAppliance/suite-api/api/adapters/testConnection"
            Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vropsHeaders -Body $body
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/adapters/testConnection"
            $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
            $response
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vROPSAdapterConnection

Function Start-vROPSAdapter {
    <#
        .SYNOPSIS
        Starts collection of adapter.

        .DESCRIPTION
        The Start-vROPSAdapter cmdlet starts the collection of an adapter in VMware Aria Operations

        .EXAMPLE
        Start-vROPSAdapter -adpaterId <id>
        This example starts the adpater by id.

        .PARAMETER adapterId
        The ID of the adapter to start.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adapterId
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/adapters/$adapterId/monitoringstate/start"
        Invoke-RestMethod -Method 'PUT' -Uri $Uri -Headers $vropsHeaders # API has no response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Start-vROPSAdapter

Function Stop-vROPSAdapter {
    <#
        .SYNOPSIS
        Stops collection of adapter.

        .DESCRIPTION
        The Stop-vROPSAdapter cmdlet starts the collection of an adapter in VMware Aria Operations

        .EXAMPLE
        Stop-vROPSAdapter -adpaterId <id>
        This example starts the adpater by id.

        .PARAMETER adapterId
        The ID of the adapter to stop.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adapterId
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/adapters/$adapterId/monitoringstate/stop"
        $response = Invoke-RestMethod -Method 'PUT' -Uri $Uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Stop-vROPSAdapter

Function Get-vROPSAdapterKind {
    <#
        .SYNOPSIS
        Get list of adapter kinds.

        .DESCRIPTION
        The Get-vROPSAdapterKind cmdlet gets a list of adapter kinds in VMware Aria Operations

        .EXAMPLE
        Get-vROPSAdapterKind
        This example gets a list of all adapter kinds

        .EXAMPLE
        Get-vROPSAdapterKind -kind VMWARE
        This example gets details of an resource kinds for the VMWARE adapter kind.

        .PARAMETER adapterKind
        The adapter kind to get resource kinds for.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet("Container", "EP Ops Adapter", "Http Post", "LogInsight", "MicrosoftAzureAdapter", "AmazonAWSAdapter", "NSXTAdapter", "PingAdapter", "SDDCHealthAdapter", "APPLICATIONDISCOVERY", "VMWARE", "VmcAdapter", "IdentityManagerAdapter", "APPOSUCP", "VOAAdapter", "CASAdapter", "LogInsightAdapter", "NETWORK_INSIGHT", "vCenter Operations Adapter", "vRealizeOpsMgrAPI", "VirtualAndPhysicalSANAdapter")] [ValidateNotNullOrEmpty()] [String]$adapterKind
    )

    Try {
        if ($PsBoundParameters.ContainsKey("adapterKind")) {
            $uri = "https://$vropsAppliance/suite-api/api/adapterkinds/$adapterKind"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.resourceKinds
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/adapterkinds"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.'adapter-kind'
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSAdapterKind

Function Get-vROPSResourceDetail {
    <#
        .SYNOPSIS
        Get resource detail.

        .DESCRIPTION
        The Get-vROPSResourceDetail cmdlet gets the details for a resource from VMware Aria Operations

        .EXAMPLE
        Get-vROPSResourceDetail -adapter VMWARE -resource Datacenter -objectName sfo-m01-dc01
        This example gets the resource details.

        .PARAMETER adapter
        The adapter to get the resource from.

        .PARAMETER resource
        The resource to get the details for.

        .PARAMETER objectName
        The name of the object to get the details for.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adapter,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$resource,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$objectname
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/adapterkinds/$adapter/resourcekinds/$resource/resources?identifiers[VMEntityName]=$objectName"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
        $response.resourceList.resourceKey.resourceIdentifiers
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSResourceDetail

Function Get-vROPSCredential {
    <#
        .SYNOPSIS
        Get credentials.

        .DESCRIPTION
        The Get-vROPSCredential cmdlet gets credentials from VMware Aria Operations

        .EXAMPLE
        Get-vROPSCredential
        This example gets all credentials from VMware Aria Operations.

        .PARAMETER credentialId
        The ID of the credential to get.

        .PARAMETER adapter
        The adapter to get credentials for.

        .PARAMETER resource
        The resource to get credentials for.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$credentialId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$adapter,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$resource
    )

    Try {
        if ($PsBoundParameters.ContainsKey("credentialId") -and (-not $PsBoundParameters.ContainsKey("adapter") -and (-not $PsBoundParameters.ContainsKey("resource")))) {
            $uri = "https://$vropsAppliance/suite-api/api/credentials/$credentialId"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("credentialId") -and ($PsBoundParameters.ContainsKey("adapter"))) {
            $uri = "https://$vropsAppliance/suite-api/api/credentials/$credentialId/adapters"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.adapterInstancesInfoDto
        } elseif ($PsBoundParameters.ContainsKey("credentialId") -and ($PsBoundParameters.ContainsKey("resource"))) {
            $uri = "https://$vropsAppliance/suite-api/api/credentials/$credentialId/resources"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/credentials"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.credentialInstances
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSCredential

Function Add-vROPSCredential {
    <#
        .SYNOPSIS
        Add a credential.

        .DESCRIPTION
        The Add-vROPSCredential cmdlet adds a credential to VMware Aria Operations

        .EXAMPLE
        Add-vROPSCredential -json .\credentialJson
        This example adds a new credential.

        .PARAMETER json
        The JSON file containing the credential details.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }
        $uri = "https://$vropsAppliance/suite-api/api/credentials"
        $response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vROPSCredential

Function Remove-vROPSCredential {
    <#
        .SYNOPSIS
        Delete a credential.

        .DESCRIPTION
        The Remove-vROPSCredential cmdlet deletes a credential from VMware Aria Operations

        .EXAMPLE
        Remove-vROPSCredential -credentialId <id>
        This example deletes a credential.

        .PARAMETER credentialId
        The ID of the credential to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$credentialId
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/credentials/$credentialId"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $Uri -Headers $vropsHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSCredential

Function Get-vROPSCurrency {
    <#
        .SYNOPSIS
        Get the currency configuration.

        .DESCRIPTION
        The Get-vROPSCurrency cmdlet gets the currency configuration for VMware Aria Operations

        .EXAMPLE
        Get-vROPSCurrency
        This example gets the currency configuration for VMware Aria Operations.
    #>


    Try {
        $uri = "https://$vropsAppliance/suite-api/api/costconfig/currency"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSCurrency

Function Set-vROPSCurrency {
    <#
        .SYNOPSIS
        Applies the currency configuration.

        .DESCRIPTION
        The Set-vROPSCurrency cmdlet applies the currency configuration for VMware Aria Operations.
        NOTE: Once applied for an instance it cannot be changed.

        .EXAMPLE
        Set-vROPSCurrency
        This example gets the currency configuration for VMware Aria Operations.

        .PARAMETER currency
        The currency code to apply.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$currency
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/costconfig/currency"
        $body = '{
            "code" : "'
+ $currency + '"
        }'

        $response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vROPSCurrency

Function Get-vROPSSolution {
    <#
        .SYNOPSIS
        Get list of solutions.

        .DESCRIPTION
        The Get-vROPSSolution cmdlet gets a list of solutions in VMware Aria Operations

        .EXAMPLE
        Get-vROPSSolution
        This example gets a list of all solutions

        .EXAMPLE
        Get-vROPSSolution -solutionId "vSphere"
        This example gets a list of all solutions.

        .PARAMETER solutionId
        The ID of the solution to get details for.

        .PARAMETER adapterKind
        The ID of the solution to get details for.

        .PARAMETER license
        The ID of the solution to get details for.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$solutionId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$adapterKind,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$license
    )

    Try {
        if ($PsBoundParameters.ContainsKey("solutionId") -and (-not $PsBoundParameters.ContainsKey("adapterKind") -and (-not $PsBoundParameters.ContainsKey("license")))) {
            $uri = "https://$vropsAppliance/suite-api/api/solutions/$solutionId"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("solutionId") -and ($PsBoundParameters.ContainsKey("adapterKind"))) {
            $uri = "https://$vropsAppliance/suite-api/api/solutions/$solutionId/adapterkinds"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.'adapter-kind'
        } elseif ($PsBoundParameters.ContainsKey("solutionId") -and ($PsBoundParameters.ContainsKey("license"))) {
            $uri = "https://$vropsAppliance/suite-api/api/solutions/$solutionId/licenses"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.solutionLicenses
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/solutions"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.solution
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSSolution

Function Import-vROPSManagementPack {
    <#
        .SYNOPSIS
        Upload a management pack.

        .DESCRIPTION
        The Import-vROPSManagementPack cmdlet uploads a management pack into VMware Aria Operations

        .EXAMPLE
        Import-vROPSManagementPack -server xint-vrops01.rainpole.io -username admin -password VMw@re1! -pak .\managementPack.pak
        This example uploads the management pack provided to VMware Aria Operations.

        .PARAMETER server
        The FQDN or IP address of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to authenticate to the VMware Aria Operations appliance.

        .PARAMETER password
        The password to authenticate to the VMware Aria Operations appliance.

        .PARAMETER pak
        The path to the management pack file to upload.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pak
    )

    Try {
        if ($PsBoundParameters.ContainsKey("pak")) {
            if (!(Test-Path $pak)) {
                Throw "Management Pack file $pak not found"
            }
        }
        $uri = "https://$server/casa/upgrade/cluster/pak/reserved/operation/upload?pak_handling_advice=CLOBBER"
        $contentType = "application/octet-stream"

        Add-Type -AssemblyName System.Net.Http
        $httpClientHandler = New-Object System.Net.Http.HttpClientHandler
        $networkCredential = New-Object System.Net.NetworkCredential @($userName, $password)
        $httpClientHandler.Credentials = $networkCredential
        $httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler
        $packageFileStream = New-Object System.IO.FileStream @($pak, [System.IO.FileMode]::Open)
        $fileHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data"
        $fileHeaderValue.Name = "contents"
        $fileHeaderValue.FileName = (Split-Path $pak -leaf)
        $streamContent = New-Object System.Net.Http.StreamContent $packageFileStream
        $streamContent.Headers.ContentDisposition = $fileHeaderValue
        $streamContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue $contentType
        $content = New-Object System.Net.Http.MultipartFormDataContent
        $content.Add($streamContent)
        $response = $httpClient.PostAsync($uri, $content).Result

        if (!$response.IsSuccessStatusCode) {
            $responseBody = $response.Content.ReadAsStringAsync().Result
            $errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody
            Throw [System.Net.Http.HttpRequestException] $errorMessage
        }
        Return $response.Content.ReadAsStringAsync().Result
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Import-vROPSManagementPack

Function Install-vROPSManagementPack {
    <#
        .SYNOPSIS
        Install a management pack.

        .DESCRIPTION
        The Install-vROPSManagementPack cmdlet installs a management pack in VMware Aria Operations

        .EXAMPLE
        Install-vROPSManagementPack -server xint-vrops01.rainpole.io -username admin -password VMw@re1! -pakId SDDCHealth-8115995854
        This example installs the management pack in VMware Aria Operations.

        .PARAMETER server
        The FQDN or IP address of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to authenticate to the VMware Aria Operations appliance.

        .PARAMETER password
        The password to authenticate to the VMware Aria Operations appliance.

        .PARAMETER pakId
        The ID of the management pack to install.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pakId
    )

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vropsBasicHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vropsBasicHeaders.Add("Authorization", "Basic $base64AuthInfo")
        $vropsBasicHeaders.Add("Content-Type", "application/json")
        $response = Invoke-RestMethod "https://$server/casa/upgrade/cluster/pak/$pakId/operation/install" -Method 'POST' -Headers $vropsBasicHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Install-vROPSManagementPack

Function Set-vROPSManagementPack {
    <#
        .SYNOPSIS
        Activate / Deactivate a management pack.

        .DESCRIPTION
        The Set-vROPSManagementPack cmdlet activates or deactivates a management pack in VMware Aria Operations

        .EXAMPLE
        Set-vROPSManagementPack -server xint-vrops01.rainpole.io -username admin -password VMw@re1! -pakId PingAdapter -version "8.4.0.17863953" -status enable
        This example activates the Ping management pack in VMware Aria Operations

        Set-vROPSManagementPack -server xint-vrops01.rainpole.io -username admin -password VMw@re1! -pakId PingAdapter -version "8.4.0.17863953" -status disable
        This example deactivates the Ping management pack in VMware Aria Operations.

        .PARAMETER server
        The FQDN or IP address of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to authenticate to the VMware Aria Operations appliance.

        .PARAMETER password
        The password to authenticate to the VMware Aria Operations appliance.

        .PARAMETER pakId
        The ID of the management pack to activate or deactivate.

        .PARAMETER version
        The version of the management pack to activate or deactivate.

        .PARAMETER status
        The status to set the management pack to. Valid values are enable or disable.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pakId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$version,
        [Parameter (Mandatory = $true)] [ValidateSet("enable", "disable")] [ValidateNotNullOrEmpty()] [String]$status
    )

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vropsBasicHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vropsBasicHeaders.Add("Authorization", "Basic $base64AuthInfo")
        $vropsBasicHeaders.Add("Content-Type", "application/json")
        $body = '{
            "pak_id" : "'
+ $pakId + '",
            "version" : "'
+ $version + '",
            "force_content_update": true
        }'

        $response = Invoke-RestMethod "https://$server/casa/upgrade/cluster/pak/operation/$status" -Method 'POST' -Headers $vropsBasicHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vROPSManagementPack

Function Get-vROPSManagementPack {
    <#
        .SYNOPSIS
        Get installed management packs.

        .DESCRIPTION
        The Get-vROPSManagementPack cmdlet gets a list of installed management packs in VMware Aria Operations

        .EXAMPLE
        Get-vROPSManagementPack -server xint-vrops01.rainpole.io -username admin -password VMw@re1!
        This example gets a list of all the management packs installed in VMware Aria Operations.

        .PARAMETER server
        The FQDN or IP address of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to authenticate to the VMware Aria Operations appliance.

        .PARAMETER password
        The password to authenticate to the VMware Aria Operations appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password
    )

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vropsBasicHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vropsBasicHeaders.Add("Authorization", "Basic $base64AuthInfo")
        $vropsBasicHeaders.Add("Content-Type", "application/json")
        $response = Invoke-RestMethod "https://$server/casa/upgrade/cluster/pak/reserved/list" -Method 'GET' -Headers $vropsBasicHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSManagementPack

Function Get-vROPSManagementPackStatus {
    <#
        .SYNOPSIS
        Get install status of management pack.

        .DESCRIPTION
        The Get-vROPSManagementPackStatus cmdlet gets the status of the install of a management pack in VMware Aria Operations

        .EXAMPLE
        Get-vROPSManagementPackStatus -server xint-vrops01.rainpole.io -username admin -password VMw@re1! -pakId SDDCHealth-8115995854
        This example uploads the management pack provided to VMware Aria Operations.

        .PARAMETER server
        The FQDN or IP address of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to authenticate to the VMware Aria Operations appliance.

        .PARAMETER password
        The password to authenticate to the VMware Aria Operations appliance.

        .PARAMETER pakId
        The ID of the management pack to get the status of.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pakId
    )

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vropsBasicHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vropsBasicHeaders.Add("Authorization", "Basic $base64AuthInfo")
        $response = Invoke-RestMethod "https://$server/casa/upgrade/cluster/pak/$pakId/status" -Method 'GET' -Headers $vropsBasicHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSManagementPackStatus

Function Get-vROPSManagementPackActivity {
    <#
        .SYNOPSIS
        Get current activity.

        .DESCRIPTION
        The Get-vROPSManagementPackActivity cmdlet gets the current activity for management packs in VMware Aria Operations

        .EXAMPLE
        Get-vROPSManagementPackActivity -server xint-vrops01.rainpole.io -username admin -password VMw@re1!
        This example gets the current management pack activity in VMware Aria Operations.

        .PARAMETER server
        The FQDN or IP address of the VMware Aria Operations appliance.

        .PARAMETER username
        The username to authenticate to the VMware Aria Operations appliance.

        .PARAMETER password
        The password to authenticate to the VMware Aria Operations appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password
    )

    Try {

        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vropsBasicHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vropsBasicHeaders.Add("Authorization", "Basic $base64AuthInfo")
        $response = Invoke-RestMethod "https://$server/casa/upgrade/cluster/pak/reserved/current_activity" -Method 'GET' -Headers $vropsBasicHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSManagementPackActivity

Function Get-vROPSAlertPlugin {
    <#
        .SYNOPSIS
        Get the alert plugins.

        .DESCRIPTION
        The Get-vROPSAlertPlugin cmdlet gets the configured alert plugins in VMware Aria Operations

        .EXAMPLE
        Get-vROPSAlertPlugin
        This example gets a list of the alert plugins configure in VMware Aria Operations.
    #>


    Try {
        $uri = "https://$vropsAppliance/suite-api/api/alertplugins"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
        $response.notificationPluginInstances
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSAlertPlugin

Function Add-vROPSAlertPlugin {
    <#
        .SYNOPSIS
        Create an alert plugin.

        .DESCRIPTION
        The Add-vROPSAlertPlugin cmdlet creates a new alert plugin in VMware Aria Operations

        .EXAMPLE
        Add-vROPSAlertPlugin -json .\alertPlugin.json
        This example adds a new alert plugin based on the JSON provide to VMware Aria Operations.

        .PARAMETER json
        The JSON file containing the alert plugin configuration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }

        $uri = "https://$vropsAppliance/suite-api/api/alertplugins"
        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vROPSAlertPlugin

Function Set-vROPSAlertPlugin {
    <#
        .SYNOPSIS
        Updates an alert plugin.

        .DESCRIPTION
        The Set-vROPSAlertPlugin cmdlet updates an existing alert plugin in VMware Aria Operations

        .EXAMPLE
        Set-vROPSAlertPlugin -json .\alertPluginUpdate.json
        This example updates the configuration of an existing alert plugin based on the JSON provide to VMware Aria Operations.

        .PARAMETER json
        The JSON file containing the alert plugin configuration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        if ($PsBoundParameters.ContainsKey("json")) {
            if (!(Test-Path $json)) {
                Throw "JSON File Not Found"
            } else {
                $body = (Get-Content $json) # Read the json file contents into the $body variable
            }
        }
        $uri = "https://$vropsAppliance/suite-api/api/alertplugins"
        $response = Invoke-RestMethod -Method 'PUT' -Uri $uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vROPSAlertPlugin

Function Remove-vROPSAlertPlugin {
    <#
        .SYNOPSIS
        Delete an alert plugin.

        .DESCRIPTION
        The Remove-vROPSAlertPlugin cmdlet deletes an existing alert plugin from VMware Aria Operations

        .EXAMPLE
        Remove-vROPSAlertPlugin -plugId <plugin_id>
        This example deletes the alert plugin with the plugin ID provide to VMware Aria Operations.

        .PARAMETER pluginId
        The ID of the alert plugin to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pluginId
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/alertplugins/$pluginId"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSAlertPlugin

Function Get-vROPSAlertDefinition {
    <#
        .SYNOPSIS
        Get collection of alert definitions matching the search criteria specified.

        .DESCRIPTION
        The Get-vROPSAlertDefinition cmdlet gets collection of alert definitions matching the search criteria specified
        in VMare Aria Operations

        .EXAMPLE
        Get-vROPSAlertDefinition
        This example gets all alert definitions

        .EXAMPLE
        Get-vROPSAlertDefinition -id SrmAdapter
        This example gets an alert definition by its id

        .EXAMPLE
        Get-vROPSAlertDefinition -adapterKind SrmAdapter
        This example gets all alert definitions for the adapter type SrmAdapter

        .EXAMPLE
        Get-vROPSAlertDefinition -resourceKind "Protection Groups"
        This example gets all alert definitions for the resource type SrmAdapter.

        .PARAMETER id
        The ID of the alert definition to get.

        .PARAMETER adapterKind
        The adapter kind of the alert definition to get.

        .PARAMETER resourceKind
        The resource kind of the alert definition to get.
    #>


    [CmdletBinding(DefaultParametersetName = 'default')][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'id')] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false, ParameterSetName = 'adapterKind')] [ValidateNotNullOrEmpty()] [String]$adapterKind,
        [Parameter (Mandatory = $false, ParameterSetName = 'resourceKind')] [ValidateNotNullOrEmpty()] [String]$resourceKind
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/alertdefinitions?id=$id&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.alertDefinitions
        } elseif ($PsBoundParameters.ContainsKey("adapterKind")) {
            $uri = "https://$vropsAppliance/suite-api/api/alertdefinitions?adapterKind=$adapterKind&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.alertDefinitions
        } elseif ($PsBoundParameters.ContainsKey("resourceKind")) {
            $uri = "https://$vropsAppliance/suite-api/api/alertdefinitions?resourceKind=$resourceKind&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.alertDefinitions
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/alertdefinitions"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.alertDefinitions
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSAlertDefinition

Function Set-vROPSAlertPluginStatus {
    <#
        .SYNOPSIS
        Enable/Disable alert plugin.

        .DESCRIPTION
        The Set-vROPSAlertPluginStatus cmdlet Enables/Disables an existing alert plugin from VMware Aria Operations

        .EXAMPLE
        Set-vROPSAlertPluginStatus -plugId <plugin_id> -status true
        This example deletes the alert plugin with the plugin ID provide to VMware Aria Operations.

        .PARAMETER pluginId
        The ID of the alert plugin to enable/disable.

        .PARAMETER status
        The status of the alert plugin to enable/disable.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pluginId,
        [Parameter (Mandatory = $true)] [ValidateSet("false", "true")] [ValidateNotNullOrEmpty()] [String]$status
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/alertplugins/$pluginId/enable/$status"
        $response = Invoke-RestMethod -Method 'PUT' -Uri $uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vROPSAlertPluginStatus

Function Get-vROPSAuthSource {
    <#
        .SYNOPSIS
        Get all the available authentication sources in the system.

        .DESCRIPTION
        The Get-vROPSAuthSource cmdlet gets all the available authentication sources in VMware Aria Operations

        .EXAMPLE
        Get-vROPSAuthSource
        This example gets a list of all available authentication sources

        .EXAMPLE
        Get-vROPSAuthSource -sourceId <source_id>
        This example gets detailed information about the provided authentication source.

        .PARAMETER sourceId
        The ID of the authentication source to get.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$sourceId
    )

    Try {
        if ($PsBoundParameters.ContainsKey("sourceId")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/sources/$sourceId"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/auth/sources"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.sources
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSAuthSource

Function Get-vROPSAuthRole {
    <#
        .SYNOPSIS
        Get all the roles available in the system.

        .DESCRIPTION
        The Get-vROPSAuthRole cmdlet gets all the roles available in VMware Aria Operations

        .EXAMPLE
        Get-vROPSAuthRole
        This example gets all the roles available.

        .PARAMETER name
        The name of the role to get.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        if ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/roles/$name"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/auth/roles"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.userRoles
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSAuthRole

Function Get-vROPSUserAccount {
    <#
        .SYNOPSIS
        Get list of local user accounts using identifiers or/and names.

        .DESCRIPTION
        The Get-vROPSUserAccount cmdlet gets a user account in VMware Aria Operations

        .EXAMPLE
        Get-vROPSUserAccount
        This example gets a list of all available authentication sources.

        .EXAMPLE
        Get-vROPSUserAccount -id <userAccount_id>
        This example gets detailed information about the user account using the ID.

        .EXAMPLE
        Get-vROPSUserAccount -username <userAccount_username>
        This example gets detailed information about the user account using the username.

        .EXAMPLE
        Get-vROPSUserAccount -roleName <userAccount_roleName>
        This example gets detailed information about the user account using the role name.

        .PARAMETER id
        The ID of the user account to get.

        .PARAMETER username
        The username of the user account to get.

        .PARAMETER roleName
        The role name of the user account to get.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$roleName
    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/users?id=$id&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("username")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/users?username=$username&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response.users
        } elseif ($PsBoundParameters.ContainsKey("roleName")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/users?roleName=$roleName&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.users
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/auth/users"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.users
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSUserAccount

Function Get-vROPSUserGroup {
    <#
        .SYNOPSIS
        Get list of local user groups using identifiers or/and names.

        .DESCRIPTION
        The Get-vROPSUserGroup cmdlet gets list of local user groups in VMware Aria Operations

        .EXAMPLE
        Get-vROPSUserGroup
        This example gets a list of all available authentication sources

        .EXAMPLE
        Get-vROPSUserGroup -id <userGroup_id>
        This example gets detailed information about the provided user group using the ID

        .EXAMPLE
        Get-vROPSUserGroup -id <userGroup_id>
        This example gets detailed information about the provided user group using the name.

        .PARAMETER id
        The ID of the user group to get.

        .PARAMETER name
        The name of the user group to get.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$name

    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/usergroups?id=$id&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders
            $response
        } elseif ($PsBoundParameters.ContainsKey("name")) {
            $uri = "https://$vropsAppliance/suite-api/api/auth/usergroups?name=$name&_no_links=true"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.userGroups
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/auth/usergroups"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.userGroups
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSUserGroup

Function Add-vROPSUserAccount {
    <#
        .SYNOPSIS
        Imports a user account from an authentication source.

        .DESCRIPTION
        The Add-vROPSUserAccount cmdlet imports a user account from the authentication source into VMware Aria
        Operations

        .EXAMPLE
        Add-vROPSUserAccount -sourceId <authentication_sourceId> -userName <user_account_name> -lastName <user_last_name> -firstName <user_first_name> -distinguishedName <user_distinguishedName> -role <role_name>
        This example imports a user account from the authentication source and assigns a role.

        .PARAMETER sourceId
        The ID of the authentication source to import the user account from.

        .PARAMETER userName
        The name of the user account to import.

        .PARAMETER lastName
        The last name of the user account to import.

        .PARAMETER firstName
        The first name of the user account to import.

        .PARAMETER distinguishedName
        The distinguished name of the user account to import.

        .PARAMETER role
        The name of the role to assign to the user account.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sourceId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$lastName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$firstName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$distinguishedName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/sources/$sourceId/users"
        $body = '{ "users" : [
        {
            "username" : "'
 + $userName + '",
            "firstName" : "'
 + $firstName + '",
            "lastName" : "'
 + $lastName + '",
            "distinguishedName" : "'
 + $domain + '",
            "emailAddress" : "'
 + $userName + '@' + $domain + '",
            "enabled" : true,
            "role-permissions" : [ {
                "roleName" : "'
 + $role + '",
                "allowAllObjects" : true
            } ]
        }]}'

        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vROPSUserAccount

Function Add-vROPSUserGroup {
    <#
        .SYNOPSIS
        Import user group from an authentication source.

        .DESCRIPTION
        The Add-vROPSUserGroup cmdlet imports a user group from the authentication source into VMware Aria Operations

        .EXAMPLE
        Add-vROPSUserGroup -sourceId <authentication_sourceId> -userGroup <user_group_name> -role <role_name>
        This example imports a user group from the authentication source and assigns the Administrator Role.

        .PARAMETER sourceId
        The ID of the authentication source to import the user group from.

        .PARAMETER userGroup
        The name of the user group to import.

        .PARAMETER role
        The name of the role to assign to the user group.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sourceId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$userGroup,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$role
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/usergroups"
        $body = '{
            "authSourceId" : "'
 + $sourceId + '",
            "name" : "'
 + $userGroup + '",
            "role-permissions" : [ {
                "roleName" : "'
 + $role + '",
                "allowAllObjects" : true
            } ]
        }'

        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vROPSUserGroup

Function Remove-vROPSUserAccount {
    <#
        .SYNOPSIS
        Deletes a user account.

        .DESCRIPTION
        The Remove-vROPSUserAccount cmdlet deletes a user account from VMware Aria Operations.

        .EXAMPLE
        Remove-vROPSUserAccount -id <userAccount_Id>
        This example deletes a user account from VMware Aria Operations.

        .PARAMETER id
        The ID of the user account to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/users/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSUserAccount

Function Remove-vROPSUserGroup {
    <#
        .SYNOPSIS
        Deletes a user group.

        .DESCRIPTION
        The Remove-vROPSUserGroup cmdlet deletes a user group from VMware Aria Operations

        .EXAMPLE
        Remove-vROPSUserGroup -id <userGroup_Id>
        This example deletes a user group from VMware Aria Operations.

        .PARAMETER id
        The ID of the user group to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/usergroups/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSUserGroup

Function Search-vROPSUserAccount {
    <#
        .SYNOPSIS
        Search for a user account in the source.

        .DESCRIPTION
        The Search-vROPSUserAccount cmdlet searches for a user account in the source in VMware Aria Operations.

        .EXAMPLE
        Search-vROPSUserAccount -sourceId 6d971ad0-a979-4dc1-81af-e77f6c8c158c -domain sfo.rainpole.io -userName "nigel.mccloud"
        This example searches for a user account in the source defined by source ID.

        .PARAMETER sourceId
        The ID of the source to search.

        .PARAMETER domain
        The domain of the user account to search.

        .PARAMETER userName
        The name of the user account to search.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$sourceId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$userName
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/sources/$sourceId/users/search"
        
        $body = '{
                "domain": "'
 + $domain + '",
                "name": "'
 + $nameName + '"
            }'

        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
        $response.'user-search-response'
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Search-vROPSUserAccount

Function Search-vROPSUserGroup {
    <#
        .SYNOPSIS
        Search for a user group in the source.

        .DESCRIPTION
        The Search-vROPSUserGroup cmdlet searches for a user group in the source in VMware Aria Operations

        .EXAMPLE
        Search-vROPSUserGroup -sourceId 6d971ad0-a979-4dc1-81af-e77f6c8c158c -domain sfo.rainpole.io -groupName "gg-vrops-read-only@sfo.rainpole.io"
        This example searches for a user group in the source defined by source ID.

        .PARAMETER sourceId
        The ID of the source to search.

        .PARAMETER domain
        The domain of the user group to search.

        .PARAMETER groupName
        The name of the user group to search.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$sourceId,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$groupName
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/sources/$sourceId/usergroups/search"
        
        $body = '{
                "domain": "'
 + $domain + '",
                "name": "'
 + $groupName + '"
            }'

        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
        $response.'usergroup-search-response'
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Search-vROPSUserGroup

Function Update-vROPSUserAccount {
    <#
        .SYNOPSIS
        Updates a user account.

        .DESCRIPTION
        The Update-vROPSUserAccount cmdlet updates a user account in VMware Aria Operations.

        .EXAMPLE
        Updates-vROPSUserAccount -id <userAccount_Id>
        This example updateds a user account in VMware Aria Operations.

        .PARAMETER id
        The ID of the user account to update.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/auth/users/$id"
        $response = Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vropsHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Update-vROPSUserAccount

Function Get-vROpsLogForwarding {
    <#
        .SYNOPSIS
        Gets the VMware Aria Operations logging forwarding configuration.

        .DESCRIPTION
        The Get-vROpsLogForwarding cmdlet gets the VMware Aria Operations logging forwarding configuration.

        .EXAMPLE
        Get-vROpsLogForwarding
        This example returns the logging forwarding configuration on VMware Aria Operations.
    #>


    Try {
        $uri = "https://$vropsAppliance/suite-api/api/logs/forwarding"
        if ($PSEdition -eq 'Core') {
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders -SkipCertificateCheck
        } else {
            $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders 
        }
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROpsLogForwarding

Function Get-vROPSNotification {
    <#
        .SYNOPSIS
        Get list of all notifications.

        .DESCRIPTION
        The Get-vROPSNotification cmdlet gets list of all notifications in VMware Aria Operations

        .EXAMPLE
        Get-vROPSNotification
        This example gets a list of all notifications

        .EXAMPLE
        Get-vROPSNotification -id <id>
        This example gets a list of all notifications.

        .PARAMETER id
        The ID of the notification to get.
     #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id

    )

    Try {
        if ($PsBoundParameters.ContainsKey("id")) {
            $uri = "https://$vropsAppliance/suite-api/api/notifications/rules/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response
        } else {
            $uri = "https://$vropsAppliance/suite-api/api/notifications/rules"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vropsHeaders
            $response.rules
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROPSNotification

Function New-vROPSNotification {
    <#
        .SYNOPSIS
        Create notifications in VMware Aria Operations.

        .DESCRIPTION
        The New-vROPSNotification cmdlet creates notifications in VMware Aria Operations

        .EXAMPLE
        New-vROPSNotification -csvPath .\SampleNotifications\aria-operations-notifications-vcf.csv
        This example adds all the notifications in the csv file to VMware Aria Operations.

        .PARAMETER csvPath
        The path to the csv file containing the notifications to add.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$csvPath
    )

    Try {
        if ($PsBoundParameters.ContainsKey("csvPath")) {
            if (!(Test-Path $csvPath)) {
                Throw "CSV File Not Found"
            } else {
                $alerts = Import-CSV $csvPath | Where-Object -FilterScript { $_.alertName }
            }
        }
        Foreach ($alert in $alerts) {
            if ((Get-vROPSAlertPlugin | Where-Object { $_.name -eq $($alert.alertPluginName) })) {
                $body = '{
                    "name": "'
+ $($alert.alertName) + '",
                    "pluginId": "'
+ (Get-vROPSAlertPlugin | Where-Object { $_.name -eq $($alert.alertPluginName) }).pluginId + '",
                    "resourceKindFilters": [
                        {
                            "resourceKind": "'
+ $($alert.resourceKindKey) + '",
                            "adapterKind": "'
+ $($alert.adapterKindKey) + '"
                        }
                    ],
                    "resourceFilters": [ ],
                    "alertDefinitionIdFilters": {
                        "values": [ "'
+ $($alert.alertDefinition) + '" ]
                    },
                    "properties": [
                        {
                            "name": "maxNotify",
                            "value": "'
+ $($alert.maxNotify) + '"
                        },
                        {
                            "name": "delay",
                            "value": "'
+ $($alert.delay) + '"
                        },
                        {
                            "name": "emailaddr",
                            "value": "'
+ $($alert.emailAddress) + '"
                        },
                        {
                            "name": "resend",
                            "value": "'
+ $($alert.resend) + '"
                        }
                    ]
                }'

                $uri = "https://$vropsAppliance/suite-api/api/notifications/rules"
                if (!(Get-vROPSNotification | Where-Object { $_.name -eq $($alert.alertName) })) {
                    Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vropsHeaders -Body $body
                }
            } else {
                Write-Error "Unable to Add Notification for Alert Definition ($($alert.alertDefinition)), Due to Incorrect Alert Plugin Name ($($alert.alertPluginName))"
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vROPSNotification

Function Remove-vROPSNotification {
    <#
        .SYNOPSIS
        Delete a notification.

        .DESCRIPTION
        The Remove-vROPSNotification cmdlet deletes a notifications in VMware Aria Operations

        .EXAMPLE
        Remove-vROPSNotification -id <id>
        This example deletes a notifications.

        .PARAMETER id
        The ID of the notification to delete.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id

    )

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/notifications/rules/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vropsHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vROPSNotification

Function Test-vROPsAdapterStatus {
    <#
        .SYNOPSIS
        Validates the integration status of a VMware Aria Operations adapter through adapter's ID
        
        .DESCRIPTION
        The Test-vROPsAdapterStatus cmdlet validates the integration status between VMware Aria Operations and
        configured adapter.
    
        .EXAMPLE
        Test-vROPsAdapterStatus -resourceId "b214fd75-07cc-4dab-9fbb-95a6af739a04"
        This example validates the integration status between VMware Aria Operations and configured adapter through its ID. .

        .PARAMETER resourceId
        The ID of the adapter to validate the integration status.
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$resourceId
    )

    $name = (Get-vROPSAdapter | Where-Object { $_.id -eq $resourceId }).resourceKey.name

    Try {
        $uri = "https://$vropsAppliance/suite-api/api/resources/$resourceId"
        if ($PSEdition -eq 'Core') {
            $vropsresponse = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders -SkipCertificateCheck # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vropsresponse = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vropsHeaders 
        }
        if ($vropsresponse.resourceHealth -eq "GREEN") {
            Write-Output "Adapter Name : $($name), Health Status: GREEN" 
        } else { 
            Write-Output "Adapter Name : $($name), Health Status: $($vropsresponse.resourceHealth), please check adapter log for details"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vROPsAdapterStatus

#EndRegion End VMware Aria Operations Functions ######
###################################################################################

###################################################################################
#Region Start VMware Aria Operations for Logs Functions ######

Function Request-vRLIToken {
    <#
        .SYNOPSIS
        Connects to the specified VMware Aria Operations for Logs instance and obtains authorization token.

        .DESCRIPTION
        The Request-vRLIToken cmdlet connects to the specified VMware Aria Operations for Logs instance and obtains an
        authorization token. It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-vRLIToken -fqdn sfo-vrli01.sfo.rainpole.io -username admin -password VMw@re1!
        This example shows how to connect to the VMware Aria Operations for Logs instance.

        .PARAMETER fqdn
        The fully qualified domain name of the VMware Aria Operations for Logs instance.

        .PARAMETER username
        The username of the VMware Aria Operations for Logs instance.

        .PARAMETER password
        The password of the VMware Aria Operations for Logs instance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    Try {
        $Global:vrliAppliance = $fqdn + ":9543"
        $Global:vrliHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $vrliHeaders.Add("Content-Type", "application/json")
        $uri = "https://$vrliAppliance/api/v1/sessions"
        $body = '{
            "username": "'
+ $username + '",
            "password": "'
+ $password + '",
            "provider": "Local"
        }'

        if ($PSEdition -eq 'Core') {
            $vrliResponse = Invoke-RestMethod -Uri $uri -Method 'POST' -Headers $vrliHeaders -Body $body -SkipCertificateCheck # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vrliResponse = Invoke-RestMethod -Uri $uri -Method 'POST' -Headers $vrliHeaders -Body $body
        }
        if ($vrliResponse.sessionId) {
            $vrliHeaders.Add("Authorization", "Bearer " + $vrliResponse.sessionId)
            Write-Output "Successfully Connected to VMware Aria Operations for Logs: $vrliAppliance"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-vRLIToken

Function Get-vRLIVersion {
    <#
        .SYNOPSIS
        Get VMware Aria Operations for Logs version information.

        .DESCRIPTION
        The Get-vRLIVersion cmdlet gets the VMware Aria Operations for Logs version information

        .EXAMPLE
        Get-vRLIVersion
        This example gets the VMware Aria Operations for Logs version information.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/version"
        Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIVersion

Function Get-vRLIAuthenticationWSA {
    <#
        .SYNOPSIS
        Get configuration of Workspace ONE Access.

        .DESCRIPTION
        The Get-vRLIAuthenticationWSA cmdlet gets the configuration for Workspace ONE Access Integration

        .EXAMPLE
        Get-vRLIAuthenticationWSA
        This example gets the configuration for the Workspace ONE Access Integration

        .EXAMPLE
        Get-vRLIAuthenticationWSA -statuss
        This example gets the connection status for the Workspace ONE Access Integration.

        .PARAMETER status
        The status of the Workspace ONE Access Integration.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$status
    )

    Try {
        if ($PsBoundParameters.ContainsKey("status")) {
            $uri = "https://$vrliAppliance/api/v1/vidm/status"
        } else {
            $uri = "https://$vrliAppliance/api/v1/vidm"
        }
        Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIAuthenticationWSA

Function Set-vRLIAuthenticationWSA {
    <#
        .SYNOPSIS
        Configure Workspace ONE Access as an authentication provider.

        .DESCRIPTION
        The Set-vRLIAuthenticationWSA cmdlet configures the Workspace ONE Access as an authentication provider in
        VMware Operations for Logs

        .EXAMPLE
        Set-vRLIAuthenticationWSA -hostname sfo-wsa01.sfo.rainpole.io -port 443 -redirectUrl sfo-vrli01.sfo.rainpole.io -username admin -password VMw@re1!
        This example configures Workspace ONE Access as an authentication provider.

        .PARAMETER hostname
        The hostname of the Workspace ONE Access appliance.

        .PARAMETER port
        The port of the Workspace ONE Access appliance.

        .PARAMETER redirectUrl
        The redirect URL of the Workspace ONE Access appliance.

        .PARAMETER username
        The username of the Workspace ONE Access appliance.

        .PARAMETER password
        The password of the Workspace ONE Access appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$hostname,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$redirectUrl,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$password
    )

    Try {
        $jsonSpec = @()
        $jsonSpec += [pscustomobject]@{
            'acceptCert'  = $true
            'enabled'     = $true
            'hostname'    = $hostname
            'port'        = $port
            'redirectURL' = $redirectUrl
            'username'    = $username
            'password'    = $password 
        }
        
        $body = $jsonSpec | ConvertTo-Json -Depth 12
        $uri = "https://$vrliAppliance/api/v1/vidm"
        $response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLIAuthenticationWSA

Function Remove-vRLIAuthenticationWSA {
    <#
        .SYNOPSIS
        Disables Workspace ONE Access Intergration.

        .DESCRIPTION
        The Remove-vRLIAuthenticationWSA cmdlet disables Workspace ONE Access Integration

        .EXAMPLE
        Remove-vRLIAuthenticationWSA
        This example disables Workspace ONE Access Integration.
    #>


    Try {
        $jsonSpec = @()
        $jsonSpec += [pscustomobject]@{
            'enabled' = $false
        }
        $body = $jsonSpec | ConvertTo-Json -Depth 12
        $uri = "https://$vrliAppliance/api/v1/vidm"
        $response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vrliHeaders -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLIAuthenticationWSA

Function Get-vRLIAuthenticationAD {
    <#
        .SYNOPSIS
        Get Active Directory configuration settings.

        .DESCRIPTION
        The Get-vRLIAuthenticationAD cmdlet gets the Active Directory configuration settings

        .EXAMPLE
        Get-vRLIAuthenticationAD
        This example gets the the Active Directory configuration settings.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/ad"
        Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIAuthenticationAD

Function Set-vRLIAuthenticationAD {
    <#
        .SYNOPSIS
        Configure Active Directory as an authentication provider.

        .DESCRIPTION
        The Set-vRLIAuthenticationAD cmdlet configures Active Directory as an authentication provider in VMware
        Operations for Logs

        .EXAMPLE
        Set-vRLIAuthenticationAD -domain sfo.rainpole.io -domainServers sfo-ad01.sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -connectionType STANDARD
        This example configures Active Directory as an authentication provider

        .EXAMPLE
        Set-vRLIAuthenticationAD -domain sfo.rainpole.io -domainServers sfo-ad01.sfo.rainpole.io -domainBindUser svc-vsphere-ad -domainBindPass VMw@re1! -connectionType CUSTOM -port 636 -requireSsl:$true
        This example configures Active Directory as an authentication provider using custom configuration.

        .PARAMETER domain
        The domain name of the Active Directory server.

        .PARAMETER domainBindUser
        The username of the Active Directory server.

        .PARAMETER domainBindPass
        The password of the Active Directory server.

        .PARAMETER domainServers
        The hostname of the Active Directory server.

        .PARAMETER connectionType
        The connection type of the Active Directory server. Valid values are STANDARD, GLOBAL_CAT, and CUSTOM.

        .PARAMETER requireSsl
        The SSL requirement of the Active Directory server.

        .PARAMETER port
        The port of the Active Directory server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domainBindPass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$domainServers,
        [Parameter (Mandatory = $false)] [ValidateSet("STANDARD","GLOBAL_CAT","CUSTOM")] [String]$connectionType,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Boolean]$requireSsl=$false,
        [Parameter (Mandatory = $false)] [ValidateSet("389","636","50001")] [String]$port='389'
    )

    Try {
        $jsonSpec = New-Object -TypeName psobject
        $jsonSpec | Add-Member -notepropertyname 'enableAD' -notepropertyvalue $true
        $jsonSpec | Add-Member -notepropertyname 'domain' -notepropertyvalue $domain
        $jsonSpec | Add-Member -notepropertyname 'domainServers' -notepropertyvalue $domainServers
        $jsonSpec | Add-Member -notepropertyname 'username' -notepropertyvalue $domainBindUser
        $jsonSpec | Add-Member -notepropertyname 'password' -notepropertyvalue $domainBindPass
        $jsonSpec | Add-Member -notepropertyname 'connType' -notepropertyvalue $connectionType
        $jsonSpec | Add-Member -notepropertyname 'acceptCert' -notepropertyvalue $true
        $jsonSpec | Add-Member -notepropertyname 'sslOnly' -notepropertyvalue $requireSsl
        if ($connectionType -eq "Custom") {
            $jsonSpec | Add-Member -notepropertyname 'port' -notepropertyvalue $port
            $body = $jsonSpec | ConvertTo-Json
        } else {
            $body = $jsonSpec | ConvertTo-Json
        }
        $uri = "https://$vrliAppliance/api/v2/ad"
        Invoke-RestMethod $uri -Method 'POST' -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLIAuthenticationAD

Function Remove-vRLIAuthenticationAD {
    <#
        .SYNOPSIS
        Disable Active Directory as an authentication provider.

        .DESCRIPTION
        The Remove-vRLIAuthenticationAD cmdlet disbales Active Directory as an authentication provider in VMware
        Operations for Logs

        .EXAMPLE
        Remove-vRLIAuthenticationAD
        This example disables Active Directory as an authentication provider in VMware Aria Suite Lifecycle.
    #>


    Try {
        $jsonSpec = New-Object -TypeName psobject
        $jsonSpec | Add-Member -notepropertyname 'enableAD' -notepropertyvalue $false
        $body = $jsonSpec | ConvertTo-Json
        $uri = "https://$vrliAppliance/api/v2/ad"
        Invoke-RestMethod $uri -Method 'POST' -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLIAuthenticationAD

Function Get-vRLIAgentGroup {
    <#
        .SYNOPSIS
        Get list of agent groups.

        .DESCRIPTION
        The Get-vRLIAgentGroup cmdlet gets a list of agent groups

        .EXAMPLE
        Get-vRLIAgentGroup
        This example gets a list agent groups.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/agent/groups"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
        $response.groups
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIAgentGroup

Function New-vRLIAgentGroup {
    <#
        .SYNOPSIS
        Create a new agent group.

        .DESCRIPTION
        The New-vRLIAgentGroup cmdlet creates a new agent group

        .EXAMPLE
        New-vRLIAgentGroup -agentGroupType wsa -criteria sfo-wsa01.sfo.rainpole.io
        This example creates a new agent group for Workspace ONE Access and assigns the sfo-wsa01.sfo.rainpole.io host
        
        .EXAMPLE
        New-vRLIAgentGroup -agentGroupType photon -criteria sfo-vcf01.sfo.rainpole.io,xint-vrslcm01.rainpole.io,sfo-wsa01.sfo.rainpole.io
        This example creates a new agent group for Workspace ONE Access and assigns the hosts provided in the criteria host.

        .PARAMETER agentGroupType
        The type of agent group to create. Valid values are wsa and photon.

        .PARAMETER criteria
        The criteria for the agent group. For Workspace ONE Access, this is the hostname of the Workspace ONE Access appliance. For VMware Aria Operations for Logs, this is a comma-separated list of hostnames of the VMware Aria Operations for Logs appliances.

        .PARAMETER agentGroupName
        The name of the agent group to create. If not specified, the name is automatically generated.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("wsa", "photon")] [ValidateNotNullOrEmpty()] [String]$agentGroupType,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$agentGroupName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$criteria
    )

    if ($agentGroupType -eq "wsa") {
        $agentGroupConfig = '[filelog|gb-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=greenbox*.log\nevent_marker=^\\d{4}-\\d{2}-\\d{2}\nparser=gb-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"greenbox\"}\n\n[parser|gb-parser-onprem]\nbase_parser=clf\nformat=%t %{priority}i (%{thread}i) [%{java_class}i] - %M\n; Analytics Log InSight agent section\n\n[filelog|analytics-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=analytics-*.log\nevent_marker=^\\d{4}-\\d{2}-\\d{2}\nparser=analytics-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"analytics\"}\n\n[parser|analytics-parser-onprem]\nbase_parser=clf\nformat=%t %{timezone}i %{priority}i %{instance}i:%{service}i (%{thread}i) [%{src_str}i] %{java_class}i - %M\n; Password vault Log InSight agent section\n\n[filelog|pwvault-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=pwvault-*.log\nevent_marker=^\\d{4}-\\d{2}-\\d{2}\nparser=pwvault-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"pwvault\"}\n\n[parser|pwvault-parser-onprem]\nbase_parser=clf\nformat=%t %{timezone}i %{priority}i %{instance}i:%{service}i (%{thread}i) [%{src_str}i] %{java_class}i - %M\n\n[filelog|cert-proxy-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=cert-proxy*.log\nevent_marker=^\\d{4}-\\d{2}-\\d{2}\nparser=cert-proxy-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"cert-proxy\"}\n\n[parser|cert-proxy-parser-onprem]\nbase_parser=clf\nformat=%t %{priority}i (%{thread}i) [%{src_str}i] %{java_class}i - %M\n; vIDM SaaS Log InSight agent section\n\n[filelog|vidm-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=*.log\nevent_marker=^\\d{4}-\\d{2}-\\d{2}\nparser=vidm-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"vidm\"}\n\n[parser|vidm-parser-onprem]\nbase_parser=clf\nformat=%t %{priority}i (%{thread}i) [%{authentication}i] %{java_class}i - %M\nfield_decoder={\"authentication\":\"vidm-authentication-decoder-onprem\",\"log_message\":\"vidm-message-decoder-onprem\"}\nexclude_fields=log_message\n; vIDM SaaS Log InSight agent section for *.txt file\n\n[filelog|vidm-txt-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=*.txt\nevent_marker=^\nparser=vidm-txt-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"vidm\"}\n\n[parser|vidm-txt-parser-onprem]\nbase_parser=clf\nformat=%h %l %u [%t] \"%{request}i\" %{status_code}i %b %{response_time}i\n\n[filelog|kdc-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=kdc*.log\ntags={\"product\":\"vidm-aws\",\"component\":\"kdc\"}\n\n[filelog|kdc-mtkadmin-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs\ninclude=mtkadmin.log\ntags={\"product\":\"vidm-aws\",\"component\":\"kdc\"}\n;cfn-init Log InSight agent section\n\n[filelog|cfn-init-onprem]\n; IMPORTANT: Change the directory as per the environment\ndirectory=/opt/vmware/horizon/workspace/logs/\ninclude=cfn.*.log\nevent_marker=^\nparser=cfn-init-parser-onprem\ntags={\"product\":\"vidm-aws\",\"component\":\"cfn-init\"}\n\n[parser|cfn-init-parser-onprem]\nbase_parser=clf\n\n[parser|vidm-authentication-decoder-onprem]\nbase_parser=csv\ndelimiter=\";\"\nfields=tenant, user_uuid, remote_host\n\n[parser|vidm-message-decoder-onprem]\nbase_parser=clf\nformat=%{status}i %{operation}i (%{referer}i)\nfield_decoder={\"referer\":\"vidm-referer-decoder-onprem\"}\n\n[parser|vidm-referer-decoder-onprem]\nbase_parser=csv\nfields=url, , mime_type, method, ,'
    }
    elseif ($agentGroupType -eq "photon") {
        $agentGroupConfig = '[journaldlog|journal_config]\njournal_files=all\ntags={\"generator\":\"journald\"}\n\n[filelog|audit]\ndirectory=/root/\ninclude=.bash_history\ntags={\"audit\":\"bash_history\"}'
    }

    if ($criteria.Count -ge "1") {
        $criteriaInput = ""
        $count = $criteria.Count
        $pollLoopCounter = 0
        foreach ($component in $criteria) {
            $pollLoopCounter ++
            if ($pollLoopCounter -ne $count) {
                $criteriaInput += '(hostname=~\"'+$component+'\") or '
            } else {
                $criteriaInput += '(hostname=~\"'+$component+'\")'
            }
        }
    } else {
        $criteriaInput = '"hostname=~\"'+$criteria+'\""'
    }

    Try {
        $uri = "https://$vrliAppliance/api/v1/agent/groups"
        $body = '{
            "name":"'
+ $agentGroupName + '",
            "criteria":"'
+ $criteriaInput + '",
            "agentConfig":"'
+ $agentGroupConfig + '"
        }'

        Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRLIAgentGroup

Function Remove-vRLIAgentGroup {
    <#
        .SYNOPSIS
        Remove an agent group.

        .DESCRIPTION
        The Remove-vRLIAgentGroup cmdlet deletes an agent group

        .EXAMPLE
        Remove-vRLIAgentGroup -groupName "Workspace ONE Access (IAM) - Appliance Agent Group"
        This example deletes an agent group.

        .PARAMETER groupName
        The name of the agent group to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$groupName
    )

    Try {
        $groupName = $groupName.replace(' ', '%20')
        $uri = "https://$vrliAppliance/api/v1/agent/groups/$groupName"
        Invoke-RestMethod -Method 'DELETE' -Uri $Uri -Headers $vrliHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLIAgentGroup

Function Get-vRLISmtpConfiguration {
    <#
        .SYNOPSIS
        Get SMTP server settings.

        .DESCRIPTION
        The Get-vRLISmtpConfiguration cmdlet gets the SMTP server configuration in VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLISmtpConfiguration
        This example gets the SMTP settings.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/notification/channels"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
        $response.channels.config
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLISmtpConfiguration

Function Set-vRLISmtpConfiguration {
    <#
        .SYNOPSIS
        Configure the SMTP server settings.

        .DESCRIPTION
        The Set-vRLISmtpConfiguration cmdlet configures the SMTP server settings in VMware Aria Operations for Logs

        .EXAMPLE
        Set-vRLISmtpConfiguration -smtpServer smtp.rainpole.io -port 25 -sender administrator@rainpole.io -username administrator@rainpole.io -password VMw@re1!
        This example sets the SMTP server settings.

        .PARAMETER smtpServer
        The SMTP server address.

        .PARAMETER port
        The SMTP server port.

        .PARAMETER sender
        The sender email address.

        .PARAMETER username
        The SMTP server username.

        .PARAMETER password
        The SMTP server password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$smtpServer,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$sender,
        [Parameter (Mandatory = $false)] [String]$username,
        [Parameter (Mandatory = $false)] [String]$password
    )

    Try {
        $uri = "https://$vrliAppliance/api/v1/notification/channels"
        $body = '{
            "channels": [{
                "type": "email",
                "config": {
                    "server": "'
+ $smtpServer + '",
                    "port": '
+ $port + ',
                    "sslAuth": false,
                    "tls": false,
                    "defaultSender": "'
+ $sender + '",
                    "login": "'
+ $username + '",
                    "password": "'
+ $password + '"
                }
            }]
        }'

        Invoke-RestMethod -Method 'PUT' -Uri $Uri -Headers $vrliHeaders -body $body | Out-Null
        Get-vRLISmtpConfiguration # API returns no output, calling Get-vRLISmtpConfiguration to display updated information
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLISmtpConfiguration

Function Get-vRLIRetentionThreshold {
    <#
        .SYNOPSIS
        Get the retention threshold configuration.

        .DESCRIPTION
        The Get-vRLIRetentionThreshold cmdlet gets the retention configuration in VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLIRetentionThreshold
        This example gets the retention configuration.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/notification/config/retention-threshold"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIRetentionThreshold

Function Set-vRLIRetentionThreshold {
    <#
        .SYNOPSIS
        Configuer the retention threshold settings.

        .DESCRIPTION
        The Set-vRLIRetentionThreshold cmdlet configures the retention settings in VMware Aria Operations for Logs

        .EXAMPLE
        Set-vRLIRetentionThreshold -enable true -interval 1 -intervalUnit weeks
        This example configures the retention configuration.

        .PARAMETER enable
        Enable or disable the retention configuration.

        .PARAMETER interval
        The interval for the retention configuration.

        .PARAMETER intervalUnit
        The interval unit for the retention configuration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [ValidateNotNullOrEmpty()] [String]$enable,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$interval,
        [Parameter (Mandatory = $true)] [ValidateSet("minutes", "hours", "days", "weeks", "months")] [ValidateNotNullOrEmpty()] [String]$intervalUnit
    )

    Try {
        $uri = "https://$vrliAppliance/api/v1/notification/config/retention-threshold"
        $body = '{
            "sendNotification" : '
+ $enable + ',
            "dataInterval" : '
+ $interval + ',
            "intervalUnit" : "'
+ $intervalUnit.ToUpper() + '"
        }'

        $response = Invoke-RestMethod -Method 'PUT' -Uri $Uri -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLIRetentionThreshold

Function Get-vRLIIndexPartition {
    <#
        .SYNOPSIS
        Get the index partitions.

        .DESCRIPTION
        The Get-vRLIIndexPartition cmdlet gets a list of index partitions in VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLIIndexPartition
        This example gets a list of index partitions.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/partitioning"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
        $response.partitions
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIIndexPartition

Function Set-vRLILogArchive {
    <#
        .SYNOPSIS
        Configuer the index partitions.

        .DESCRIPTION
        The Set-vRLILogArchive cmdlet configures the log archive location for a partition in VMware Aria Operations for Logs

        .EXAMPLE
        Set-vRLILogArchive -id d41d8cd9-8f00-3204-a980-0998ecf8427e -enable true -retentionPeriod 7 -archiveEnable true -archiveLocation nfs://172.27.11.4/sfo-m01-vrli01-400GB
        This example configures the retention configuration.

        .PARAMETER id
        The id of the partition to configure.

        .PARAMETER enable
        Enable or disable the partition.

        .PARAMETER retentionPeriodDays
        The retention period in days.

        .PARAMETER archiveEnable
        Enable or disable the archive.

        .PARAMETER archiveLocation
        The archive location.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [ValidateNotNullOrEmpty()] [String]$enable,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$retentionPeriodDays,
        [Parameter (Mandatory = $true)] [ValidateSet("true", "false")] [ValidateNotNullOrEmpty()] [String]$archiveEnable,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$archiveLocation
    )

    Try {
        $uri = "https://$vrliAppliance/api/v1/partitioning"
        $body = '{
            "id": "'
 + $id + '",
            "name": "",
            "enabled": '
+ $enable + ',
            "routingFilter": "",
            "retentionPeriodSeconds": '
+ $retentionPeriodDays * 86400 + ',
            "archiveEnabled": '
+ $archiveEnable + ',
            "archiveLocation": "'
+ $archiveLocation + '"
        }'

        $response = Invoke-RestMethod -Method 'PUT' -Uri $Uri -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLILogArchive

Function Get-vRLIEmailNotification {
    <#
        .SYNOPSIS
        Get list of email address for notifications.

        .DESCRIPTION
        The Get-vRLIEmailNotification cmdlet gets a list of the emails notifications will be sent to in VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLIEmailNotification
        This example gets a list of email notifications.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/notification/email"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIEmailNotification

Function Set-vRLIEmailNotification {
    <#
        .SYNOPSIS
        Configure email address for notifications.

        .DESCRIPTION
        The Set-vRLIEmailNotification cmdlet configures the emails addresses for notifications in VMware Aria Operations for Logs

        .EXAMPLE
        Set-vRLIEmailNotification -emailAddress "administrator@rainpole.io"
        This example adds a new email address to the notifications.

        .PARAMETER emailAddress
        The email address to add to the notifications.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$emailAddress
    )  

    Try {
        $uri = "https://$vrliAppliance/api/v1/notification/email"
        $body = '{
            "emails": ["'
+ $emailAddress + '"
                ]
        }'

        $response = Invoke-RestMethod -Method 'PUT' -Uri $Uri -Headers $vrliHeaders -body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLIEmailNotification

Function Get-vRLIRole {
    <#
        .SYNOPSIS
        Get list of roles.

        .DESCRIPTION
        The Get-vRLIRole cmdlet gets a list of roles in VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLIRole
        This example gets a list of roles in VMware Aria Operations for Logs.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/roles"
        $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders
        $response.roles
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIRole

Function Get-vRLIGroup {
    <#
        .SYNOPSIS
        Get list of groups by authentication provider.

        .DESCRIPTION
        The Get-vRLIGroup cmdlet gets a list of groups by authentication provider from VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLIGroup -authProvider vidm
        This example gets a list groups assigned using the Identity Manager authenitcation provider

        .EXAMPLE
        Get-vRLIGroup -authProvider ad
        This example gets a list groups assigned using the Active Directory authenitcation provider.

        .PARAMETER authProvider
        The authentication provider to use. Valid values are vidm or ad.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vidm", "ad")] [ValidateNotNullOrEmpty()] [String]$authProvider
    )

    Try {
        if ((Get-vRLIVersion).version.Split("-")[0] -lt 8.6.2) {
            $uri = "https://$vrliAppliance/api/v1/authgroups/$authProvider"
            (Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders).authProviderGroups
        } else {
            $uri = "https://$vrliAppliance/api/v2/user-groups/$authProvider"
            (Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders).userGroups
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIGroup

Function Add-vRLIGroup {
    <#
        .SYNOPSIS
        Add a group by authentication provider.

        .DESCRIPTION
        The Add-vRLIGroup cmdlet adds a group by authentication provider to VMware Aria Operations for Logs

        .EXAMPLE
        Add-vRLIGroup -authProvider vidm -domain sfo.rainpole.io -group gg-vrli-admins -role "Super Admin"
        This example adds a group assigned using the the vIDM authenitcation provider and assigns the Super Admin role.

        .PARAMETER authProvider
        The authentication provider to use. Valid values are vidm or ad.

        .PARAMETER domain
        The domain of the group to add.

        .PARAMETER group
        The group to add.

        .PARAMETER role
        The role to assign to the group. Valid values are Super Admin, User, Dashboard User, View Only Admin

        .EXAMPLE
        Add-vRLIGroup -authProvider ad -domain sfo.rainpole.io -group gg-vrli-admins -role "Super Admin"
        This example adds a group assigned using the the LDAP authenitcation provider and assigns the Super Admin role.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vidm", "ad")] [ValidateNotNullOrEmpty()] [String]$authProvider,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$group,
        [Parameter (Mandatory = $true)] [ValidateSet("Super Admin", "User", "Dashboard User", "View Only Admin")] [ValidateNotNullOrEmpty()] [String]$role
    )

    Try {
        if ((Get-vRLIVersion).version.Split("-")[0] -lt 8.6.2) {
            $uri = "https://$vrliAppliance/api/v1/authgroups"
            $json = '{ "provider": "' + $authProvider + '", "domain": "'+ $domain +'", "name": "'+ $group + "@" + $domain +'", "groupIds": [ "'+ ((Get-vRLIRole | Where-Object {$_.name -eq $role}).id) + '" ]}'
            Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vrliHeaders -Body $json
        } else {
            $uri = "https://$vrliAppliance/api/v2/user-groups"
            if ($authProvider -eq "ad") {
                $json = '{ "provider": "' + $authProvider + '", "domain": "'+ $domain +'", "name": "'+ $group+'", "roleIds": [ "'+ ((Get-vRLIRole | Where-Object {$_.name -eq $role}).id) + '" ]}'
            } elseif ($authProvider -eq "vidm") {
                $json = '{ "provider": "' + $authProvider + '", "domain": "'+ $domain +'", "name": "'+ $group + "@" + $domain +'", "roleIds": [ "'+ ((Get-vRLIRole | Where-Object {$_.name -eq $role}).id) + '" ]}'
            }
            Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vrliHeaders -Body $json
        }  
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Add-vRLIGroup

Function Remove-vRLIGroup {
    <#
        .SYNOPSIS
        Remove a group by authentication provider.

        .DESCRIPTION
        The Remove-vRLIGroup cmdlet removes a group by authentication provider from VMware Aria Operations for Logs

        .EXAMPLE
        Remove-vRLIGroup -authProvider vidm -domain sfo.rainpole.io -group gg-vrli-admins
        This example removes a group assigned using the the vIDM authenitcation provider.

        .PARAMETER authProvider
        The authentication provider to use. Valid values are vidm or ad.

        .PARAMETER domain
        The domain of the group to remove.

        .PARAMETER group
        The group to remove.

        .EXAMPLE
        Remove-vRLIGroup -authProvider ad -domain sfo.rainpole.io -group gg-vrli-admins
        This example removes a group assigned using the the vIDM authenitcation provider.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("vidm", "ad")] [ValidateNotNullOrEmpty()] [String]$authProvider,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$group
    )

    Try {
        if ((Get-vRLIVersion).version.Split("-")[0] -lt 8.6.2) {
            $uri = "https://$vrliAppliance/api/v1/authgroups/$authProvider/$domain/$group@$domain"
            Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vrliHeaders
        } else {
            $uri = "https://$vrliAppliance/api/v2/user-groups/$authProvider/$domain/$group@$domain"
            Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vrliHeaders
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLIGroup

Function Get-vRLIAlert {
    <#
        .SYNOPSIS
        Get list of alerts.

        .DESCRIPTION
        The Get-vRLIGroup cmdlet gets a list of alerts

        .EXAMPLE
        Get-vRLIGroup
        This example gets a list alerts from VMware Aria Operations for Logs.
    #>


    Try {
        if ((Get-vRLIVersion).version -Split ("-")[0] -gt 8.6.2) {
            $uri = "https://$vrliAppliance/api/v2/alerts"
        } else {
            $uri = "https://$vrliAppliance/api/v1/alerts"
        }
        Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIAlert

Function New-vRLIAlert {
    <#
        .SYNOPSIS
        Create an alert.

        .DESCRIPTION
        The New-vRLIAlert cmdlet creates an alert in VMware Aria Operations for Logs

        .EXAMPLE
        New-vRLIAlert -json (Get-Content -Raw .\vrliAlert.json)
        This example creates an alert in VMware Aria Operations for Logs based on the contents of the JSON.

        .PARAMETER json
        The JSON configuration of the alert to create.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$vrliAppliance/api/v1/alerts"
        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vrliHeaders -Body $json
        $response   
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function New-vRLIAlert

Function Remove-vRLIAlert {
    <#
        .SYNOPSIS
        Delete an alerts.

        .DESCRIPTION
        The Get-vRLIGroup cmdlet deletes an alerts

        .EXAMPLE
        Get-vRLIGroup -alertId <alert_id>
        This example deletes an alert from VMware Aria Operations for Logs.

        .PARAMETER alertId
        The ID of the alert to delete.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$alertId
    )

    Try {
        $uri = "https://$vrliAppliance/api/v1/alerts/$alertId"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vrliHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLIAlert

Function Set-vRLIAlert {
    <#
        .SYNOPSIS
        Enable/Disable an alert.

        .DESCRIPTION
        The Set-vRLIAlert cmdlet enables or disables an alert in VMware Aria Operations for Logs

        .EXAMPLE
        Set-vRLIAlert -id 0111952f-9aec-3872-b108-d70ec8a2981a -enabled true
        This example enables the alert in VMware Aria Operations for Logs based on id provided.

        .PARAMETER id
        The ID of the alert to enable/disable.

        .PARAMETER enabled
        Enable or disable the alert. Valid values are true or false.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$enabled
    )

    Try {
        $json = '{
            "ids":["'
+ $id + '"],
            "enabled":'
+ $enabled + '
        }'

        $uri = "https://$vrliAppliance/api/v2/alerts/batch-subscribe"
        Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vrliHeaders -Body $json 
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLIAlert

Function Update-vRLIAlert {
    <#
        .SYNOPSIS
        Update the configuration of an alert.

        .DESCRIPTION
        The Update-vRLIAlert cmdlet updates the configuration of an existing alert in VMware Aria Operations for Logs

        .EXAMPLE
        Update-vRLIAlert -id 0111952f-9aec-3872-b108-d70ec8a2981a -email administrator@rainpole.io
        This example adds a single email address to an alert in VMware Aria Operations for Logs.

        .PARAMETER id
        The ID of the alert to update.

        .PARAMETER email
        The email address to add to the alert.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$email
    )

    Try {
        $json = '{
            "recipients":
                {
                    "emails": [
                        "'
+ $email + '"
                    ],
                    "webhookIds":[

                    ],
                    "vrops":{"autoClearAlertAfterTimeout":false,
                    "autoClearAlertsTimeoutMinutes":15,
                    "vcopsCriticality":"none",
                    "vcopsResourceKindKey":"",
                    "vcopsResourceName":""
                }
            }
        }'

        $uri = "https://$vrliAppliance/api/v2/alerts/$id"
        Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vrliHeaders -Body $json 
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Update-vRLIAlert

Function Get-vRLILogForwarder {
    <#
        .SYNOPSIS
        Get list of log forwarders.

        .DESCRIPTION
        The Get-vRLILogForwarder cmdlet returns log forwarders from VMware Aria Operations for Logs.

        .EXAMPLE
        Get-vRLILogForwarder
        This example gets a list of log forwarders from VMware Aria Operations for Logs.

        .EXAMPLE
        Get-vRLILogForwarder -id "04f98100-995b-3f56-b321-0e10f21ee022"
        This example gets a log forwarder from VMware Aria Operations for Logs by ID.

        .PARAMETER id
        The ID of the log forwarder destination.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        if ($PsBoundParameters.ContainsKey('id')) {
            $uri = "https://$vrliAppliance/api/v2/log-forwarder/$id"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders
            $response
        } else {
            $uri = "https://$vrliAppliance/api/v2/log-forwarder"
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $vrliHeaders
            $response.forwarders
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLILogForwarder

Function Set-vRLILogForwarder {
    <#
        .SYNOPSIS
        Adds a log forwarder destination.

        .DESCRIPTION
        The Set-vRLILogForwarder cmdlet adds a log forwarder destination to VMware Aria Operations for Logs.

        .EXAMPLE
        Set-vRLILogForwarder -name "lax01-vrli01" -server "lax01-vrli01.lax.rainpole.io" -protocol SYSLOG -port 514 -transport TCP -acceptCert false -sslEnabled false -testConnection false
        This example adds a log forwarder to VMware Aria Operations for Logs using syslog over TCP 514.

        .EXAMPLE
        Set-vRLILogForwarder -name "lax01-vrli01" -server "lax01-vrli01.lax.rainpole.io" -protocol CFAPI -port 9543 acceptCert true -sslEnabled true -testConnection true
        This example adds a log forwarder to VMware Aria Operations for Logs using the Ingestion API and SSL enabled.

        .PARAMETER name
        The name of the log forwarder destination.

        .PARAMETER server
        The server name or IP address of the log forwarder destination.

        .PARAMETER protocol
        The protocol of the log forwarder destination. Valid values are CFAPI, SYSLOG, or RAW.

        .PARAMETER port
        The port number of the log forwarder destination.

        .PARAMETER transport
        The transport protocol of the log forwarder destination. Valid values are TCP or UDP.

        .PARAMETER acceptCert
        Accept the certificate of the log forwarder destination. Valid values are true or false.

        .PARAMETER sslEnabled
        Enable SSL for the log forwarder destination. Valid values are true or false.

        .PARAMETER testConnection
        Test the connection to the log forwarder destination. Valid values are true or false.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$name,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateSet("CFAPI", "SYSLOG", "RAW")] [String]$protocol,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $false)] [ValidateSet("TCP", "UDP")] [String]$transport,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$acceptCert,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$sslEnabled,
        [Parameter (Mandatory = $true)] [ValidateSet('true', 'false')] [String]$testConnection
    )

    Try {
        $uri = "https://$vrliAppliance/api/v2/log-forwarder"

        if ($protocol -eq 'SYSLOG' -and (-not $PsBoundParameters.ContainsKey('transport'))) {
            Throw 'You must enter a transport for SYSLOG.'
        } elseif ($protocol -eq 'SYSLOG' -and ($PsBoundParameters.ContainsKey('transport'))) {
            $body = '{
                "name": "'
 + $name + '",
                "host": "'
+ $server + '",
                "port": '
+ $port + ',
                "protocol": "'
+ $protocol.ToUpper() + '",
                "transport": "'
+ $transport.Tolower() + '",
                "acceptCert": '
+ $acceptCert.ToString().ToLower() + ',
                "sslEnabled": '
+ $sslEnabled.ToString().ToLower() + ',
                "testConnection": '
+ $testConnection.ToString().ToLower() + '
            }'

        } else {
            $body = '{
                "name": "'
 + $name + '",
                "host": "'
+ $server + '",
                "port": '
+ $port + ',
                "protocol": "'
+ $protocol.ToUpper() + '",
                "acceptCert": '
+ $acceptCert.ToString().ToLower() + ',
                "sslEnabled": '
+ $sslEnabled.ToString().ToLower() + ',
                "forwardComplementaryFields": true,
                "testConnection": '
+ $testConnection.ToString().ToLower() + '
            }'

        }
        Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Set-vRLILogForwarder

Function Remove-vRLILogForwarder {
    <#
        .SYNOPSIS
        Remove a log forwarder.

        .DESCRIPTION
        The Remove-vRLILogForwarder cmdlet removes a log forwarder destination from VMware Aria Operations for Logs.

        .EXAMPLE
        Remove-vRLILogForwarder
        This example removes a log forwarder destination from VMware Aria Operations for Logs.

        .EXAMPLE
        Remove-vRLILogForwarder -id "04f98100-995b-3f56-b321-0e10f21ee022"
        This example removes a log forwarder destination from VMware Aria Operations for Logs by ID.

        .PARAMETER id
        The ID of the log forwarder destination.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$id
    )

    Try {
        $uri = "https://$vrliAppliance/api/v2/log-forwarder/$id"
        $response = Invoke-RestMethod -Method 'DELETE' -Uri $uri -Headers $vrliHeaders
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLILogForwarder

Function Update-vRLILogForwarder {
    <#
        .SYNOPSIS
        Updates a log forwarder.

        .DESCRIPTION
        The Updates-vRLILogForwarder cmdlet updates a log forwarder destination from VMware Aria Operations for Logs.

        .EXAMPLE
        Updates-vRLILogForwarder
        This example updates a log forwarder destination from VMware Aria Operations for Logs.

        .EXAMPLE
        Updates-vRLILogForwarder -id "04f98100-995b-3f56-b321-0e10f21ee022" -json $json
        This example updates a log forwarder destination from VMware Aria Operations for Logs.

        .PARAMETER id
        The ID of the log forwarder destination.

        .PARAMETER json
        The JSON payload for the log forwarder destination.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json
    )

    Try {
        $uri = "https://$vrliAppliance/api/v2/log-forwarder/$id"
        Invoke-RestMethod -Method 'PATCH' -Uri $uri -Headers $vrliHeaders -Body $json
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Update-vRLILogForwarder

Function Test-vRLILogForwarder {
    <#
        .SYNOPSIS
        Test a log forwarder destination endpoint.

        .DESCRIPTION
        The Test-vRLILogForwarder cmdlet tests a log forwarder destination from VMware Aria Operations for Logs.

        .EXAMPLE
        Test-vRLILogForwarder -server "lax01-vrli01.lax.rainpole.io" -port 9000 -protocol CFAPI
        This example tests a log forwarder destination from VMware Aria Operations for Logs.

        .PARAMETER server
        The server name or IP address of the log forwarder destination.

        .PARAMETER port
        The port number of the log forwarder destination.

        .PARAMETER protocol
        The protocol of the log forwarder destination. Valid values are CFAPI, TCP, or UDP.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$port,
        [Parameter (Mandatory = $true)] [ValidateSet("CFAPI", "TCP", "UDP")] [String]$protocol
    )

    Try {
        $uri = "https://$vrliAppliance/api/v2/log-forwarder/testconnection"
        $body = '{ "host": "' + $server + '", "port": ' + $port + ', "protocol": "' + $protocol.ToLower() + '"}'
        Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $vrliHeaders -Body $body
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vRLILogForwarder

Function Get-vRLIMarketplaceMetadata {
    <#
        .SYNOPSIS
        Returns metadate for available items in the Content Pack Marketplace.

        .DESCRIPTION
        The Get-vRLIMarketplaceMetadata cmdlet returns the metadata for VMware Aria Operations for Logs content packs
        available in the Content Pack Marketplace hosted on GitHub (https://github.com/vmw-loginsight/).

        .EXAMPLE
        Get-vRLIMarketplaceMetadata -token <your_base64_encoded_github_token>
        This example returns the metadata for VMware Aria Operations for Logs content packs in the Content Pack MarketPlace.

        .PARAMETER token
        The base64 encoded GitHub token.

        .PARAMETER index
        Returns the index of available content packs in the Content Pack Marketplace.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$index,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$token
    )
    
    Try {
        # Get the headers with authorization to pull content pack from the GitHub repository
        createGitHubAuthHeader -token $token
        if ($PsBoundParameters.ContainsKey("index")) {
            # Get the content pack index from the GitHub repository
            $uri = 'https://api.github.com/repos/vmw-loginsight/vlcp/contents/index.json'
        } else {
            # Get the content pack metadata from the GitHub repository
            $uri = 'https://api.github.com/repos/vmw-loginsight/vlcp/contents/content/'
        }
        Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $ghHeaders
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Get-vRLIMarketplaceMetadata

Function Get-vRLIContentPack {
    <#
        .SYNOPSIS
        Get list of installed content packs.

        .DESCRIPTION
        The Get-vRLIContentPack cmdlet gets a list of all content packs installed on VMware Aria Operations for Logs

        .EXAMPLE
        Get-vRLIContentPack
        This example gets a list of all content packs.
    #>


    Try {
        $uri = "https://$vrliAppliance/api/v1/content/contentpack"
        $response = Invoke-RestMethod -Method 'GET' -Uri $Uri -Headers $vrliHeaders
        $response.contentPackMetadataList
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vRLIContentPack

Function Install-vRLIContentPack {
    <#
        .SYNOPSIS
        Installs a Content Pack to VMware Aria Operations for Logs.

        .DESCRIPTION
        The Install-vRLIContentPack cmdlet installed a content pack to VMware Aria Operations for Logs.

        .EXAMPLE
        Install-vRLIContentPack -json $json
        This example installs a content pack to VMware Aria Operations for Logs from a JSON payload.

        .EXAMPLE
        Insall-vRLIContentPack -update -json $json
        This example updates a content pack in VMware Aria Operations for Logs from a JSON payload.

        .PARAMETER update
        Overwrite an existing content pack.

        .PARAMETER json
        The JSON payload for the content pack.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$json,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$update
    )

    Try {
        if ($PsBoundParameters.ContainsKey("update")) {
            $uri = "https://$vrliAppliance/api/v1/content/contentpack?overwrite=true"
        } else {
            $uri = "https://$vrliappliance/api/v1/content/contentpack"
        }
        Invoke-RestMethod -Method 'POST' -Uri $Uri -ContentType 'application/octet-stream' -Headers $vrliHeaders -Body $json
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Install-vRLIContentPack

Function Remove-vRLIContentPack {
    <#
        .SYNOPSIS
        Remove a VMware Aria Operations for Log content pack

        .DESCRIPTION
        The Remove-vRLIContentPack cmdlet removes a content pack from VMware Aria Operations for Logs

        .EXAMPLE
        Remove-vRLIContentPack -namespace 'com.vmware.vidm'
        This example removes the Workspace ONE Access content pack

        .PARAMETER namespace
        The namespace of the content pack to remove.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$namespace
    )

    Try {
        $uri = "https://$vrliAppliance/api/v1/content/contentpack/$namespace"
        Invoke-RestMethod -Method 'DELETE' -Uri $Uri -Headers $vrliHeaders
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Remove-vRLIContentPack

#EndRegion End VMware Aria Operations for Logs Functions ######
###################################################################################

###################################################################################
#Region Start VMware Cloud Services Functions ######

Function Request-CSPToken {
    <#
        .SYNOPSIS
        Request authorization token from VMware Cloud Service.

        .DESCRIPTION
        The Request-CSPToken cmdlet connects to the VMware Cloud Service and obtains an authorization token.
        It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-CSPToken -environment production -apiToken <string>
        This example shows how to connect to the production VMware Cloud Service and obtain an authorization token.

        .EXAMPLE
        Request-CSPToken -environment staging -apiToken <string>
        This example shows how to connect to the staging VMware Cloud Service and obtain an authorization token.

        .EXAMPLE
        Request-CSPToken -environment staging -apiToken <string> -extensibilityProxy sfo-vmc-cep01.sfo.rainpole.io
        This example shows how to connect to the staging VMware Cloud Service and obtain an authorization token and set
        set the fqdn for the Cloud Extensibility Proxy for VMware Aria Automation Orchestrator configuration.

        .PARAMETER environment
        Connect to the production or staging VMware Cloud Service.

        .PARAMETER apiToken
        The API Token for the VMware Cloud Service.

        .PARAMETER extensibilityProxy
        The fqdn of the Cloud Extensibility Proxy for VMware Aria Automation Orchestrator configuration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("production", "staging")] [ValidateNotNullOrEmpty()] [String]$environment,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$apiToken,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$extensibilityProxy
    )

    Try {
        if ($environment -eq "staging") {
            $Global:cspBaseUrl = "https://console-stg.cloud.vmware.com"
        } elseif ($environment -eq "production") {
            $Global:cspBaseUrl = "https://console.cloud.vmware.com"
        }
        if ($PSBoundParameters.ContainsKey('extensibilityProxy')) {
            $Global:cepAppliance = $extensibilityProxy
        }
        
        $Global:basicHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $basicHeader.Add("Content-Type", "application/x-www-form-urlencoded")
        $path = "/csp/gateway/am/api/auth/api-tokens/authorize?refresh_token=$apiToken"
        $uri = $cspBaseUrl + $path

        if ($PSEdition -eq 'Core') {
            $cspResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $basicHeader -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $cspResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $basicHeader -UseBasicParsing
        }

        if ($cspResponse.StatusCode -eq 200) {
            $Global:cspHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
            $cspHeader.Add("Accept", "application/json")
            $cspHeader.Add("Content-Type", "application/json")
            $cspHeader.Add("Authorization", "Bearer " + ($cspResponse.Content | ConvertFrom-Json).access_token)
            Write-Output "Successfully connected to VMware Cloud Console: $cspBaseUrl"
        } else {
            Write-Error "Invalid API Token Failed to connect to VMware Cloud Console: $cspBaseUrl"
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Request-CSPToken

Function Get-CloudProxy {
    <#
        .SYNOPSIS
        Request Cloud Proxies from VMware Cloud Service.

        .DESCRIPTION
        The Get-CloudProxy cmdlet connects to the VMware Cloud Service and either downloads the OVA or
        supplies the OVA link.

        .EXAMPLE
        Get-CloudProxy -environment production -type 'Cloud Proxy' -download -path <string>
        This example shows how to download the Cloud Proxy OVA to the path provided.

        .EXAMPLE
        Get-CloudProxy -environment production -type 'Cloud Extensibility Proxy' -download -path <string>
        This example shows how to download the Cloud Extensibility Proxy OVA to the path provided.

        .EXAMPLE
        Get-CloudProxy -environment production -type 'Cloud Proxy' -ovaUrl
        This example shows how to obtain the URL to the Cloud Proxy OVA.

        .EXAMPLE
        Get-CloudProxy -environment production -region uk -type 'Cloud Proxy' -ovaUrl
        This example shows how to obtain the URL to the Cloud Proxy OVA for the United Kingdom region.

        .PARAMETER environment
        Connect to the production or staging VMware Cloud Service.

        .PARAMETER type
        The type of Cloud Proxy to request the One Time Key (OTK) for.

        .PARAMETER region
        The region to request the One Time Key (OTK) for. Only required for production environment.

        .PARAMETER download
        Download the OVA to the path provided.

        .PARAMETER path
        The path to download the OVA to.

        .PARAMETER ovaUrl
        Return the URL to the OVA.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("production", "staging")] [ValidateNotNullOrEmpty()] [String]$environment,
        [Parameter (Mandatory = $false)] [ValidateSet("au", "br", "ca", "de", "jp", "sg", "uk", "us")] [ValidateNotNullOrEmpty()] [String]$region,
        [Parameter (Mandatory = $true)] [ValidateSet("Cloud Proxy", "Cloud Extensibility Proxy")] [ValidateNotNullOrEmpty()] [String]$type,
        [Parameter (Mandatory = $false, ParameterSetName = 'download')] [ValidateNotNullOrEmpty()] [Switch]$download,
        [Parameter (Mandatory = $false, ParameterSetName = 'download')] [ValidateNotNullOrEmpty()] [String]$path,
        [Parameter (Mandatory = $false, ParameterSetName = 'ovaUrl')] [ValidateNotNullOrEmpty()] [Switch]$ovaUrl
    )

    Try {
        if ($environment -eq "staging") {
            $baseUrl = "https://api.staging.symphony-dev.com"
        } elseif ($environment -eq "production") {
            if ($PsBoundParameters.ContainsKey("region")) {
                if ($region -eq "us") {
                    $baseUrl = 'https://api.mgmt.cloud.vmware.com'
                } else {
                    $baseUrl = "https://$region.api.mgmt.cloud.vmware.com"
                }       
            } else {
                $baseUrl = "https://api.mgmt.cloud.vmware.com"
            }
        }

        if ($type -eq "Cloud Proxy") {
            $apiUrl = "/api/artifact-provider?artifact=data-collector"
            $uri = $baseUrl + $apiUrl
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $cspHeader
            $ovaName = ($response.providerUrl -Split (".com/"))[1]
        } elseif ($type -eq "Cloud Extensibility Proxy") {
            $apiUrl = "/api/artifact-provider?artifact=cexp-data-collector"
            $uri = $baseUrl + $apiUrl
            $response = Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $cspHeader
            $ovaName = ($response.providerUrl -Split (".com/staging/"))[1]
        }

        if ($PsBoundParameters.ContainsKey("download")) {
            if ($PsBoundParameters.ContainsKey("path")) {
                $downloadPath = $path + "\" + $ovaName
            } else {
                $downloadPath = $PSScriptRoot + "\" + $ovaName
            }
            if ($PSEdition -eq "Core" -and ($PSVersionTable.OS).Split(' ')[0] -eq "Linux" -or ($PSVersionTable.OS).Split(' ')[0] -eq "Darwin" ) {
                $downloadPath = ($downloadPath).split('\') -join '/' | Split-Path -NoQualifier
            }

            if (!(Test-Path $downloadPath)) {
                Write-Output "Started to Download the VMware Aria Automation Assembler Cloud Proxy OVA to '$downloadPath'"
                (New-Object System.Net.WebClient).DownloadFile($($response.providerUrl), $downloadPath)
                if (Test-Path $downloadPath) {
                    Write-Output "Downloading the VMware Aria Automation Assembler Cloud Proxy OVA to '$downloadPath': SUCCESSFUL"
                } else {
                    Write-Error "Downloading the VMware Aria Automation Assembler Cloud Proxy OVA to '$downloadPath': POST_VALIDATION_FAILED"
                }
            }
            else {
                Write-Warning "Downloading the VMware Aria Automation Assembler Cloud Proxy OVA to '$downloadPath', already downloaded: SKIPPED"
            }
        } elseif ($PsBoundParameters.ContainsKey("ovaUrl")) {
            $response.providerUrl
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-CloudProxy

Function Get-CloudProxyOtk {
    <#
        .SYNOPSIS
        Request One Time Key (OTK) for Cloud Proxies from VMware Cloud Service.

        .DESCRIPTION
        The Get-CloudProxyOtk cmdlet connects to the VMware Cloud Service and requests a One Time Key (OTK) which is
        used during the deployment of the OVA.

        .EXAMPLE
        Get-CloudProxyOtk -environment production -type 'Cloud Proxy'
        This example shows how to get the One Time Key (OTK) for the Cloud Proxy.

        .EXAMPLE
        Get-CloudProxyOtk -environment production -type 'Cloud Extensibility Proxy'
        This example shows how to get the One Time Key (OTK) for the Cloud Extensibility Proxy.

        .PARAMETER environment
        Connect to the production or staging VMware Cloud Service.

        .PARAMETER type
        The type of Cloud Proxy to request the One Time Key (OTK) for.

        .PARAMETER region
        The region to request the One Time Key (OTK) for. Only required for production environment.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet("production", "staging")] [ValidateNotNullOrEmpty()] [String]$environment,
        [Parameter (Mandatory = $true)] [ValidateSet("Cloud Proxy", "Cloud Extensibility Proxy")] [ValidateNotNullOrEmpty()] [String]$type,
        [Parameter (Mandatory = $false)] [ValidateSet("au", "br", "ca", "de", "jp", "sg", "uk", "us")] [ValidateNotNullOrEmpty()] [String]$region
    )

    Try {
        if ($environment -eq 'staging') {
            $baseUrl = 'https://api.staging.symphony-dev.com'
        } elseif ($environment -eq 'production') {
            if ($PsBoundParameters.ContainsKey('region')) {
                if ($region -eq 'us') {
                    $baseUrl = 'https://api.mgmt.cloud.vmware.com'
                } else {
                    $baseUrl = "https://$region.api.mgmt.cloud.vmware.com"
                }       
            } else {
                $baseUrl = 'https://api.mgmt.cloud.vmware.com'
            }
        }
        $apiUrl = "/api/otk-v3"
        $uri = $baseUrl + $apiUrl
        if ($type -eq "Cloud Proxy") {
            $body = '{"url":"' + $baseUrl + '","service":"cloud_assembly"}'
        } elseif ($type -eq "Cloud Extensibility Proxy") {
            $body = '{"url":"' + $baseUrl + '","service":"cloud_assembly_extensibility"}'
        }
        $response = Invoke-RestMethod -Method 'POST' -Uri $uri -Headers $cspHeader -Body $body
        $response
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-CloudProxyOtk

Function Get-vROVersion {
    <#
        .SYNOPSIS
        Retrieve the VMware Aria Automation Orchestrator version details
        
        .DESCRIPTION
        The Get-vROVersion cmdlet retrieves the VMware Aria Automation Orchestrator version information. It supports
        the following: (Requires an access token before a connection can be made)
        - Standalone VMware Aria Automation Orchestrator
        - Embedded VMware Aria Automation Orchestrator with VMware Aria Automation
        - Cloud Extensibility Proxy with VMware Aria Automation Orchestrator

        .EXAMPLE
        Get-vROVersion -standalone
        This examples retrieves the version details from a standlaone VMware Aria Automation Orchestrator appliance

        .EXAMPLE
        Get-vROVersion -embedded
        This examples retrieves the version details from an embedded VMware Aria Automation Orchestrator instance running within the VMware Aria Automation appliances.

        .EXAMPLE
        Get-vROVersion -extensibility
        This examples retrieves the version details from a VMware Aria Automation Orchestrator instance running within the Cloud Extensibility Proxy appliance.

        .PARAMETER standalone
        Connect to a standalone VMware Aria Automation Orchestrator appliance.

        .PARAMETER embedded
        Connect to an embedded VMware Aria Automation Orchestrator instance running within the VMware Aria Automation appliances.

        .PARAMETER extensibility
        Connect to a VMware Aria Automation Orchestrator instance running within the Cloud Extensibility Proxy appliance.
    #>


    [CmdletBinding(DefaultParametersetName = "embedded")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $false, ParameterSetName = "standalone")] [ValidateNotNullOrEmpty()] [Switch]$standalone,
        [Parameter (Mandatory = $false, ParameterSetName = "embedded")] [ValidateNotNullOrEmpty()] [Switch]$embedded,
        [Parameter (Mandatory = $false, ParameterSetName = "extensibility")] [ValidateNotNullOrEmpty()] [Switch]$extensibility
    )

    Try {
        Switch ($PsCmdlet.ParameterSetName) {
            "standalone" {
                $baseUrl = "https://$vroAppliance"
                Break
            }
            "embedded" {
                $baseUrl = "https://$vraAppliance"
                Break
            }
            "extensibility" {
                $baseUrl = "https://$cepAppliance"
                Break
            }
        }

        $path = "/vco/api/about"
        $uri = $baseUrl + $path
        Invoke-RestMethod -Method 'GET' -Uri $uri -Headers $cspHeader
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-vROVersion

Function Get-CEPWorkflow {
    <#
        .SYNOPSIS
        Get VMware Aria Automation Orchestrator workflows.

        .DESCRIPTION
        The Get-CEPWorkflow cmdlet returns details for VMware Aria Automation Orchestrator workflows

        .EXAMPLE
        Get-CEPWorkflow

        .EXAMPLE
        Get-CEPWorkflow -categoryName 'SSL Trust Manager'

        .EXAMPLE
        Get-CEPWorkflow -categoryId 3f23f186158a4869b464b7271fc216ba

        .EXAMPLE
        Get-CEPWorkflow -id '93a7bb21-0255-4750-9293-2437abe9d2e5'

        .EXAMPLE
        Get-CEPWorkflow -name 'Import a trusted certificate from a file'

        .EXAMPLE
        Get-CEPWorkflow -name 'Import a trusted certificate' -wildcard

        .NOTES
        Attribution: PowervRO by Jakku Labs (https://github.com/jakkulabs/PowervRO/).

        .PARAMETER categoryName
        The name of the category to filter by.

        .PARAMETER categoryId
        The ID of the category to filter by.

        .PARAMETER id
        The ID of the workflow to filter by.

        .PARAMETER name
        The name of the workflow to filter by.

        .PARAMETER wildcard
        Use wildcard search for the name of the workflow.

        .PARAMETER tag
        The tag to filter by.
    #>


    [CmdletBinding(DefaultParametersetName = "All")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $false, ParameterSetName = "categoryName")] [Alias("Category")] [String]$categoryName,
        [Parameter (Mandatory = $false, ParameterSetName = "categoryId")] [String]$categoryId,
        [Parameter (Mandatory = $false, ParameterSetName = "id")] [String]$id,
        [Parameter (Mandatory = $false, ParameterSetName = "name")] [String]$name,
        [Parameter (Mandatory = $false, ParameterSetName = "name")] [Switch]$wildcard,
        [Parameter (Mandatory = $false, ParameterSetName = "all")]
        [Parameter (Mandatory = $false, ParameterSetName = "categoryName")]
        [Parameter (Mandatory = $false, ParameterSetName = "category")] [String[]]$tag
    )

    Try {
        Switch ($PsCmdlet.ParameterSetName) {
            "all" {
                $uri = "https://$cepAppliance/vco/api/workflows"
                break
            }
            "categoryName" {
                $uri = "https://$cepAppliance/vco/api/workflows/?conditions=categoryName=$($categoryName)"
                break
            }
            "categoryId" {
                $uri = "https://$cepAppliance/vco/api/catalog/System/WorkflowCategory/$($categoryId)/workflows"
                break
            }
            "id" {
                $uri = "https://$cepAppliance/vco/api/workflows/$($id)"
                break
            }
            "name" {
                if ($PSBoundParameters.ContainsKey('wildcard')) {
                    $uri = "https://$cepAppliance/vco/api/workflows/?conditions=name~$($name)"
                } else {
                    $uri = "https://$cepAppliance/vco/api/workflows/?conditions=name=$($name)"
                }
                break
            }
        }
        # Filter by tag, if needed
        if ($PSBoundParameters.ContainsKey('tag')) {
            $uri += if ($PSCmdlet.ParameterSetName -eq 'all') { '?' } else { '&' }
            $newParams = @()
            foreach ($tagAttr in $tag) {
                $newParams += "tags=$($tagAttr)"
            }
            $uri += $newParams -join '&'
        }
        Switch ($PsCmdlet.ParameterSetName) {
            "id" {
                $workflow = Invoke-RestMethod -method 'GET' -uri $uri -Headers $cspHeader
                [pscustomobject]@{
                    Name         = $workflow.name
                    ID           = $workflow.id
                    Description  = $workflow.description
                    ItemHref     = $workflow.href
                    Version      = $workflow.version
                    CategoryName = $null
                    CategoryHref = $null
                    CustomIcon   = $workflow.'customized-icon'
                    CanExecute   = $null
                    CanEdit      = $null
                }
            }
            "categoryId" {
                $workflows = Invoke-RestMethod -method 'GET' -uri $uri -Headers $cspHeader
                foreach ($workflow in $workflows.link) {
                    $returnObject = @{
                        Name         = ($workflow.attributes | Where-Object { $_.name -eq 'name' }).value
                        ID           = ($workflow.attributes | Where-Object { $_.name -eq 'id' }).value
                        Description  = ($workflow.attributes | Where-Object { $_.name -eq 'description' }).value
                        ItemHref     = $workflow.href
                        Version      = ($workflow.attributes | Where-Object { $_.name -eq 'version' }).value
                        CategoryName = ($workflow.attributes | Where-Object { $_.name -eq 'categoryName' }).value
                        CategoryHref = ($workflow.attributes | Where-Object { $_.name -eq 'categoryHref' }).value
                        CustomIcon   = ($workflow.attributes | Where-Object { $_.name -eq 'customIcon' }).value
                        CanExecute   = ($workflow.attributes | Where-Object { $_.name -eq 'canExecute' }).value
                        CanEdit      = ($workflow.attributes | Where-Object { $_.name -eq 'canEdit' }).value
                    }
                    # Add tags if needed
                    $tags = $workflow.attributes | Where-Object { $_.name -eq 'globalTags' } | Select-Object -ExpandProperty 'value'
                    if ($tags) {
                        $tagsArray = ($tags -replace ':__SYSTEM_TAG__|.$', '').Split(' ')
                        $returnObject.Add('tags', $tagsArray)
                    }
                    [PSCustomObject]$returnObject
                }
            }
            Default {
                $workflows = Invoke-RestMethod -method 'GET' -uri $uri -Headers $cspHeader
                Foreach ($workflow in $workflows.link) {
                    $returnObject = @{
                        Name         = ($workflow.attributes | Where-Object { $_.name -eq 'name' }).value
                        ID           = ($workflow.attributes | Where-Object { $_.name -eq 'id' }).value
                        Description  = ($workflow.attributes | Where-Object { $_.name -eq 'description' }).value
                        ItemHref     = ($workflow.attributes | Where-Object { $_.name -eq 'itemHref' }).value
                        Version      = ($workflow.attributes | Where-Object { $_.name -eq 'version' }).value
                        CategoryName = ($workflow.attributes | Where-Object { $_.name -eq 'categoryName' }).value
                        CategoryHref = ($workflow.attributes | Where-Object { $_.name -eq 'categoryHref' }).value
                        CustomIcon   = ($workflow.attributes | Where-Object { $_.name -eq 'customIcon' }).value
                        CanExecute   = ($workflow.attributes | Where-Object { $_.name -eq 'canExecute' }).value
                        CanEdit      = ($workflow.attributes | Where-Object { $_.name -eq 'canEdit' }).value
                    }
                    # Add tags, if needed
                    $tags = $workflow.attributes | Where-Object { $_.name -eq 'globalTags' } | Select-Object -ExpandProperty 'value'
                    if ($tags) {
                        $tagsArray = ($tags -replace ':__SYSTEM_TAG__|.$', '').Split(' ')
                        $returnObject.Add('tags', $tagsArray)
                    }
                    [PSCustomObject]$returnObject
                }
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-CEPWorkflow

Function Invoke-CEPWorkflow {
    <#
        .SYNOPSIS
        Invoke a VMware Aria Automation Orchestrator workflow.

        .DESCRIPTION
        The Invoke-CEPWorkflow cmdlet starts a VMware Aria Automation Orchestrator workflow

        .EXAMPLE
        Invoke-CEPWorkflow -ID 3f23f186-158a-4869-b464-b7271fc216ba

        .EXAMPLE
        Invoke-CEPWorkflow -ID 3f23f186-158a-4869-b464-b7271fc216ba -parameterName 'text' -parameterValue 'foo' -parameterType 'string'

        .EXAMPLE
        $Parameters = @"
        {"parameters":
            [
                {
                    "value": {"string":{ "value": "bar"}},
                    "type": "string",
                    "name": "foo",
                    "scope": "local"
                },
                {
                    "value": {"number":{ "value": 2022}},
                    "type": "number",
                    "name": "year",
                    "scope": "local"
                }
            ]
        }
        "@

        Invoke-CEPWorkflow -id 3f23f186-158a-4869-b464-b7271fc216ba -parameters ($parameters | ConvertFrom-Json).parameters

        .EXAMPLE
        $param1 = New-vROParameterDefinition -name 'foo' -value 'bar' -type string -scope LOCAL
        Invoke-CEPWorkflow -id 3f23f186-158a-4869-b464-b7271fc216ba -parameters $param1

        .EXAMPLE
        Invoke-CEPWorkflow -name 'Import a trusted certificate from a file' | Invoke-CEPWorkflow -parameterName 'foo' -parameterValue 'bar' -parameterType string.

        .PARAMETER id
        The VMware Aria Automation Orchestrator workflow ID.

        .PARAMETER name
        The VMware Aria Automation Orchestrator workflow name.

        .PARAMETER parameterName
        The VMware Aria Automation Orchestrator workflow parameter name.

        .PARAMETER parameterValue
        The VMware Aria Automation Orchestrator workflow parameter value.

        .PARAMETER parameterType
        The VMware Aria Automation Orchestrator workflow parameter type.

        .PARAMETER parameters
        The VMware Aria Automation Orchestrator workflow parameters.
    #>


    [CmdletBinding(DefaultParametersetName = "A")][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = "A")]
        [Parameter (Mandatory = $true, ParameterSetName = "B")] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false, ParameterSetName = "A")] [Parameter (ParameterSetName = "C")] [ValidateNotNullOrEmpty()] [String]$parameterName,
        [Parameter (Mandatory = $false, ParameterSetName = "A")] [Parameter (ParameterSetName = "C")] [String]$parameterValue,
        [Parameter (Mandatory = $false, ParameterSetName = "A")] [Parameter (ParameterSetName = "C")] [ValidateNotNullOrEmpty()] [String]$parameterType,
        [Parameter (Mandatory = $false, ParameterSetName = "B")] [Parameter (ParameterSetName = "D")] [ValidateNotNullOrEmpty()] [PSCustomObject[]]$parameters
    )

    Begin {}
    Process {
        Try {
            if ($PSBoundParameters.ContainsKey('parameterType')) {
                $parameterType = $parameterType.ToLower()
                $body = @"
{"parameters":
    [
        {
            "value": {"$($parameterType)":{ "value": "$($parameterValue)"}},
            "type": "$($parameterType)",
            "name": "$($parameterName)",
            "scope": "local"
        }
    ]
}
"@

            } elseif ($PSBoundParameters.ContainsKey('parameters')) {
                $object = [PSCustomObject]@{
                    parameters = @()
                }
                foreach ($parameter in $parameters) {
                    $object.parameters += $parameter
                }
                $body = $object | ConvertTo-Json -Depth 100
            } else {
                $body = @"
{"parameters":
[
]
}
"@

            }
            $uri = "https://$cepAppliance/vco/api/workflows/$id/executions/"
            $response = Invoke-RestMethod -method 'POST' -uri $uri -body $body -Headers $cspHeader

            if ($PSEdition -eq 'Core') {
                [pscustomobject]@{
                    StatusCode        = $response.StatusCode
                    StatusDescription = $response.StatusDescription
                    Execution         = ([System.Uri]$response.Headers.Location[0]).LocalPath
                }
            } else {
                [pscustomobject]@{
                    StatusCode        = $response.StatusCode
                    StatusDescription = $response.StatusDescription
                    Execution         = ([System.Uri]$response.Headers.Location).LocalPath
                }
            }
        } Catch {
            Write-Error $_.Exception.Message
        }
    }
}
Export-ModuleMember -Function Invoke-CEPWorkflow

Function Get-CEPWorkflowExecution {
    <#
        .SYNOPSIS
        Retrieve VMware Aria Automation Orchestrator Workflow Status.

        .DESCRIPTION
        The Get-CEPWorkflowExecution cmdlet returns the execution status for a VMware Aria Automation Orchestrator workflow

        .EXAMPLE
        Get-CEPWorkflowExecution -id 93a7bb21-0255-4750-9293-2437abe9d2e5
        The example retrieves the status for all workflows based on workflow ID

        .EXAMPLE
        Get-CEPWorkflowExecution -name 'Import a trusted certificate from a file'
        The example retrieves the status for all workflows based on workflow name

        .EXAMPLE
        Get-CEPWorkflowExecution -name 'Import a trusted certificate from a file' -executionId 397a7b99-cdd0-427e-8fa1-2ff9cdd96fae.

        .PARAMETER id
        The VMware Aria Automation Orchestrator workflow ID.

        .PARAMETER name
        The VMware Aria Automation Orchestrator workflow name.
    #>


    [CmdletBinding(DefaultParametersetName = "A")][OutputType('System.Management.Automation.PSObject')]

    Param (   
        [Parameter (Mandatory = $false, ParameterSetName = "id")] [ValidateNotNullOrEmpty()] [String]$id,
        [Parameter (Mandatory = $false, ParameterSetName = "name")] [ValidateNotNullOrEmpty()] [String]$name
    )

    Try {
        if ($PSCmdlet.ParameterSetName -eq "name") {
            $id = (Get-CEPWorkflow -name $name).id
        }
        $uri = "https://$cepAppliance/vco/api/workflows/$id/executions"
        $response = Invoke-RESTMethod -Method 'GET' -Uri $uri -Headers $cspHeader
        $data = $response.relations.link | Where-Object { $_.attributes }
        Foreach ($execution in $data) {
            [PSCustomObject]@{                                
                Name      = ($execution.attributes | Where-Object { $_.name -eq 'name' }).value
                ID        = ($execution.attributes | Where-Object { $_.name -eq 'id' }).value
                Execution = "$uri/$(($execution.attributes | Where-Object {$_.name -eq 'id'}).value)/"
                State     = ($execution.attributes | Where-Object { $_.name -eq 'state' }).value
                StartedBy = ($execution.attributes | Where-Object { $_.name -eq 'startedBy' }).value
                StartDate = ($execution.attributes | Where-Object { $_.name -eq 'StartDate' }).value
                EndDate   = ($execution.attributes | Where-Object { $_.name -eq 'EndDate' }).value
            }
        }
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-CEPWorkflowExecution

Function Get-CEPWorkflowExecutionState {
    <#
        .SYNOPSIS
        Get a VMware Aria Automation Orchestrator Workflow execution state.

        .DESCRIPTION
        The Get-CEPWorkflowExecutionState cmdlet returns the status of VMware Aria Automation Orchestrator workflow
        execution runs.

        .EXAMPLE
        Get-CEPWorkflowExecutionState -workflowId 93a7bb21-0255-4750-9293-2437abe9d2e5 -executionId 0f37aa69-b95c-4c80-8b63-b8e5085aa3fd
        The examples returns the execution status of a workflow based on the Workflow ID and Execution ID.

        .PARAMETER workflowId
        The VMware Aria Automation Orchestrator workflow ID.

        .PARAMETER executionId
        The VMware Aria Automation Orchestrator workflow execution ID.
    #>


    Param (   
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$workflowId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$executionId
    )

    Try {
        $uri = "https://$cepAppliance/vco/api/workflows/$workflowId/executions/$executionId/state"   
        (Invoke-RestMethod -method 'GET' -uri $uri -Headers $cspHeader).value
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Get-CEPWorkflowExecutionState

Function Add-CEPTrustedCertificate {
    <#
        .SYNOPSIS
        Adds a trusted certificate to an embedded VMware Aria Automation Orchestrator.

        .DESCRIPTION
        The Add-vROTrustedCertificateOnCEP cmdlet invokes a workflow in VMware Aria Automation Orchestrator to add
        trusted certificate. The cmdlet connects to SDDC Manager using the -server, -user, and -password values
        and then:
        - Makes a connection to the embedded VMware Aria Automation Orchestrator using the -vraUser and -vraPass values.
        - Verifies the workflow exists.
        - Adds the trusted certificate using the -certFile value.

        .EXAMPLE
        Add-CEPTrustedCertificate -extensibilityProxy sfo-vmc-cep01.sfo.rainpole.io -environment staging -apiToken <string> -certFile "C:\Root64.pem"
        This example adds a trusted certificate in PEM-encoded format to the Cloud Extensibility Proxy VMware Aria Automation Orchestrator instance.

        .PARAMETER extensibilityProxy
        The Cloud Extensibility Proxy FQDN or IP address.

        .PARAMETER environment
        The VMware Cloud Services environment.

        .PARAMETER apiToken
        The VMware Cloud Services API token.

        .PARAMETER certFile
        The trusted certificate file in PEM-encoded format.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$extensibilityProxy,
        [Parameter (Mandatory = $true)] [ValidateSet("production", "staging")] [ValidateNotNullOrEmpty()] [String]$environment = "production",
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$apiToken,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$certFile
    )

    $workflowName = "Import a trusted certificate from a file"

    if (!$PsBoundParameters.ContainsKey("certFile")) {
        $certFile = Get-ExternalFileName -title "Select the trusted certificate file (.cer)" -fileType "cer" -location "default"
    } elseif ($PsBoundParameters.ContainsKey("certFile")) {
        if (!(Test-Path -Path $certFile)) {
            Write-Error  "Selecting the trusted certificate file ($certFile), file not found: PRE_VALIDATION_FAILED"
            Break
        }
    }

    Try {
        Request-CSPToken -environment $environment -apiToken $apiToken -extensibilityProxy $extensibilityProxy | Out-Null
        if ($workflow = Get-CEPWorkflow -name $workflowName) {
            $certName = Split-Path -Path "$certFile" -Leaf
            $certContent = [Convert]::ToBase64String([IO.File]::ReadAllBytes("$certFile"))
            $Global:parameters =  
            @"
{"parameters":
    [
        {"value": {
            "mime-attachment": {
                "name":"$certName",
                "content": "$certContent",
                "mime-type": "application/x-x509-ca-cert"}
            },
            "type": "MimeAttachment",
            "name": "cer",
            "scope": "local"
        }
    ]
}
"@

            Invoke-CEPWorkflow -id $($workflow.ID) -parameters ($parameters | ConvertFrom-Json).parameters | Out-Null
            $workflowExecution = (Get-CEPWorkflowExecution -name $workflowName | Select-Object -last 1)
            if (Get-CEPWorkflowExecutionState -workflowId $workflow.ID -executionId $workflowExecution.ID | Where-Object { $_.State -ne "failed" }) {
                Do {
                    $workflowStatus = Get-CEPWorkflowExecutionState -workflowId $workflow.ID -executionId $workflowExecution.ID
                } 
                Until ($workflowStatus.State -ne "running")
                if ((Get-CEPWorkflowExecutionState -workflowId $workflow.ID -executionId $workflowExecution.ID) -eq "completed") { 
                    Write-Output "Adding trusted certificate ($certFile) to the VMware Aria Automation Orchestrator ($($extensibilityProxy)): SUCCESSFUL"
                } else {
                    Write-Error "Adding trusted certificate ($certFile) to the VMware Aria Automation Orchestrator ($($extensibilityProxy)), check certificate format: POST_VALIDATION_FAILED"
                }
            } else {
                Write-Error "Adding trusted certificate ($certFile) to the VMware Aria Automation Orchestrator ($($extensibilityProxy)): FAILED"
            }
        } 
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-CEPTrustedCertificate

Function Add-CEPvCenterServer {
    <#
        .SYNOPSIS
        Adds a vCenter Server instance to an embedded VMware Aria Automation Orchestrator.

        .DESCRIPTION
        The Add-vROvCenterServer cmdlet invokes the workflow in VMware Aria Automation Orchestrator to add a vCenter
        Server. The cmdlet connects to SDDC Manager using the -server, -user, -password, and -domain values to return
        the workload domain vCenter Server details from its inventory and then:
        - Makes a connection to the Cloud Extensibility Proxy VMware Aria Automation Orchestrator instance using the -apiToken.
        - Verifies the workflow exists.
        - Adds the vCenter Server instance using the -serviceAccount and -servicePassword values.

        .EXAMPLE
        Add-CEPvCenterServer -server sfo-vcf01.sfo.rainpole.io -user administrator@vsphere.local -pass VMw@re1! -domain sfo-w01 -apiToken <string> -environment staging -extensibilityProxy sfo-vmc-cep01.sfo.rainpole.io -serviceAccount svc-vro-vsphere@sfo.rainpole.io -servicePassword VMw@re1!
        This example adds the vCenter Server instance from the "sfo-w01" workload domain to the Cloud Extensibility Proxy VMware Aria Automation Orchestrator instance.

        .PARAMETER server
        The vCenter Server FQDN or IP address.

        .PARAMETER user
        The vCenter Server user account.

        .PARAMETER pass
        The vCenter Server user account password.

        .PARAMETER domain
        The vCenter Server domain.

        .PARAMETER apiToken
        The VMware Cloud Services API token.

        .PARAMETER environment
        The VMware Cloud Services environment.

        .PARAMETER extensibilityProxy
        The Cloud Extensibility Proxy FQDN or IP address.

        .PARAMETER serviceAccount
        The vCenter Server service account.

        .PARAMETER servicePassword
        The vCenter Server service account password.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$domain,
        [Parameter (Mandatory = $true)] [ValidateSet("production", "staging")] [ValidateNotNullOrEmpty()] [String]$environment = "production",
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$apiToken,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$extensibilityProxy,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$serviceAccount,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$servicePassword
    )

    $workflowName = "Add a vCenter Server instance"

    Try {
        if (Test-VCFConnection -server $server) {
            if (Test-VCFAuthentication -server $server -user $user -pass $pass) {
                if (Get-VCFWorkloadDomain | Where-Object { $_.name -eq $domain }) {
                    $vcenter = Get-vCenterServerDetail -server $server -user $user -pass $pass -domain $domain          
                    Request-CSPToken -environment $environment -apiToken $apiToken -extensibilityProxy $extensibilityProxy | Out-Null
                    $checkExists = (Invoke-RestMethod -Method 'GET' -URI "https://$cepAppliance/vco/api/catalog/VC" -headers $cspHeader)
                    if ((($checkExists.relations.link.attributes | Where-Object { $_.name -eq "id" }).value) -ne "$($vcenter.fqdn)") {
                        if ($workflow = Get-CEPWorkflow -name $workflowName) {
                            $parameters =  
                            @"
{"parameters":
    [
        {
            "value": {
                "boolean": {
                    "value": true
                }
            },
            "type": "boolean",
            "name": "enabled",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "$($vcenter.fqdn)"
                }
            },
            "type": "string",
            "name": "host",
            "scope": "local"
        },
        {
            "value": {
                "number": {
                    "value": 443
                }
            },
            "type": "number",
            "name": "port",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "/sdk"
                }
            },
            "type": "string",
            "name": "path",
            "scope": "local"
        },
        {
            "value": {
                "boolean": {
                    "value": false
                }
            },
            "type": "boolean",
            "name": "sessionPerUser",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "$serviceAccount"
                }
            },
            "type": "string",
            "name": "userName",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "$servicePassword"
                }
            },
            "type": "string",
            "name": "password",
            "scope": "local"
        },
        {
            "value": {
                "boolean": {
                    "value": true
                }
            },
            "type": "boolean",
            "name": "ignoreCertificateWarnings",
            "scope": "local"
        },
        {
            "value": {
                "number": {
                    "value": 443
                }
            },
            "type": "number",
            "name": "httpPort",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "https://$($vcenter.fqdn):443/pbm"
                }
            },
            "type": "string",
            "name": "pbmUrl",
            "scope": "local"
        },
        {
            "value": {
                "string": {
                    "value": "https://$($vcenter.fqdn):443/sms/sdk"
                }
            },
            "type": "string",
            "name": "smsUrl",
            "scope": "local"
        }
    ]
}
"@

                            Invoke-CEPWorkflow -id $($workflow.ID) -parameters ($parameters | ConvertFrom-Json).parameters | Out-Null
                            $workflowExecution = (Get-CEPWorkflowExecution -name $workflowName | Select-Object -last 1)
                            if (Get-CEPWorkflowExecutionState -workflowId $workflow.ID -executionId $workflowExecution.ID | Where-Object { $_.State -ne "failed" }) { 
                                Do {
                                    $workflowStatus = Get-CEPWorkflowExecutionState -workflowId $workflow.ID -executionId $workflowExecution.ID
                                } 
                                Until ($workflowStatus -ne "running")
                                if ((Get-CEPWorkflowExecutionState -workflowId $workflow.ID -executionId $workflowExecution.ID) -eq "completed") { 
                                    Write-Output "Adding vCenter Server ($($vcenter.fqdn)) to VMware Aria Automation Orchestrator ($cepAppliance) for Workload Domain ($domain): SUCCESSFUL"
                                } else {
                                    Write-Error "Adding vCenter Server ($($vcenter.fqdn)) to VMware Aria Automation Orchestrator ($cepAppliance) for Workload Domain ($domain), check credentials: POST_VALIDATION_FAILED"
                                }
                            } else {
                                Write-Error "Adding vCenter Server ($($vcenter.fqdn)) to VMware Aria Automation Orchestrator ($cepAppliance) for Workload Domain ($domain): FAILED"
                            }
                        } else {
                            Write-Error "Unable to find the workflow named ($workflowName) to VMware Aria Automation Orchestrator ($cepAppliance): PRE_VALIDATION_FAILED"
                        }
                    } else {
                        Write-Warning "Adding vCenter Server ($($vcenter.fqdn)) to VMware Aria Automation Orchestrator ($cepAppliance) for Workload Domain ($domain), already exists: SKIPPED"
                    }                                
                } else {
                    Write-Error "Unable to find Workload Domain named ($domain) in the inventory of SDDC Manager ($server): PRE_VALIDATION_FAILED"
                }
            }
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-CEPvCenterServer

#EndRegion End VMware Cloud Services Functions ######
###################################################################################

###################################################################################
#Region Start of vSphere Replication Functions ######

Function Request-VrmsToken {
    <#
        .SYNOPSIS
        Connects to the specified vSphere Replication appliance and obtains an authorization token.

        .DESCRIPTION
        The Request-VrmsToken cmdlet connects to the specified vSphere Replication appliance and obtains an
        authorization token. It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-VrmsToken -fqdn sfo-m01-vrms01.sfo.rainpole.io -username admin -password VMw@re1!
        This example shows how to connect to a vSphere Replication appliance.

        .PARAMETER fqdn
        The fqdn parameter The fully qualified domain name of the vSphere Replication appliance.

        .PARAMETER username
        The username parameter The username to be used to connect to the vSphere Replication appliance.

        .PARAMETER password
        The password parameter The password to be used to connect to the vSphere Replication appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vrmsBasicHeader = @{"Accept" = "application/json, text/plain, */*" }
        $vrmsBasicHeader.Add("Authorization", "Basic $base64AuthInfo")
        $vrmsBasicHeader.Add("Content-Type", "application/json")
        $Global:vrmsAppliance = $fqdn

        $uri = "https://$vrmsAppliance/api/rest/configure/v1/session"
        if ($PSEdition -eq "Core") {
            $vrmsResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $vrmsBasicHeader -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vrmsResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $vrmsBasicHeader -UseBasicParsing
        }
        if ($vrmsResponse.StatusCode -eq 200) {
            $Global:vrmsHeader = @{"Accept" = "application/json" }
            $vrmsHeader.Add("Content-Type", "application/json")
            $vrmsHeader.Add("x-dr-session", "$(($vrmsResponse.Content | ConvertFrom-Json).session_id)")
            Write-Output "Successfully connected to the vSphere Replication Appliance: $vrmsAppliance"
        }
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Request-VrmsToken

Function Get-VrmsApplianceDetail {
    <#
        .SYNOPSIS
        Get information about the vSphere Replication appliance.

        .DESCRIPTION
        The Get-VrmsApplianceDetail cmdlet retrieves information about the vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsApplianceDetail
        This example retrieves information about the vSphere Replication appliance.
    #>


    Try {
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsApplianceDetail

Function Set-VrmsApplianceState {
    <#
        .SYNOPSIS
        Restart or shutdown the appliance.

        .DESCRIPTION
        The Set-VrmsApplianceState cmdlet allows you to restart or shutdown the vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsApplianceState -action restart
        This example restarts the vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsApplianceState -action stop
        This example shutsdown the vSphere Replication appliance.

        .PARAMETER action
        The action parameter The action to be performed on the vSphere Replication appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('restart', 'stop')] [String]$action
    )

    Try {
        if ($PsBoundParameters.ContainsKey('action') -eq 'restart') {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/actions/restart"
        } elseif ($PsBoundParameters.ContainsKey('action') -eq 'stop') {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/actions/stop"
        }
        Invoke-RestMethod -Method POST -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Set-VrmsApplianceState

Function Get-VrmsTask {
    <#
        .SYNOPSIS
        Get tasks.

        .DESCRIPTION
        The Get-VrmsTask cmdlet retrieves the tasks for a vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsTask
        This example retrieves all the tasks from the vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsTask -taskId <task_id>
        This example retrieves a specific task based on the task ID from the vSphere Replication appliance.

        .PARAMETER taskId
        The taskId parameter The task to be retrieved.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$taskId
    )

    Try {
        if ($PsBoundParameters.ContainsKey('taskId')) {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/tasks/$taskId"
        } else {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/tasks"
        }
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsTask

Function Get-VrmsService {
    <#
        .SYNOPSIS
        Get information about vSphere Replication appliance services.

        .DESCRIPTION
        The Get-VrmsService cmdlet retrieves information about the vSphere Replication appliance services.

        .EXAMPLE
        Get-VrmsService
        This example retrieves information about all services on the vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsService -serviceId hms
        This example retrieves information about hms service on the vSphere Replication appliance.

        .PARAMETER serviceId
        The serviceId parameter The service to be configured.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet('drclient', 'hbrsrv', 'hmsdb', 'hms', 'telegraf', 'iperf3', 'auditd', 'drrest', 'drclientplugin')] [String]$serviceId
    )

    Try {
        if ($PsBoundParameters.ContainsKey("serviceId")) {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/services/$serviceId"
            Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader

        } else {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/services"
            (Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader).list
        }
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsService

Function Set-VrmsService {
    <#
        .SYNOPSIS
        Get information about vSphere Replication appliance services.

        .DESCRIPTION
        The Set-VrmsService cmdlet retrieves information about the vSphere Replication appliance services.

        .EXAMPLE
        Set-VrmsService -serviceId hms -state stop
        This example stops the hms service on the vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsService -serviceId hms -state start
        This example starts the hms service on the vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsService -serviceId hms -state restart
        This example restarts the hms service on the vSphere Replication appliance.

        .PARAMETER serviceId
        The serviceId parameter The service to be configured.

        .PARAMETER state
        The state parameter The state of the service to be configured.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('drclient', 'hbrsrv', 'hmsdb', 'hms', 'telegraf', 'iperf3', 'auditd', 'drrest', 'drclientplugin')] [String]$serviceId,
        [Parameter (Mandatory = $true)] [ValidateSet('start', 'stop', 'restart')] [String]$state
    )

    Try {
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/services/$serviceId/actions/$state"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Set-VrmsService

Function Get-VrmsNetworkAll {
    <#
        .SYNOPSIS
        Get all network configuration.

        .DESCRIPTION
        The Get-VrmsNetworkAll cmdlet retrieves all the network configuration of a vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsNetworkAll
        This example retrieves all network configuration of the vSphere Replication appliance.
    #>


    Try {
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/settings/network"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsNetworkAll

Function Get-VrmsNetworkDns {
    <#
        .SYNOPSIS
        Get DNS configuration.

        .DESCRIPTION
        The Get-VrmsNetworkDns cmdlet retrieves DNS configuration of a vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsNetworkDns
        This example retrieves information about the DNS configuration of the vSphere Replication appliance.
    #>


    Try {
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/settings/network/dns"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsNetworkDns

Function Set-VrmsNetworkDns {
    <#
        .SYNOPSIS
        Set DNS configuration.

        .DESCRIPTION
        The Set-VrmsNetworkDns cmdlet change the DNS configuration of a vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsNetworkDns -vrmsHostname sfo-m01-vrms01.sfo.rainpole.io -dnsServers "172.18.95.4","172.18.95.5"
        This example retrieves information about the DNS configuration of the vSphere Replication appliance.

        .PARAMETER vrmsHostname
        The vrmsHostname parameter The hostname of the vSphere Replication appliance.

        .PARAMETER dnsServers
        The dnsServers parameter The DNS servers to be configured.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vrmsHostname,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$dnsServers
    )

    Try {
        $body = New-Object psobject -Property @{servers = $dnsServers }
        $body | Add-Member -notepropertyname 'hostname' -notepropertyvalue $vrmsHostname
        $body | Add-Member -notepropertyname 'mode' -notepropertyvalue 'STATIC'
        $body = $body | ConvertTo-Json
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/settings/network/dns"
        Invoke-RestMethod -Method PUT -Uri $uri -Headers $vrmsHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Set-VrmsNetworkDns

Function Get-VrmsNetworkInterface {
    <#
        .SYNOPSIS
        Get network interface configuration.

        .DESCRIPTION
        The Get-VrmsNetworkInterface cmdlet retrieves network interface configuration of a vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsNetworkInterface
        This example retrieves information about the network interface configuration of the vSphere Replication appliance.
    #>


    Try {
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/settings/network/interfaces"
        (Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader).list
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsNetworkInterface

Function Set-VrmsNetworkInterface {
    <#
        .SYNOPSIS
        Set network interface configuration.

        .DESCRIPTION
        The Set-VrmsNetworkInterface cmdlet configures the network interface of a vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsNetworkInterface -interface eth1 -ipAddress 172.18.111.125 -gateway 172.18.111.1 -prefix 24
        This example configures the network interface of the vSphere Replication appliance.

        .PARAMETER interface
        The interface parameter The network interface to be configured.

        .PARAMETER ipAddress
        The ipAddress parameter The IP address to be configured.

        .PARAMETER gateway
        The gateway parameter The gateway to be configured.

        .PARAMETER prefix
        The prefix parameter The prefix to be configured.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$interface,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ipAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$prefix
    )

    Try {
        $ipv4Object = New-Object -TypeName psobject
        $ipv4Object | Add-Member -notepropertyname 'address' -notepropertyvalue $ipAddress
        $ipv4Object | Add-Member -notepropertyname 'assignment_mode' -notepropertyvalue 'STATIC'
        $ipv4Object | Add-Member -notepropertyname 'default_gateway' -notepropertyvalue $gateway
        $ipv4Object | Add-Member -notepropertyname 'prefix' -notepropertyvalue $prefix
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'ipv4' -notepropertyvalue $ipv4Object
        $body = $body | ConvertTo-Json
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/settings/network/interfaces/$interface"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $vrmsHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Set-VrmsNetworkInterface

Function Get-VrmsConfiguration {
    <#
        .SYNOPSIS
        Get registration.

        .DESCRIPTION
        The Get-VrmsConfiguration cmdlet retrieves registration configuration for a vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsConfiguration
        This example retrieves the registration configuration for the vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsConfiguration -reconfigure
        This example retrieves the reconfiguration status for the vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsConfiguration -replication
        This example retrieves the storage replication configuration for the vSphere Replication appliance.

        .PARAMETER reconfigure
        The reconfigure parameter The reconfiguration status for the vSphere Replication appliance.

        .PARAMETER replication
        The replication parameter The storage replication configuration for the vSphere Replication appliance.
    #>

    
    [CmdletBinding(DefaultParametersetName = 'default')][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'reconfigure')] [ValidateNotNullOrEmpty()] [Switch]$reconfigure,
        [Parameter (Mandatory = $false, ParameterSetName = 'replication')] [ValidateNotNullOrEmpty()] [Switch]$replication
    )

    Try {
        if ($PsBoundParameters.ContainsKey('reconfigure')) {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/configuration-manager/reconfigure-required"
        } elseif ($PsBoundParameters.ContainsKey('replication')) {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/configuration-manager/replication-server-settings"
        } else {
            $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/configuration-manager/configuration"
        }
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsConfiguration

Function Set-VrmsConfiguration {
    <#
        .SYNOPSIS
        Set the vCenter Server registration.

        .DESCRIPTION
        The Set-VrmsConfiguration cmdlet configures the vCenter Server registration for a vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsConfiguration -vcenterFqdn sfo-m01-vc01.sfo.rainpole.io -vcenterInstanceId 6d6399d4-65ce-4e68-8009-ed8a4735b4a2 -ssoUser administrator@vsphere.local -ssoPassword VMw@re1! -adminEmail vrms-administrator@rainpole.io -siteName SFO-M01
        This example configures the vCenter Server registration with the vSphere Replication appliance.

        .PARAMETER vcenterFqdn
        The vcenterFqdn parameter The vCenter Server FQDN to be used to register the vSphere Replication appliance.

        .PARAMETER vcenterInstanceId
        The vcenterInstanceId parameter The vCenter Server instance ID to be used to register the vSphere Replication appliance.

        .PARAMETER ssoUser
        The ssoUser parameter The SSO user to be used to register the vSphere Replication appliance.

        .PARAMETER ssoPassword
        The ssoPassword parameter The SSO password to be used to register the vSphere Replication appliance.

        .PARAMETER adminEmail
        The adminEmail parameter The administrator email to be used to register the vSphere Replication appliance.

        .PARAMETER siteName
        The siteName parameter The site name to be used to register the vSphere Replication appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterInstanceId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adminEmail,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$siteName
    )

    Try {
        $command = 'openssl s_client -connect ' + $vcenterFQDN + ':443 2>&1 | openssl x509 -sha256 -fingerprint -noout'
        $thumbprint = (Invoke-Expression "& $command").Split("=")[1]

        $connectionObject = New-Object -TypeName psobject
        $connectionObject | Add-Member -notepropertyname 'psc_thumbprint' -notepropertyvalue $thumbprint
        $connectionObject | Add-Member -notepropertyname 'psc_uri' -notepropertyvalue ($vcenterFqdn + ":443")
        $connectionObject | Add-Member -notepropertyname 'vc_instance_id' -notepropertyvalue $vcenterInstanceId
        $connectionObject | Add-Member -notepropertyname 'vc_thumbprint' -notepropertyvalue $thumbprint

        $credentialsObject = New-Object -TypeName psobject
        $credentialsObject | Add-Member -notepropertyname 'admin_password' -notepropertyvalue $ssoPassword
        $credentialsObject | Add-Member -notepropertyname 'admin_user' -notepropertyvalue $ssoUser

        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'admin_email' -notepropertyvalue $adminEmail
        $body | Add-Member -notepropertyname 'extension_key' -notepropertyvalue "com.vmware.vcHms"
        $body | Add-Member -notepropertyname 'host_name' -notepropertyvalue $vrmsAppliance
        $body | Add-Member -notepropertyname 'site_name' -notepropertyvalue $siteName
        $body | Add-Member -notepropertyname 'connection' -notepropertyvalue $connectionObject
        $body | Add-Member -notepropertyname 'credentials' -notepropertyvalue $credentialsObject
        $body = $body | ConvertTo-Json

        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/configuration-manager/configuration"
        Invoke-RestMethod -Method PUT -Uri $uri -Headers $vrmsHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Set-VrmsConfiguration

Function Remove-VrmsConfiguration {
    <#
        .SYNOPSIS
        Remove the configuration.

        .DESCRIPTION
        The Remove-VrmsConfiguration cmdlet removes the vCenter Server registration for a vSphere Replication appliance.

        .EXAMPLE
        Remove-VrmsConfiguration -ssoUser administrator@vsphere.local -ssoPassword VMw@re1!
        This example removes the vCenter Server registration for the vSphere Replication appliance.

        .PARAMETER ssoUser
        The ssoUser parameter The SSO user to be used to remove the vCenter Server registration.

        .PARAMETER ssoPassword
        The ssoPassword parameter The SSO password to be used to remove the vCenter Server registration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoPassword
    )

    Try {
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'admin_password' -notepropertyvalue $ssoPassword
        $body | Add-Member -notepropertyname 'admin_user' -notepropertyvalue $ssoUser
        $body = $body | ConvertTo-Json
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/configuration-manager/configuration/actions/remove"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $vrmsHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Remove-VrmsConfiguration

Function Set-VrmsReplication {
    <#
        .SYNOPSIS
        Set the replication server settings.

        .DESCRIPTION
        The Set-VrmsReplication cmdlet configures the replication server settings for a vSphere Replication appliance.

        .EXAMPLE
        Set-VrmsReplication -filterIp 172.18.111.125 -managementIp 172.18.95.125
        This example configures the vCenter Server registration with the vSphere Replication appliance.

        .PARAMETER filterIp
        The filterIp parameter The IP address of the vSphere Replication appliance.

        .PARAMETER managementIp
        The managementIp parameter The IP address of the vSphere Replication appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$filterIp,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$managementIp
    )

    Try {
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'filter_ip' -notepropertyvalue $filterIp
        $body | Add-Member -notepropertyname 'management_ip' -notepropertyvalue $managementIp
        $body = $body | ConvertTo-Json
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/configuration-manager/replication-server-settings"
        Invoke-RestMethod -Method PUT -Uri $uri -Headers $vrmsHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Set-VrmsReplication

Function Get-VrmsVamiCertificate {
    <#
        .SYNOPSIS
        Get the certificate of the VAMI Appliance interface.

        .DESCRIPTION
        The Get-VrmsConfiguration cmdlet retrieves the certificate of the VAMI interface of a vSphere Replication appliance.

        .EXAMPLE
        Get-VrmsConfiguration
        This example retrieves the registration configuration for the vSphere Replication appliance.
    #>


    Try {
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/certificates/server"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeader
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Get-VrmsVamiCertificate

Function Set-VrmsVamiCertificate {
    <#
        .SYNOPSIS
        Install a Signed Certificate for the VAMI Appliance interface.

        .DESCRIPTION
        The Set-VrmsVamiCertificate cmdlet replaces the certificate on the VAMI interface of the vSphere
        Replication appliance.

        .EXAMPLE
        Set-VrmsVamiCertificate -pkcs12CertFile C:\Certs\sfo-m01-vrms01.4.p12 -certPassword VMw@re1!
        This example replaces the certificate on the VAMI Appliance interface of the vSphere Replication appliance.

        .PARAMETER pkcs12CertFile
        The pkcs12CertFile parameter The path to the certificate file (.p12) to be installed on the.

        .PARAMETER certPassword
        The certPassword parameter The password to use to install the certificate file (.p12) on the.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pkcs12CertFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certPassword
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("pkcs12CertFile")) {
            $pkcs12CertFile = Get-ExternalFileName -title "Select the Appliance Certificate File (.p12)" -fileType
        } elseif ($PsBoundParameters.ContainsKey("pkcs12CertFile")) {
            if (!(Test-Path -Path $pkcs12CertFile)) {
                Write-Error  "Certificate (.p12) '$pkcs12CertFile' File Not Found"
            }
        }

        $certContent = [Convert]::ToBase64String([IO.File]::ReadAllBytes($pkcs12CertFile))
        $pkcs12Object = New-Object -TypeName psobject
        $pkcs12Object | Add-Member -notepropertyname 'certificate' -notepropertyvalue $certContent
        $pkcs12Object | Add-Member -notepropertyname 'password' -notepropertyvalue $certPassword
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'pkcs12_format' -notepropertyvalue $pkcs12Object
        $body = $body | ConvertTo-Json
        $uri = "https://$vrmsAppliance/api/rest/configure/v1/appliance/certificates/server"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $vrmsHeader -Body $body
        Set-VrmsApplianceState -action restart | Out-Null
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Set-VrmsVamiCertificate

Function Request-VrmsTokenREST {
    <#
        .SYNOPSIS
        Connects to the specified vSphere Replication appliance and obtains an authorization token.

        .DESCRIPTION
        The Request-VrmsToken cmdlet connects to the specified vSphere Replication appliance and obtains an
        authorization token. It is required once per session before running all other cmdlets. This
        authorization is separate from the VAMI token acquired using Request-VrmsToken.

        .EXAMPLE
        Request-VrmsTokenREST -fqdn sfo-m01-vrms01.sfo.rainpole.io -username administrator@vsphere.local -password VMw@re1!
        This example shows how to connect to the vSphere Replication REST API using a vCenter Server SSO user.

        .PARAMETER fqdn
        The fully qualified domain name of the vSphere Replication REST API server

        .PARAMETER username
        The username to authenticate to the vSphere Replication REST API server

        .PARAMETER password
        The password to authenticate to the vSphere Replication REST API server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $vrmsBasicHeader = @{"Accept" = "application/json, text/plain, */*" }
        $vrmsBasicHeader.Add("Authorization", "Basic $base64AuthInfo")
        $vrmsBasicHeader.Add("Content-Type", "application/json")
        $Global:vrmsAppliance = $fqdn

        $uri = "https://$vrmsAppliance/api/rest/vr/v2/session"
        if ($PSEdition -eq "Core") {
            $vrmsResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $vrmsBasicHeader -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $vrmsResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $vrmsBasicHeader -UseBasicParsing
        }
        if ($vrmsResponse.StatusCode -eq 200) {
            $Global:vrmsHeaderREST = @{"Accept" = "application/json"}
            $vrmsHeaderREST.Add("Content-Type", "application/json")
            $vrmsHeaderREST.Add("x-dr-session", "$(($vrmsResponse.Content | ConvertFrom-Json).session_id)")
            Write-Output "Successfully connected to the vSphere Replication appliance: $vrmsAppliance"
        }
    } Catch {
        internalCatchWriter -applianceName "vSphere Replication Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Request-VrmsTokenREST

Function Get-VrmsSitePairing {
    <#
        .SYNOPSIS
        Retrieve site pairing information from a vSphere Replication instance.

        .DESCRIPTION
        The Get-VrmsSitePairing cmdlet retrieves site pairing information from a vSphere Replication.

        .EXAMPLE
        Get-VrmsSitePairing
        This example retrieves site pairings from the vSphere Replication instance.
    #>


    Try {
        $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings"
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeaderREST
        $return.list | Where-Object {$_.local_vc_server.name -ne $_.remote_vc_server.name}
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-VrmsSitePairing

Function Connect-VrmsRemoteSession {
    <#
        .SYNOPSIS
        Instantiates a connection with the remote vSphere Replication instance.

        .DESCRIPTION
        The Connect-VrmsRemoteSession cmdlet instantiates a connection with the remote vSphere Replication instance.

        .EXAMPLE
        Connect-VrmsRemoteSession -username administrator@vsphere.local -password VMw@re1!
        This example instantiates a connection with the remote vSphere Replication instance
        .PARAMETER username
        The username to authenticate to the remote vSphere Replication instance

        .PARAMETER password
        The password to authenticate to the remote vSphere Replication instance.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    Try {
        if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
            $creds = Get-Credential # Request Credentials
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        $vrmsSessionId = $vrmsHeaderREST.Get_Item("x-dr-session")
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $global:vrmsRemoteHeader = @{"Accept" = "application/json" }
        $vrmsRemoteHeader.Add("Authorization", "Basic $base64AuthInfo")
        $vrmsRemoteHeader.Add("Content-Type", "application/json")
        $vrmsRemoteHeader.Add("x-dr-session", "$vrmsSessionId")
        $pairing_id = (Get-VrmsSitePairing).pairing_id
        $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairing_id/remote-session"
        $return = Invoke-WebRequest -Method POST -Uri $uri -Headers $vrmsRemoteHeader
        if (($return.StatusCode -eq 200) -or ($return.StatusCode -eq 202) -or ($return.StatusCode -eq 204)) {
            Write-Output "Successfully connected to the vSphere Replication remote session."
        }
        } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Connect-VrmsRemoteSession

Function Get-VrmsVm {
    <#
        .SYNOPSIS
        Retrieves a list of all VMs from a vSphere Replication instance.

        .DESCRIPTION
        The Get-VrmsVm cmdlet retrieves a list of all VMs from a vSphere Replication instance.

        .EXAMPLE
        Get-VrmsVm
        This example retrieves a list of all VMs from the vSphere Replication instance.

        .PARAMETER vmName
        The name of the optional virtual machine to target.
    #>

    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmName
    )

    Try {
        $pairing_id = (Get-VrmsSitePairing).pairing_id
        $source_vc_id = (Get-VrmsSitePairing).local_vc_server.id
        $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairing_id/vcenters/$source_vc_id/vms"
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeaderREST
        if ($vmName) {
            $return.list | Where-Object {$_.name -eq $vmName} 
        }
        Else {
            $return.list
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-VrmsVm

Function Get-VrmsDatastore {
    <#
        .SYNOPSIS
        Retrieves a list of datastores from a vSphere Replication instance.

        .DESCRIPTION
        The Get-VrmsDatastore cmdlet retrieves a list of all datastores from a vSphere Replication instance.

        .EXAMPLE
        Get-VrmsDatastore -site recovery
        This example retrieves a list of all datastores from the recovery site via vSphere Replication instance.

        .PARAMETER site
        The site, either recovery or protected, to target.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('protected','recovery')] [String]$site
    )

    Try {
        $pairing_id = (Get-VrmsSitePairing).pairing_id
        if ($site -eq "protected") {
            $vcenter_id = (Get-VrmsSitePairing).local_vc_server.id
        }
        elseif ($site -eq "recovery") {
            $vcenter_id = (Get-VrmsSitePairing).remote_vc_server.id
        }
        $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairing_id/vcenters/$vcenter_id/datastores"
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeaderREST
        $return.list
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-VrmsDatastore

Function Get-VrmsReplication {
    <#
        .SYNOPSIS
        Retrieves a list of replications from a vSphere Replication instance.

        .DESCRIPTION
        The Get-VrmsReplications cmdlet retrieves a list of all replications from a vSphere Replication server via the REST API

        .EXAMPLE
        Get-VrmsReplications
        This example retrieves a list of all replications from the vSphere Replication server REST API

        .PARAMETER name
        The name of the replication to target.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmName
    )

    Try {
        $pairing_id = (Get-VrmsSitePairing).pairing_id
        if ($vmName) {
            $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairing_id/replications?filter_property=name&filter=$vmName"
        } else {
            $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairing_id/replications"
        }
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $vrmsHeaderREST
        $evaluateReturn = $return.list[0].id
        if ([string]::IsNullOrEmpty($evaluateReturn) -and ($vmName)) {
            Write-Output "vSphere Replication $vmName was not found"  
        } elseif ([string]::IsNullOrEmpty($evaluateReturn) -and (!$vmName)) {
            Write-Output "No vSphere Replications found"
        } else {
            $return.list
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-VrmsReplication

Function Add-VrmsReplication {
    <#
        .SYNOPSIS
        Adds a vSphere Replication for the specified virtual machine.

        .DESCRIPTION
        The Add-VrmsReplication cmdlet adds a vSphere Replication for the specified virtual machine.

        .EXAMPLE
        Add-VrmsReplication -vmName xint-vrslcm01 -recoveryPointObjective 1440
        This example adds a vSphere Replication for virtual machine xint-vrslcm01 to the vSphere Replication instance.

        .PARAMETER vmName
        The name of the virtual machine to target.

        .PARAMETER recoveryPointObjective
        The number of minutes, within a range of 5 to 1440 (one day), to define the RPO for the new replication.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateRange(5,1440)] [Int]$recoveryPointObjective
    )

    Try {
        $sitePair = Get-VrmsSitePairing
        $pairingId = $sitePair.pairing_id
        $vmToReplicate = Get-VrmsVm -vmName $vmName
        $existingDisks = $vmToReplicate.disks
        $destinationDatastore = Get-VrmsDatastore -site recovery
        $disks = @() 
        foreach ($existingDisk in $existingDisks) {
            $tempDisk = @{
                destination_datastore_id = $destinationDatastore.id
                destination_disk_format = "SAME_AS_SOURCE"
                enabled_for_replication = $true
                vm_disk = $existingDisk
            }
            $disks += $tempDisk
        }
        $vrmsBody = @{
            auto_replicate_new_disks = $true
            disks = $disks
            lwd_encryption_enabled = $false
            mpit_enabled = $false
            network_compression_enabled = $false
            rpo = $recoveryPointObjective
            target_vc_id = $sitePair.remote_vc_server.id
            vm_id = $vmToReplicate.id
        }
        $json = $vrmsBody | Convertto-JSON -depth 20
        $json = "[$json]"
        $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairingId/replications"
        $return = Invoke-RestMethod -Method POST -Uri $uri -Body $json -Headers $vrmsHeaderREST
        $return.list
    } catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Add-VrmsReplication

Function Remove-VrmsReplication {
    <#
        .SYNOPSIS
        Removes a vSphere Replication for the specified virtual machine.

        .DESCRIPTION
        The Remove-VrmsReplication cmdlet removes a vSphere Replication for the specified virtual machine.

        .EXAMPLE
        Remove-VrmsReplication -vmName xint-vrslcm01
        This example removes the replication for virtual machine xint-vrslcm01 from the vSphere Replication instance.

        .PARAMETER vmName
        The name of the virtual machine to target.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName
    )

    Try {
        $sitePair = Get-VrmsSitePairing
        $pairingId = $sitePair.pairing_id
        $vmReplicationId = (Get-VrmsReplications -vmName $vmName | Where-Object {$_.name -eq $vmName}).id
        $uri = "https://$vrmsAppliance/api/rest/vr/v2/pairings/$pairingId/replications/$vmReplicationId/actions/unconfigure?retain_replica_disks=false"
        $return = Invoke-RestMethod -Method POST -Uri $uri -Headers $vrmsHeaderREST
        $return
    } catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Remove-VrmsReplication

#EndRegion End of vSphere Replication Functions ######
###################################################################################

###################################################################################
#Region Start of Site Recovery Manager Functions ######

Function Request-SrmToken {
    <#
        .SYNOPSIS
        Connects to the specified Site Recovery Manager appliance and obtains an authorization token.

        .DESCRIPTION
        The Request-SrmToken cmdlet connects to the specified Site Recovery Manager and obtains an authorization
        token. It is required once per session before running all other cmdlets.

        .EXAMPLE
        Request-SrmToken -fqdn sfo-m01-srm01.sfo.rainpole.io -username admin -password VMw@re1!
        This example shows how to connect to a Site Recovery Manager appliance.

        .PARAMETER fqdn
        The fqdn parameter The fully qualified domain name of the Site Recovery Manager appliance.

        .PARAMETER username
        The username parameter The username to use to connect to the Site Recovery Manager appliance.

        .PARAMETER password
        The password parameter The password to use to connect to the Site Recovery Manager appliance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $srmBasicHeader = @{"Accept" = "application/json, text/plain, */*" }
        $srmBasicHeader.Add("Authorization", "Basic $base64AuthInfo")
        $srmBasicHeader.Add("Content-Type", "application/json")
        $Global:srmAppliance = $fqdn

        $uri = "https://$srmAppliance/api/rest/configure/v1/session"
        if ($PSEdition -eq 'Core') {
            $srmResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $srmBasicHeader -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $srmResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $srmBasicHeader -UseBasicParsing
        }
        if ($srmResponse.StatusCode -eq 200) {
            $Global:srmHeader = @{"Accept" = "application/json" }
            $srmHeader.Add("Content-Type", "application/json")
            $srmHeader.Add("x-dr-session", "$(($srmResponse.Content | ConvertFrom-Json).session_id)")
            Write-Output "Successfully connected to the Site Recovery Manager Appliance: $srmAppliance"
        }
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Request-SrmToken

Function Get-SrmApplianceDetail {
    <#
        .SYNOPSIS
        Get information about the Site Recovery Manager appliance.

        .DESCRIPTION
        The Get-SrmApplianceDetail cmdlet retrieves information about the Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmApplianceDetail
        This example retrieves information about the Site Recovery Manager appliance.
    #>


    Try {
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmApplianceDetail

Function Set-SrmApplianceState {
    <#
        .SYNOPSIS
        Restart or shutdown the appliance.

        .DESCRIPTION
        The Set-SrmApplianceState cmdlet allows you to restart or shutdown the Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmApplianceState -action restart
        This example restarts the Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmApplianceState -action stop
        This example shutsdown the Site Recovery Manager appliance.

        .PARAMETER action
        The action parameter The action to perform.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('restart', 'stop')] [String]$action
    )

    Try {
        if ($PsBoundParameters.ContainsKey('action') -eq 'restart') {
            $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/actions/restart"
        } elseif ($PsBoundParameters.ContainsKey('action') -eq 'stop') {
            $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/actions/stop"
        }
        Invoke-RestMethod -Method POST -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Set-SrmApplianceState

Function Get-SrmTask {
    <#
        .SYNOPSIS
        Get tasks.

        .DESCRIPTION
        The Get-SrmTask cmdlet retrieves the tasks for a Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmTask
        This example retrieves all the tasks from the Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmTask -taskId <task_id>
        This example retrieves a specific task based on the task ID from the Site Recovery Manager appliance.

        .PARAMETER taskId
        The taskId parameter The task to retrieve.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$taskId
    )

    Try {
        if ($PsBoundParameters.ContainsKey('taskId')) {
            $uri = "https://$srmAppliance/api/rest/configure/v1/tasks/$taskId"
        } else {
            $uri = "https://$srmAppliance/api/rest/configure/v1/tasks"
        }
        Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmTask

Function Get-SrmService {
    <#
        .SYNOPSIS
        Get information about Site Recovery Manager appliance services.

        .DESCRIPTION
        The Get-SrmService cmdlet retrieves information about the Site Recovery Manager appliance services.

        .EXAMPLE
        Get-SrmService
        This example retrieves information about all services on the Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmService -serviceId hms
        This example retrieves information about hms service on the Site Recovery Manager appliance.

        .PARAMETER serviceId
        The serviceId parameter The service to configure.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateSet('srm', 'db', 'drclient', 'telegraf', 'iperf3', 'auditd', 'drrest', 'drclientplugin')] [String]$serviceId
    )

    Try {
        if ($PsBoundParameters.ContainsKey("serviceId")) {
            $uri = "https://$srmAppliance/api/rest/configure/v1/services/$serviceId"
            Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
        } else {
            $uri = "https://$srmAppliance/api/rest/configure/v1/services"
            (Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader).list
        }
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmService

Function Set-SrmService {
    <#
        .SYNOPSIS
        Get information about Site Recovery Manager appliance services.

        .DESCRIPTION
        The Set-SrmService cmdlet retrieves information about the Site Recovery Manager appliance services.

        .EXAMPLE
        Set-SrmService -serviceId srm -state stop
        This example stops the hms service on the Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmService -serviceId srm -state start
        This example starts the hms service on the Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmService -serviceId srm -state restart
        This example restarts the hms service on the Site Recovery Manager appliance.

        .PARAMETER serviceId
        The serviceId parameter The service to configure.

        .PARAMETER state
        The state parameter The state of the service to configure.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateSet('srm', 'db', 'drclient', 'telegraf', 'iperf3', 'auditd', 'drrest', 'drclientplugin')] [String]$serviceId,
        [Parameter (Mandatory = $true)] [ValidateSet('start', 'stop', 'restart')] [String]$state
    )

    Try {
        $uri = "https://$srmAppliance/api/rest/configure/v1/services/$serviceId/actions/$state"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Set-SrmService

Function Get-SrmNetworkAll {
    <#
        .SYNOPSIS
        Get all network configuration.

        .DESCRIPTION
        The Get-SrmNetworkAll cmdlet retrieves all the network configuration of a Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmNetworkAll
        This example retrieves all network configuration of the Site Recovery Manager appliance.
    #>


    Try {
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/settings/network"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmNetworkAll

Function Get-SrmNetworkDns {
    <#
        .SYNOPSIS
        Get DNS configuration.

        .DESCRIPTION
        The Get-SrmNetworkDns cmdlet retrieves DNS configuration of a Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmNetworkDns
        This example retrieves information about the DNS configuration of the Site Recovery Manager appliance.
    #>


    Try {
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/settings/network/dns"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmNetworkDns

Function Set-SrmNetworkDns {
    <#
        .SYNOPSIS
        Set DNS configuration.

        .DESCRIPTION
        The Set-SrmNetworkDns cmdlet change the DNS configuration of a Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmNetworkDns -srmHostname sfo-m01-srm01.sfo.rainpole.io -dnsServers "172.18.95.4","172.18.95.5"
        This example retrieves information about the DNS configuration of the Site Recovery Manager appliance.

        .PARAMETER srmHostname
        The srmHostname parameter The hostname of the Site Recovery Manager appliance.

        .PARAMETER dnsServers
        The dnsServers parameter The DNS servers to configure.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$srmHostname,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$dnsServers
    )

    Try {
        $body = New-Object psobject -Property @{servers = $dnsServers }
        $body | Add-Member -notepropertyname 'hostname' -notepropertyvalue $srmHostname
        $body | Add-Member -notepropertyname 'mode' -notepropertyvalue 'STATIC'
        $body = $body | ConvertTo-Json
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/settings/network/dns"
        Invoke-RestMethod -Method PUT -Uri $uri -Headers $srmHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Set-SrmNetworkDns

Function Get-SrmNetworkInterface {
    <#
        .SYNOPSIS
        Get network interface configuration.

        .DESCRIPTION
        The Get-SrmNetworkInterface cmdlet retrieves network interface configuration of a Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmNetworkInterface
        This example retrieves information about the network interface configuration of the Site Recovery Manager appliance.
    #>


    Try {
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/settings/network/interfaces"
        (Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader).list
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmNetworkInterface

Function Set-SrmNetworkInterface {
    <#
        .SYNOPSIS
        Set network interface configuration.

        .DESCRIPTION
        The Set-SrmNetworkInterface cmdlet configures the network interface of a Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmNetworkInterface -interface eth0 -ipAddress 172.18.95.126 -gateway 172.18.95.1 -prefix 24
        This example configures the network interface of the Site Recovery Manager appliance.

        .PARAMETER interface
        The interface parameter The network interface to configure.

        .PARAMETER ipAddress
        The ipAddress parameter The IP address to configure.

        .PARAMETER gateway
        The gateway parameter The gateway to configure.

        .PARAMETER prefix
        The prefix parameter The prefix to configure.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$interface,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ipAddress,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$gateway,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$prefix
    )

    Try {
        $ipv4Object = New-Object -TypeName psobject
        $ipv4Object | Add-Member -notepropertyname 'address' -notepropertyvalue $ipAddress
        $ipv4Object | Add-Member -notepropertyname 'assignment_mode' -notepropertyvalue 'STATIC'
        $ipv4Object | Add-Member -notepropertyname 'default_gateway' -notepropertyvalue $gateway
        $ipv4Object | Add-Member -notepropertyname 'prefix' -notepropertyvalue $prefix
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'ipv4' -notepropertyvalue $ipv4Object
        $body = $body | ConvertTo-Json
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/settings/network/interfaces/$interface"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $srmHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Set-SrmNetworkInterface

Function Get-SrmConfiguration {
    <#
        .SYNOPSIS
        Get registration.

        .DESCRIPTION
        The Get-SrmConfiguration cmdlet retrieves registration configuration for a Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmConfiguration
        This example retrieves the registration configuration for the Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmConfiguration -reconfigure
        This example retrieves the reconfiguration status for the Site Recovery Manager appliance.

        .PARAMETER reconfigure
        The reconfigure parameter retrieves the reconfiguration status for the Site Recovery Manager appliance.
    #>

    
    [CmdletBinding(DefaultParametersetName = 'default')][OutputType('System.Management.Automation.PSObject')]

    Param (
        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'reconfigure')] [ValidateNotNullOrEmpty()] [Switch]$reconfigure
    )

    Try {
        if ($PsBoundParameters.ContainsKey('reconfigure')) {
            $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/configuration-manager/reconfigure-required"
        } else {
            $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/configuration-manager/configuration"
        }
        Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmConfiguration

Function Set-SrmConfiguration {
    <#
        .SYNOPSIS
        Set the vCenter Server registration.

        .DESCRIPTION
        The Set-SrmConfiguration cmdlet configures the vCenter Server registration for a Site Recovery Manager appliance.

        .EXAMPLE
        Set-SrmConfiguration -vcenterFqdn sfo-m01-vc01.sfo.rainpole.io -vcenterInstanceId 6d6399d4-65ce-4e68-8009-ed8a4735b4a2 -ssoUser administrator@vsphere.local -ssoPassword VMw@re1! -adminEmail srm-administrator@rainpole.io -siteName SFO-M01
        This example configures the vCenter Server registration with the vSphere Replication appliance.

        .PARAMETER vcenterFqdn
        The vCenter Server FQDN for the vCenter Server registration.

        .PARAMETER vcenterInstanceId
        The vCenter Server Instance ID for the vCenter Server registration.

        .PARAMETER ssoUser
        The SSO user for the vCenter Server registration.

        .PARAMETER ssoPassword
        The SSO password for the vCenter Server registration.

        .PARAMETER adminEmail
        The administrator email for the vCenter Server registration.

        .PARAMETER siteName
        The site name for the vCenter Server registration.
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterFqdn,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vcenterInstanceId,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoPassword,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$adminEmail,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$siteName
    )

    Try {
        $command = 'openssl s_client -connect ' + $vcenterFQDN + ':443 2>&1 | openssl x509 -sha256 -fingerprint -noout'
        $thumbprint = (Invoke-Expression "& $command").Split("=")[1]

        $connectionObject = New-Object -TypeName psobject
        $connectionObject | Add-Member -notepropertyname 'psc_thumbprint' -notepropertyvalue $thumbprint
        $connectionObject | Add-Member -notepropertyname 'psc_uri' -notepropertyvalue ($vcenterFqdn + ":443")
        $connectionObject | Add-Member -notepropertyname 'vc_instance_id' -notepropertyvalue $vcenterInstanceId
        $connectionObject | Add-Member -notepropertyname 'vc_thumbprint' -notepropertyvalue $thumbprint

        $credentialsObject = New-Object -TypeName psobject
        $credentialsObject | Add-Member -notepropertyname 'admin_password' -notepropertyvalue $ssoPassword
        $credentialsObject | Add-Member -notepropertyname 'admin_user' -notepropertyvalue $ssoUser

        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'admin_email' -notepropertyvalue $adminEmail
        $body | Add-Member -notepropertyname 'extension_key' -notepropertyvalue "com.vmware.vcDr"
        $body | Add-Member -notepropertyname 'host_name' -notepropertyvalue $srmAppliance
        $body | Add-Member -notepropertyname 'site_name' -notepropertyvalue $siteName
        $body | Add-Member -notepropertyname 'connection' -notepropertyvalue $connectionObject
        $body | Add-Member -notepropertyname 'credentials' -notepropertyvalue $credentialsObject
        $body = $body | ConvertTo-Json

        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/configuration-manager/configuration"
        Invoke-RestMethod -Method PUT -Uri $uri -Headers $srmHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Set-SrmConfiguration

Function Remove-SrmConfiguration {
    <#
        .SYNOPSIS
        Remove the configuration.

        .DESCRIPTION
        The Remove-SrmConfiguration cmdlet removes the vCenter Server registration for a vSphere Replication appliance.

        .EXAMPLE
        Remove-SrmConfiguration -ssoUser administrator@vsphere.local -ssoPassword VMw@re1!
        This example removes the vCenter Server registration for the vSphere Replication appliance.

        .PARAMETER ssoUser
        The SSO user for the vCenter Server registration.

        .PARAMETER ssoPassword
        The SSO password for the vCenter Server registration.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoUser,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ssoPassword
    )

    Try {
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'admin_password' -notepropertyvalue $ssoPassword
        $body | Add-Member -notepropertyname 'admin_user' -notepropertyvalue $ssoUser
        $body = $body | ConvertTo-Json
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/configuration-manager/configuration/actions/remove"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $srmHeader -Body $body
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $vrmsAppliance
    }
}
Export-ModuleMember -Function Remove-SrmConfiguration

Function Get-SrmVamiCertificate {
    <#
        .SYNOPSIS
        Get the certificate of the VAMI Appliance interface.

        .DESCRIPTION
        The Get-SrmVamiCertificate cmdlet retrieves the certificate of the VAMI interface of a Site Recovery Manager appliance.

        .EXAMPLE
        Get-SrmVamiCertificate
        This example retrieves the registration configuration for the Site Recovery Manager appliance.
    #>


    Try {
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/certificates/server"
        Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeader
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Get-SrmVamiCertificate

Function Set-SrmVamiCertificate {
    <#
        .SYNOPSIS
        Install a Signed Certificate for the VAMI Appliance interface.

        .DESCRIPTION
        The Set-SrmVamiCertificate cmdlet replaces the certificate on the VAMI interface of the Site Recovery
        Manager appliance.

        .EXAMPLE
        Set-SrmVamiCertificate -pkcs12CertFile C:\Certs\sfo-m01-srm01.4.p12 -certPassword VMw@re1!
        This example replaces the certificate on the VAMI Appliance interface of the Site Recovery Manager appliance.

        .PARAMETER pkcs12CertFile
        The path to the certificate file (.p12) to be installed on the VAMI Appliance interface.

        .PARAMETER certPassword
        The password for the certificate file (.p12) to be installed on the VAMI Appliance interface.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pkcs12CertFile,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$certPassword
    )

    Try {
        if (!$PsBoundParameters.ContainsKey("pkcs12CertFile")) {
            $pkcs12CertFile = Get-ExternalFileName -title "Select the Appliance Certificate File (.p12)" -fileType
        } elseif ($PsBoundParameters.ContainsKey("pkcs12CertFile")) {
            if (!(Test-Path -Path $pkcs12CertFile)) {
                Write-Error  "Certificate (.p12) '$pkcs12CertFile' File Not Found"
            }
        }

        $certContent = [Convert]::ToBase64String([IO.File]::ReadAllBytes($pkcs12CertFile))
        $pkcs12Object = New-Object -TypeName psobject
        $pkcs12Object | Add-Member -notepropertyname 'certificate' -notepropertyvalue $certContent
        $pkcs12Object | Add-Member -notepropertyname 'password' -notepropertyvalue $certPassword
        $body = New-Object -TypeName psobject
        $body | Add-Member -notepropertyname 'pkcs12_format' -notepropertyvalue $pkcs12Object
        $body = $body | ConvertTo-Json
        $uri = "https://$srmAppliance/api/rest/configure/v1/appliance/certificates/server"
        Invoke-RestMethod -Method POST -Uri $uri -Headers $srmHeader -Body $body
        Set-SrmApplianceState -action restart | Out-Null
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Set-SrmVamiCertificate

Function Request-SrmTokenREST {
    <#
        .SYNOPSIS
        Connects to the specified Site Recovery Manager appliance and obtains an authorization token.

        .DESCRIPTION
        The Request-SrmToken cmdlet connects to the specified Site Recovery Manager and obtains an authorization
        token. It is required once per session before running all other cmdlets. This
        authorization is separate from the VAMI token acquired using Request-SrmToken.

        .EXAMPLE
        Request-SrmTokenREST -fqdn sfo-m01-srm01.sfo.rainpole.io -username administrator@vsphere.local -password VMw@re1!
        This example shows how to connect to the Site Recovery Manager REST API using a vCenter Server SSO user.

        .PARAMETER fqdn
        The fully qualified domain name of the Site Recovery Manager REST API server.

        .PARAMETER username
        The username to authenticate to the Site Recovery Manager REST API server.

        .PARAMETER password
        The password to authenticate to the Site Recovery Manager REST API server.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$fqdn,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
        $creds = Get-Credential # Request Credentials
        $username = $creds.UserName.ToString()
        $password = $creds.GetNetworkCredential().password
    }

    Try {
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $srmBasicHeader = @{"Accept" = "application/json, text/plain, */*" }
        $srmBasicHeader.Add("Authorization", "Basic $base64AuthInfo")
        $srmBasicHeader.Add("Content-Type", "application/json")
        $Global:srmAppliance = $fqdn

        $uri = "https://$srmAppliance/api/rest/srm/v2/session"
        if ($PSEdition -eq 'Core') {
            $srmResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $srmBasicHeader -SkipCertificateCheck -UseBasicParsing # PS Core has -SkipCertificateCheck implemented, PowerShell 5.x does not
        } else {
            $srmResponse = Invoke-WebRequest -Method POST -Uri $uri -Headers $srmBasicHeader -UseBasicParsing
        }
        if ($srmResponse.StatusCode -eq 200) {
            $Global:srmHeaderREST = @{"Accept" = "application/json"}
            $srmHeaderREST.Add("Content-Type", "application/json")
            $srmHeaderREST.Add("x-dr-session", "$(($srmResponse.Content | ConvertFrom-Json).session_id)")
            Write-Output "Successfully connected to the Site Recovery Manager appliance: $srmAppliance"
        }
    } Catch {
        internalCatchWriter -applianceName "Site Recovery Manager Appliance" -applianceFqdn $srmAppliance
    }
}
Export-ModuleMember -Function Request-SrmTokenREST

Function Connect-SrmRemoteSession {
    <#
        .SYNOPSIS
        Instantiates a connection to the remote Site Recovery Manager instance.

        .DESCRIPTION
        The Connect-SrmRemoteSession cmdlet instantiates a connection to the remote Site Recovery Manager instance.

        .EXAMPLE
        Connect-SrmRemoteSession -username administrator@vsphere.local -password VMw@re1!
        This example instantiates a connection to the remote Site Recovery Manager instance.

        .PARAMETER username
        The username to authenticate to the remote Site Recovery Manager instance.

        .PARAMETER password
        The password to authenticate to the remote Site Recovery Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$username,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$password
    )

    Try {
        if ( -not $PsBoundParameters.ContainsKey("username") -or ( -not $PsBoundParameters.ContainsKey("password"))) {
            $creds = Get-Credential # Request Credentials
            $username = $creds.UserName.ToString()
            $password = $creds.GetNetworkCredential().password
        }
        $srmSessionId = $srmHeaderREST.Get_Item("x-dr-session")
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
        $global:srmRemoteHeader = @{"Accept" = "application/json" }
        $srmRemoteHeader.Add("Authorization", "Basic $base64AuthInfo")
        $srmRemoteHeader.Add("Content-Type", "application/json")
        $srmRemoteHeader.Add("x-dr-session", "$srmSessionId")
        $pairing_id = (Get-SrmSitePairing).pairing_id
        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairing_id/remote-session"
        $return = Invoke-WebRequest -Method POST -Uri $uri -Headers $srmRemoteHeader
        if (($return.StatusCode -eq 200) -or ($return.StatusCode -eq 202) -or ($return.StatusCode -eq 204)) {
            Write-Output "Successfully connected to the Site Recovery Manager remote session."
        }
        } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Connect-SrmRemoteSession

Function Get-SrmSitePairing {
    <#
        .SYNOPSIS
        Retrieve site pairing information from a Site Recovery Manager instance.

        .DESCRIPTION
        The Get-SrmSitePairing cmdlet retrieves site pairing information from a Site Recovery Manager.

        .EXAMPLE
        Get-SrmSitePairing
        This example retrieves site pairings from the Site Recovery Manager instance.
    #>


    Try {
        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings"
        $global:pairing = Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeaderREST
        $pairing.list | Where-Object {$_.local_vc_server.name -ne $_.remote_vc_server.name}
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-SrmSitePairing

Function Get-SrmProtectionGroup {
    <#
        .SYNOPSIS
        Retrieves either a named protection group or all protection groups from a Site Recovery Manager.

        .DESCRIPTION
        The Get-SrmProtectionGroup cmdlet retrieves either a named protection group or all protection groups from a
        Site Recovery Manager instance.

        .EXAMPLE
        Get-SrmProtectionGroup
        This example retrieves all protection groups from a Site Recovery Manager instance.

        .PARAMETER pgName
        The name of the protection group to retrieve from the Site Recovery Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$pgName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id     
        if ($pgName) {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/protection-management/groups?filter_property=name&filter=$pgName"
        } else {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/protection-management/groups"
        }
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeaderREST
        $return.list
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-SrmProtectionGroup

Function Add-SrmProtectionGroup {
    <#
        .SYNOPSIS
        Adds a protection group to a Site Recovery Manager instance.

        .DESCRIPTION
        The Add-SrmProtectionGroup cmdlet Retrieves either a named protection group or all protection groups from a
        Site Recovery Manager instance.

        .EXAMPLE
        Add-SrmProtectionGroup
        This example adds a ProtectionGroup to the Site Recovery Manager instance.

        .PARAMETER pgName
        The name of the protection group to add to the Site Recovery Manager instance.

        .PARAMETER vmName
        The name of the virtual machine(s) to add to the protection group. Must be presented as an array.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pgName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$vmName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $sourceVcId = $sitePair.local_vc_server.id
        $pairingId = $sitePair.pairing_id
        $vms = @()
        foreach ($vm in $vmName) {
            $vmId = (Get-VrmsVm -vmName $vm).id
            $vms += $vmId
        }
        $vmsJson = $vms | ConvertTo-Json
$pgBody = @"
{
    "hbr_spec": {
        "vms": $vmsJson
    },
    "name": "$pgName",
    "protected_vc_guid": "$sourceVcId",
    "replication_type": "HBR"
}
"@

        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/protection-management/groups"
        $return = Invoke-WebRequest -Method POST -Uri $uri -Body $pgBody -Headers $srmHeaderREST
        if ($return.StatusCode -eq 200 -or $return.StatusCode -eq 202) {
            Write-Output "Protection Group $pgName was successfully added."
        } else {
            Write-Error "Protection Group $pgName was not successfully added."
        }    
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Add-SrmProtectionGroup

Function Remove-SrmProtectionGroup {
    <#
        .SYNOPSIS
        Removes a protection group from a Site Recovery Manager instance.

        .DESCRIPTION
        The Remove-SrmProtectionGroup cmdlet removes a named protection group from a Site Recovery Manager instance.

        .EXAMPLE
        Remove-SrmProtectionGroup -pgName xint-vrops01
        This example removes the protection group xint-vrops01 from the Site Recovery Manager instance.

        .PARAMETER pgName
        The name of the protection group to remove from the Site Recovery Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pgName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $groupId = (Get-SrmProtectionGroup -pgName $pgName).id
        if ($groupId) {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/protection-management/groups/$groupId"
            $return = Invoke-WebRequest -Method DELETE -Uri $uri -Headers $srmHeaderREST
            if ($return.StatusCode -eq 200 -or $return.StatusCode -eq 202) {
                Write-Output "Protection Group $pgName was successfully removed"
            } else {
                Write-Output "Protection Group $pgName was not successfully removed"
            }
        } else{
            Write-Output "Protection Group $pgName was not found"
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Remove-SrmProtectionGroup

Function Get-SrmRecoveryPlan {
    <#
        .SYNOPSIS
        Retrieves either a named recovery plan or all recovery plans from a Site Recovery Manager.

        .DESCRIPTION
        The Get-SrmRecoveryPlan cmdlet retrieves either a named recovery plan or all recovery plans from a
        Site Recovery Manager instance.

        .EXAMPLE
        Get-SrmRecoveryPlan
        This example retrieves all recovery plans from a Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to retrieve from the Site Recovery Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$rpName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id     
        if ($rpName) {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans?filter_property=name&filter=$rpName"
        } else {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans"
        }
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeaderREST
        $return.list
    } Catch {
        # Do Nothing
    }
  }
Export-ModuleMember -Function Get-SrmRecoveryPlan

Function Add-SrmRecoveryPlan {
    <#
        .SYNOPSIS
        Adds a recovery plan to a Site Recovery Manager instance.

        .DESCRIPTION
        The Add-SrmRecoveryPlan cmdlet adds a recovery plan to a Site Recovery Manager instance.

        .EXAMPLE
        Add-SrmRecoveryPlan
        This example adds recovery plan xint-vrops01-rp to a Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to retrieve from the Site Recovery Manager instance.

        .PARAMETER pgName
        The name of the protection group(s) to add to the recovery plan. Must be presented as an array.
.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Array]$pgName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $sourceVcId = $sitePair.local_vc_server.id
        $pgs = @()
        foreach ($pg in $pgName) {
            $pgId = (Get-SrmProtectionGroup -pgName $pg).id
            if (!$pgId) {
                $PSCmdlet.ThrowTerminatingError(
                    [System.Management.Automation.ErrorRecord]::new(
                        ([System.Management.Automation.GetValueException]"Protection Group $pg not found: PRE_VALIDATION_FAILED"),
                        'Add-SrmRecoveryPlan',
                        [System.Management.Automation.ErrorCategory]::InvalidOperation,
                        ""
                    )
                )
            }
            $pgs += $pgId
        }
        $pgsJson = $pgs | ConvertTo-Json
        if ($pgName.Count -eq 1) {
            $pgsJson = "[$pgsJson]"
        }
$rpBody = @"
{
    "name": "$rpName",
    "protected_vc_guid": "$sourceVcId",
    "protection_groups": $pgsJson
}
"@

        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans"
        $return = Invoke-WebRequest -Method POST -Uri $uri -Body $rpBody -Headers $srmHeaderREST
        if ($return.StatusCode -eq 200 -or $return.StatusCode -eq 202) {
            Write-Output "Recovery Plan $rpName was successfully added."
        } else {
            Write-Error "Recovery Plan $rpName was not successfully added."
        }    
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Add-SrmRecoveryPlan

Function Remove-SrmRecoveryPlan {
    <#
        .SYNOPSIS
        Removes a named recovery plan from a Site Recovery Manager instance.

        .DESCRIPTION
        The Remove-SrmRecoveryPlan cmdlet removes a named recovery plan from a Site Recovery Manager instance using the
        REST API.

        .EXAMPLE
        Remove-SrmRecoveryPlan -rpName xint-vrops01-rp
        This example removes the recovery plan xint-vrops01-rp from the Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to remove from the Site Recovery Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $planId = (Get-SrmRecoveryPlan -rpName $rpName).id
        if ($planId) {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans/$planId"
            $return = Invoke-WebRequest -Method DELETE -Uri $uri -Headers $srmHeaderREST
            if ($return.StatusCode -eq 200 -or $return.StatusCode -eq 202) {
                Write-Output "Recovery Plan $rpName was successfully removed"
            } else {
                Write-Output "Recovery Plan $rpName was not successfully removed"
            }
        } else{
            Write-Output "Recovery Plan $rpName was not found"
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Remove-SrmRecoveryPlan

Function Get-SrmRecoveryPlanStep {
    <#
        .SYNOPSIS
        Retrieves steps in a named recovery plan from a Site Recovery Manager instance.

        .DESCRIPTION
        The Get-SrmRecoveryPlanStep cmdlet retrieves steps in a named recovery plan from a Site Recovery Manager
        server.

        .EXAMPLE
        Get-SrmRecoveryPlanStep -rpName xint-vrops01-rp.
        This example retrieves all recovery plans from a Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to retrieve steps from the Site Recovery Manager instance.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $planId = (Get-SrmRecoveryPlan -rpName $rpName).id
        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans/$planId/recovery-steps/recovery"
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeaderREST
        $return.list
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-SrmRecoveryPlanStep
  
Function Add-SrmRecoveryPlanCalloutStep {
    <#
        .SYNOPSIS
        Adds a callout step in a named recovery plan from a Site Recovery Manager instance.

        .DESCRIPTION
        The Add-SrmRecoveryPlanCalloutStep cmdlet adds steps in a named recovery plan from a Site Recovery Manager
        server.

        .EXAMPLE
        Add-SrmRecoveryPlanCalloutStep -rpName xint-vrops01-rp -calloutType PROMPT -calloutName "Power on the VMware Aria Operations cloud proxies" -content "Power on the VMware Aria Operations cloud proxies" -position 15 -timeoutSeconds 30
        This example retrieves all recovery plans from a Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to modify.

        .PARAMETER calloutType
        The type of callout to add (prompt, runOnVM, runOnSRMServer).

        .PARAMETER calloutName
        The name of the callout.

        .PARAMETER content
        The message to be displayed in the callout.

        .PARAMETER position
        The position in the current recovery steps list.

        .PARAMETER timeoutSeconds
        Time in seconds to wait until the command completes. Only applicable when the parameter calloutType is set to runOnVM or runOnSRMServer.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName,
        [Parameter (Mandatory = $true)] [ValidateSet("PROMPT","RUN_ON_VM","RUN_ON_SRM_SERVER")] [String]$calloutType,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$calloutName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$content,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [Int]$position,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Int]$timeoutSeconds
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $planId = (Get-SrmRecoveryPlan -rpName $rpName).id
        if ($timeoutSeconds) {
$body = @"
{
    "callout_type": "$calloutType",
    "content": "$content",
    "name": "$calloutName",
    "position": $position,
    "timeout_seconds": $timeoutSeconds
}
"@

        } else {
$body = @"
{
"callout_type": "$calloutType",
"content": "$content",
"name": "$calloutName",
"position": $position
}
"@

        }
        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans/$planId/recovery-steps/recovery"
        $return = Invoke-WebRequest -Method POST -Uri $uri -Body $body -Headers $srmHeaderREST
        if ($return.StatusCode -eq 200 -or $return.StatusCode -eq 202) {
            Write-Output "Recovery Plan step $calloutName was successfully added"
        } else {
            Write-Output "Recovery Plan step $calloutName was not successfully added"
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Add-SrmRecoveryPlanCalloutStep
  
Function Get-SrmRecoveryPlanVm {
    <#
        .SYNOPSIS
        Change the startup priority for virtual machines in a named recovery plan from a Site Recovery Manager instance.

        .DESCRIPTION
        The Get-SrmRecoveryPlanVm cmdlet changes the startup priority for virtual machines in a named Recovery
        Plan from a Site Recovery Manager instance.

        .EXAMPLE
        Get-SrmRecoveryPlanVm -rpName xint-vrops01-rp -vmName xint-vrops01a
        This example sets virtual machine xint-vrops01a in recovery plan xint-vrops01-rp to startup priority 3 from a Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to modify.

        .PARAMETER vmName
        Name of virtual machine(s) to target.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$vmName
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $planId = (Get-SrmRecoveryPlan -rpName $rpName).id
        if ($vmName) {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans/$planId/vms?filter_property=name&filter=$vmName"
        } else {
            $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans/$planId/vms"
        }
        $return = Invoke-RestMethod -Method GET -Uri $uri -Headers $srmHeaderREST
        $evaluateReturn = $return.list[0].id
        if ([string]::IsNullOrEmpty($evaluateReturn) -and ($vmName)) {
            Write-Output "Virtual machine $vmName was not found in recovery plan $rpName"  
        } elseif ([string]::IsNullOrEmpty($evaluateReturn) -and (!$vmName)) {
            Write-Output "No virtual machines found in recovery plan $rpName"
        } else {
            $return.list
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Get-SrmRecoveryPlanVm

Function Set-SrmRecoveryPlanVMPriority {
    <#
        .SYNOPSIS
        Change the startup priority for virtual machines in a named recovery plan from a Site Recovery Manager instance.

        .DESCRIPTION
        The Set-SrmRecoveryPlanVMPriority cmdlet changes the startup priority for virtual machines in a named Recovery
        Plan from a Site Recovery Manager instance.

        .EXAMPLE
        Set-SrmRecoveryPlanVMPriority -rpName xint-vrops01-rp -vmName xint-vrops01a -priority P3
        This example sets virtual machine xint-vrops01a in recovery plan xint-vrops01-rp to startup priority 3 from a Site Recovery Manager instance.

        .PARAMETER rpName
        The name of the recovery plan to modify.

        .PARAMETER vmName
        Name of virtual machine(s) to target.

        .PARAMETER priority
        The priority (1-5) level to set the virtual machine.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$rpName,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$vmName,
        [Parameter (Mandatory = $true)] [ValidateSet("P1","P2","P3","P4","P5")] [String]$priority
    )

    Try {
        $sitePair = Get-SrmSitePairing
        $pairingId = $sitePair.pairing_id
        $planId = (Get-SrmRecoveryPlan -rpName $rpName).id
        $vmId = (Get-SrmRecoveryPlanVm -rpName $rpName -vmName $vmName).id
$body = @"
{
    "priority": "$priority"
}
"@

        $uri = "https://$srmAppliance/api/rest/srm/v2/pairings/$pairingId/recovery-management/plans/$planId/vms/$vmId/recovery-settings/priority"
        $return = Invoke-WebRequest -Method PUT -Uri $uri -Body $body -Headers $srmHeaderREST
        if ($return.StatusCode -eq 200 -or $return.StatusCode -eq 202) {
            Write-Output "Virtual machine restart priority ($priority) was successfully set on virtual machine $vmName"
        } else {
            Write-Output "Virtual machine restart priority ($priority) was not successfully set on virtual machine $vmName"
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Set-SrmRecoveryPlanVMPriority

#EndRegion End of Site Recovery Manager Functions ######
###################################################################################

###################################################################################
#Region Start Utility Functions ######

Function Show-PowerValidatedSolutionsOutput {
    Param (
        [Parameter (Mandatory = $true)] [AllowEmptyString()] [String]$message,
        [Parameter (Mandatory = $false)] [ValidateSet("INFO", "ERROR", "WARNING", "EXCEPTION", "ADVISORY", "NOTE", "QUESTION", "WAIT")] [String]$type = "INFO",
        [Parameter (Mandatory = $false)] [Switch]$skipnewline
    )

    If ($type -eq "INFO") {
        $messageColour = "92m" #Green
    } elseIf ($type -in "ERROR", "EXCEPTION") {
        $messageColour = "91m" # Red
    } elseIf ($type -in "WARNING", "ADVISORY", "QUESTION") {
        $messageColour = "93m" #Yellow
    } elseIf ($type -in "NOTE", "WAIT") {
        $messageColour = "97m" # White
    }

    $ESC = [char]0x1b
    $timestampColour = "97m"

    $timeStamp = Get-Date -Format "MM-dd-yyyy_HH:mm:ss"

    If ($skipnewline) {
        Write-Host -NoNewline "$ESC[${timestampcolour} [$timestamp]$ESC[${threadColour} $ESC[${messageColour} [$type] $message$ESC[0m"
    } else {
        Write-Host "$ESC[${timestampcolour} [$timestamp]$ESC[${threadColour} $ESC[${messageColour} [$type] $message$ESC[0m"
    }
}
Export-ModuleMember -Function Show-PowerValidatedSolutionsOutput

Function internalCatchWriter ($applianceName, $applianceFqdn) {
    if ($_.Exception.Message -match "400") {
        Write-Error "400 (Bad Request: ($_.Exception.ErrorLabel)"
    } elseif ($_.Exception.Message -match "401") {
        Write-Error "401 (Unauthorized: Not Connected to $($applianceName): $($applianceFqdn))"
    } elseif ($_.Exception.Message -match "403") {
        Write-Error "403 (Forbidden on $($applianceName): $($applianceFqdn))"
    } elseif ($_.Exception.Message -match "404") {
        Write-Error "404 (Resouce Not Found on $($applianceName): $($applianceFqdn))"
    } elseif ($_.Exception.Message -match "409") {
        Write-Error "409 (Conflict: $_.Exception.ErrorLabel"
    } elseif ($_.Exception.Message -match "500") {
        Write-Error "500 (Internal Server Error: $_.Exception.ErrorLabel"
    } elseif ($_.Exception.Message -match "Cannot bind parameter 'Uri'") {
        Write-Error "Missing Access Token (Request an access token for the $($applianceName) to continue)"
    } else {
        Write-Error $_.Exception.Message
    }
}

Function Debug-ExceptionWriter {
    Param (
        [Parameter(Mandatory = $true)]
        [PSObject]$object
    )

    $lineNumber = $object.InvocationInfo.ScriptLineNumber
    $lineText = $object.InvocationInfo.Line.trim()
    $errorMessage = $object.Exception.Message
    Write-Output " Error at Script Line $lineNumber"
    Write-Output " Relevant Command: $lineText"
    Write-Output " Error Message: $errorMessage"
}
Export-ModuleMember -Function Debug-ExceptionWriter

Function Get-ExternalFileName ($title, $fileType, $location) {
    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.Title = "$title"
    if ($location -eq "default") {
        $OpenFileDialog.initialDirectory = Get-Location
    } else {
        $OpenFileDialog.initialDirectory = $location
    }
    $OpenFileDialog.filter = "All files (*.$fileType) | *.$fileType"
    $OpenFileDialog.ShowDialog() | Out-Null
    $OpenFileDialog.filename
}

Function Get-ExternalDirectoryPath {
    Add-Type -AssemblyName System.Windows.Forms
    $directory = New-Object System.Windows.Forms.FolderBrowserDialog
    $null = $directory.ShowDialog()
    $directoryPath = $directory.SelectedPath
    $directoryPath
}

Function cidrMaskLookup {
    Param (
        [Parameter (Mandatory = $true)][ValidateSet("mask", "cidr")] [String]$source,  
        [Parameter (Mandatory = $true)] [String]$value
    )

    $subnetMasks = @(
        ($32 = @{ cidr = "32"; mask = "255.255.255.255" }),
        ($31 = @{ cidr = "31"; mask = "255.255.255.254" }),
        ($30 = @{ cidr = "30"; mask = "255.255.255.252" }),
        ($29 = @{ cidr = "29"; mask = "255.255.255.248" }),
        ($28 = @{ cidr = "28"; mask = "255.255.255.240" }),
        ($27 = @{ cidr = "27"; mask = "255.255.255.224" }),
        ($26 = @{ cidr = "26"; mask = "255.255.255.192" }),
        ($25 = @{ cidr = "25"; mask = "255.255.255.128" }),
        ($24 = @{ cidr = "24"; mask = "255.255.255.0" }),
        ($23 = @{ cidr = "23"; mask = "255.255.254.0" }),
        ($22 = @{ cidr = "22"; mask = "255.255.252.0" }),
        ($21 = @{ cidr = "21"; mask = "255.255.248.0" }),
        ($20 = @{ cidr = "20"; mask = "255.255.240.0" }),
        ($19 = @{ cidr = "19"; mask = "255.255.224.0" }),
        ($18 = @{ cidr = "18"; mask = "255.255.192.0" }),
        ($17 = @{ cidr = "17"; mask = "255.255.128.0" }),
        ($16 = @{ cidr = "16"; mask = "255.255.0.0" }),
        ($15 = @{ cidr = "15"; mask = "255.254.0.0" }),
        ($14 = @{ cidr = "14"; mask = "255.252.0.0" }),
        ($13 = @{ cidr = "13"; mask = "255.248.0.0" }),
        ($12 = @{ cidr = "12"; mask = "255.240.0.0" }),
        ($11 = @{ cidr = "11"; mask = "255.224.0.0" }),
        ($10 = @{ cidr = "10"; mask = "255.192.0.0" }),
        ($9 = @{ cidr = "9"; mask = "255.128.0.0" }),
        ($8 = @{ cidr = "8"; mask = "255.0.0.0" }),
        ($7 = @{ cidr = "7"; mask = "254.0.0.0" }),
        ($6 = @{ cidr = "6"; mask = "252.0.0.0" }),
        ($5 = @{ cidr = "5"; mask = "248.0.0.0" }),
        ($4 = @{ cidr = "4"; mask = "240.0.0.0" }),
        ($3 = @{ cidr = "3"; mask = "224.0.0.0" }),
        ($2 = @{ cidr = "2"; mask = "192.0.0.0" }),
        ($1 = @{ cidr = "1"; mask = "128.0.0.0" }),
        ($0 = @{ cidr = "0"; mask = "0.0.0.0" })            
    )
    If ($source -eq "Mask") {
        $found = $subnetMasks | Where-Object { $_.'mask' -eq $value }
        $returnValue = $found.cidr
    } else {
        $found = $subnetMasks | Where-Object { $_.'cidr' -eq $value }
        $returnValue = $found.mask
    }   
    Return $returnValue
}

Function createHeader {
    $Global:headers = @{"Accept" = "application/json" }
    $Global:headers.Add("Authorization", "Bearer $accessToken")
}

Function createBasicAuthHeader {
    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password))) # Create Basic Authentication Encoded Credentials
    $headers = @{"Accept" = "application/json" }
    $headers.Add("Authorization", "Basic $base64AuthInfo")
    $headers.Add("Content-Type", "application/json")
    $headers
}

Function createvCenterAuthHeader {
    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
    $vcAuthHeaders = @{"vmware-use-header-authn" = "true" }
    $vcAuthHeaders.Add("Authorization", "Basic $base64AuthInfo")
    $vcAuthHeaders
}

Function createGitHubAuthHeader {

    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$token
    )

    # Get the headers with authorization to pull content pack from the GitHub repository
    $Global:ghHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
    $ghHeaders.Add('Accept', 'application/vnd.github.VERSION.raw')
    $ghHeaders.Add('Authorization', "Basic $token")
}

#EndRegion End Utility Functions ######
###################################################################################

###################################################################################
#Region Start of Test Functions ######

Function Test-PowerValidatedSolutionsPrereq {
    <#
        .SYNOPSIS
        Validate prerequisites to run the PowerShell module.

        .DESCRIPTION
        The Test-PowerValidatedSolutionsPrereq cmdlet checks that all the prerequisites have been met to run the PowerShell module.

        .EXAMPLE
        Test-PowerValidatedSolutionsPrereq
        This example runs the prerequisite validation.
    #>


    Try {
        Clear-Host; Write-Host ""

        $modules = @(
            @{ Name=("VMware.PowerCLI"); MinimumVersion=("13.1.0")}
            @{ Name=("VMware.vSphere.SsoAdmin"); MinimumVersion=("1.3.9")}
            @{ Name=("ImportExcel"); MinimumVersion=("7.8.5")}
            @{ Name=("PowerVCF"); MinimumVersion=("2.4.0")}
        )

        foreach ($module in $modules ) {
            if ((Get-InstalledModule -ErrorAction SilentlyContinue -Name $module.Name).Version -lt $module.MinimumVersion) {
                $message = "PowerShell Module: $($module.Name) $($module.MinimumVersion) is not installed."
                Show-PowerValidatedSolutionsOutput -type ERROR -message $message
                Break
            } else {
                $moduleCurrentVersion = (Get-InstalledModule -Name $module.Name).Version
                $message = "PowerShell Module: $($module.Name) $($moduleCurrentVersion) is installed and supports the minimum required version."
                Show-PowerValidatedSolutionsOutput -type INFO -message $message
            }
        } 
    } Catch {
        Write-Error $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-PowerValidatedSolutionsPrereq

Function Test-EndpointConnection {
    <#
        .SYNOPSIS
        Test the connection to an endpoint on a specific port.

        .DESCRIPTION
        The Test-EndpointConnection cmdlet tests the connection to an endpoint on a specific port.
        If PowerShell Core is used, the Test-Connection cmdlet is used to test the connection.
        If PowerShell Desktop is used, the Test-NetConnection cmdlet is used to test the connection.

        .EXAMPLE
        Test-EndpointConnection -server example.rainpole.io -port 443
        This example tests a connection to an endpoint on port TCP 443 (HTTPS).

        .EXAMPLE
        Test-EndpointConnection -server example.rainpole.io -port 22
        This example tests a connection to an endpoint on port TCP 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the endpoint to test a connection to.

        .PARAMETER port
        The port number to test the endpoint connection.
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter(Mandatory = $true, Position = 1)] [ValidateNotNullOrEmpty()] [Int32]$port
    )

    Try {
        if ($PSVersionTable.PSEdition -eq 'Core') {
            if ($status = Test-Connection -TargetName $server -TcpPort $port -Quiet) {
                $connection = $True
                Return $connection
            } else {
                $connection = $False
                Return $connection
            } 
        } elseif ($PSVersionTable.PSEdition -eq 'Desktop') {
            $OriginalProgressPreference = $Global:ProgressPreference; $Global:ProgressPreference = 'SilentlyContinue'
            if ($status = Test-NetConnection -ComputerName $server -Port $port -WarningAction SilentlyContinue) {
                $Global:ProgressPreference = $OriginalProgressPreference
                Return $status.TcpTestSucceeded
            } else {
                $Global:ProgressPreference = $OriginalProgressPreference
                Return $status.TcpTestSucceeded
            }
        }
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-EndpointConnection

Function Test-VCFConnection {
    <#
        .SYNOPSIS
        Check network connectivity to an SDDC Manager instance.

        .DESCRIPTION
        Checks the network connectivity to an SDDC Manager instance.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-VCFConnection -server sfo-vcf01.sfo.rainpole.io
        This example checks network connectivity with an SDDC Manager instance on default port, 443 (HTTPS).

        .EXAMPLE
        Test-VCFConnection -server sfo-vcf01.sfo.rainpole.io -port 443
        This example checks network connectivity with an SDDC Manager instance on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-VCFConnection -server sfo-vcf01.sfo.rainpole.io -port 22
        This example checks network connectivity with an SDDC Manager instance on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the SDDC Manager instance.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with SDDC Manager instance ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-VCFConnection

Function Test-VCFAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:accessToken -Force -Confirm:$false -ErrorAction Ignore

    Try {
        Request-VCFToken -fqdn $server -Username $user -Password $pass -skipCertificateCheck -ErrorAction SilentlyContinue -ErrorVariable ErrMsg | Out-Null
        if ($accessToken) {
            $vcfAuthentication = $True
            Return $vcfAuthentication
        } else {
            Write-Error "Unable to obtain access token from SDDC Manager ($server), check credentials: PRE_VALIDATION_FAILED"
            $vcfAuthentication = $False
            Return $vcfAuthentication
        }
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-VCFAuthentication

Function Test-EsxiConnection {
    <#
        .SYNOPSIS
        Check network connectivity to an ESXi host.

        .DESCRIPTION
        Checks the network connectivity to an ESXi host.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-EsxiConnection -server sfo01-m01-esx01.sfo.rainpole.io
        This example checks network connectivity with an ESXi host on default port, 443 (HTTPS).

        .EXAMPLE
        Test-EsxiConnection -server sfo01-m01-esx01.sfo.rainpole.io -port 443
        This example checks network connectivity with an ESXi host on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-EsxiConnection -server sfo01-m01-esx01.sfo.rainpole.io -port 22
        This example checks network connectivity with an ESXi host on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the ESXi host.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with ESXi host ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-EsxiConnection

Function Test-EsxiAuthentication {
    <#
        .SYNOPSIS
        Check authentication to an ESXi host.

        .DESCRIPTION
        Checks the authentication to an ESXi host.

        .EXAMPLE
        Test-EsxiAuthentication -server sfo01-m01-esx01.sfo.rainpole.io -user root -pass VMware1!
        This example checks authentication to an ESXi host.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the ESXi host.

        .PARAMETER user
        The username to authenticate to the ESXi host.

        .PARAMETER pass
        The password to authenticate to the ESXi host.
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        Connect-VIServer -Server $server -User $user -pass $pass | Out-Null
        if ($DefaultVIServer.Name -eq $server) {
            $esxiAuthentication = $True
            Return $esxiAuthentication
        } else {
            Write-Error "Unable to authenticate to ESXi host ($server), check credentials: PRE_VALIDATION_FAILED"
            $esxiAuthentication = $False
            Return $esxiAuthentication
        }
    } Catch {
        # Do nothing.
    }
}
Export-ModuleMember -Function Test-EsxiAuthentication

Function Test-VsphereConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a vCenter Server instance.

        .DESCRIPTION
        Checks the network connectivity to a vCenter Server instance.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-VsphereConnection -server sfo-m01-vc01.sfo.rainpole.io
        This example checks network connectivity with a vCenter Server instance on default port, 443 (HTTPS).

        .EXAMPLE
        Test-VsphereConnection -server sfo-m01-vc01.sfo.rainpole.io -port 443
        This example checks network connectivity with a vCenter Server instance on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-VsphereConnection -server sfo-m01-vc01.sfo.rainpole.io -port 22
        This example checks network connectivity with a vCenter Server instance on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the vCenter Server instance.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with vCenter Server instance ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-VsphereConnection

Function Test-VsphereAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        Connect-VIServer -Server $server -User $user -pass $pass | Out-Null
        if ($DefaultVIServer.Name -eq $server) {
            $vsphereAuthentication = $True
            Return $vsphereAuthentication
        }    else {
            Write-Error "Unable to authenticate to vCenter Server ($server), check credentials: PRE_VALIDATION_FAILED"
            $vsphereAuthentication = $False
            Return $vsphereAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-VsphereAuthentication

Function Test-SSOConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a vCenter Single Sign-On endpoint.

        .DESCRIPTION
        Checks the network connectivity to a vCenter Single Sign-On endpoint.
        Supports testing a connection on port 443 (HTTPS).

        .EXAMPLE
        Test-SSOConnection -server sfo-m01-vc01.sfo.rainpole.io
        This example checks network connectivity with a vCenter Single Sign-On endpoint on port 443 (HTTPS).

        .EXAMPLE
        Test-SSOConnection -server sfo-m01-vc01.sfo.rainpole.io -port 443
        This example checks network connectivity with a vCenter Single Sign-On endpoint on port 443 (HTTPS).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the vCenter Single Sign-On endpoint.

        .PARAMETER port
        The port number to test the connection. Default: 443 (HTTPS).
    #>

    
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with vCenter Single Sign-On endpoint ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-SSOConnection

Function Test-SSOAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Try {
        $Script:ssoConnectionDetail = Connect-SsoAdminServer -Server $server -User $user -Password $pass -SkipCertificateCheck
        if ($DefaultSsoAdminServers.Name -eq $server) {
            $ssoAuthentication = $True
            Return $ssoAuthentication
        } else {
            Write-Error "Unable to authenticate to Single-Sign-On Server ($server), check credentials: PRE_VALIDATION_FAILED"
            $ssoAuthentication = $False
            Return $ssoAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-SSOAuthentication

Function Test-vSphereApiConnection {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server
    )

    Try {
        if (Test-Connection -ComputerName ($server) -Quiet -Count 1) {
            $vSphereApiConnection = $True
            Return $vSphereApiConnection
        } else { 
            Write-Error "Unable to communicate with vSphere API Endpoint ($server), check FQDN/IP address: PRE_VALIDATION_FAILED"
            $vSphereApiConnection = $False
            Return $vSphereApiConnection
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-vSphereApiConnection

Function Test-vSphereApiAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [Switch]$admin
    )

    Try {
        if ($PsBoundParameters.ContainsKey("admin")) {
            $response = Request-vSphereApiToken -fqdn $server -username $user -password $pass -admin
        } else {
            $response = Request-vSphereApiToken -fqdn $server -username $user -password $pass
        }
        if ($response -match "Successfully Requested") {
            $vSphereApiAuthentication = $True
            Return $vSphereApiAuthentication
        } else {
            Write-Error "Unable to authenticate to vSphere API Endpoint ($server), check credentials: PRE_VALIDATION_FAILED"
            $vSphereApiAuthentication = $False
            Return $vSphereApiAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-vSphereApiAuthentication

Function Test-NSXTConnection {
    <#
        .SYNOPSIS
        Check network connectivity to an NSX Manager.

        .DESCRIPTION
        Checks the network connectivity to an NSX Manager.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-NSXTConnection -server sfo-m01-nsx01.sfo.rainpole.io
        This example checks network connectivity with an NSX Manager on default port, 443 (HTTPS).

        .EXAMPLE
        Test-NSXTConnection -server sfo-m01-nsx01.sfo.rainpole.io -port 443
        This example checks network connectivity with an NSX Manager on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-NSXTConnection -server sfo-m01-nsx01.sfo.rainpole.io -port 22
        This example checks network connectivity with an NSX Manager on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the NSX Manager.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with NSX Manager ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-NSXTConnection

Function Test-NSXTAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:nsxtHeaders -Force -Confirm:$false -ErrorAction Ignore

    Try {
        $response = Request-NsxtToken -fqdn $server -username $user -password $pass -skipCertificateCheck
        if ($response -match "Successfully Requested") {
            $nsxtAuthentication = $True
            Return $nsxtAuthentication
        } else {
            Write-Error "Unable to obtain access token from NSX Manager ($server), check credentials: PRE_VALIDATION_FAILED"
            $nsxtAuthentication = $False
            Return $nsxtAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-NSXTAuthentication

Function Test-vRSLCMConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a VMwaare Aria Suite Lifecycle instance.

        .DESCRIPTION
        Checks the network connectivity to a VMware Aria Suite Lifecycle instance.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-vRSLCMConnection -server xint-vrslcm01.rainpole.io
        This example checks network connectivity with a VMware Aria Suite Lifecycle instance on default port, 443 (HTTPS).

        .EXAMPLE
        Test-vRSLCMConnection -server xint-vrslcm01.rainpole.io -port 443
        This example checks network connectivity with a VMware Aria Suite Lifecycle instance on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-vRSLCMConnection -server xint-vrslcm01.rainpole.io -port 22
        This example checks network connectivity with a VMware Aria Suite Lifecycle instance on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a VMware Aria Suite Lifecycle instance.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with VMware Aria Suite Lifecycle instance ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vRSLCMConnection

Function Test-vRSLCMAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:vrslcmHeaders -Force -Confirm:$false -ErrorAction Ignore

    Try {
        Request-vRSLCMToken -fqdn $server -username $user -password $pass -ErrorAction Ignore -ErrorVariable ErrMsg | Out-Null
        if ((Get-vRSLCMHealth).'vrlcm-server' -eq "UP") {
            $vrslcmAuthentication = $True
            Return $vrslcmAuthentication
        } else {
            Write-Error "Unable to obtain access token from VMware Aria Suite Lifecycle instance ($server), check credentials: PRE_VALIDATION_FAILED"
            $vrslcmAuthentication = $False
            Return $vrslcmAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-vRSLCMAuthentication

Function Test-vROPSConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a VMware Aria Operations cluster or analytics node.

        .DESCRIPTION
        Checks the network connectivity to a VMware Aria Operations cluster or analytics node.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-vROPSConnection -server xint-vrops01.rainpole.io
        This example checks network connectivity with a VMware Aria Operations cluster or analytics node on default port, 443 (HTTPS).

        .EXAMPLE
        Test-vROPSConnection -server xint-vrops01.rainpole.io -port 443
        This example checks network connectivity with a VMware Aria Operations cluster or analytics node. on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-vROPSConnection -server xint-vrops01a.rainpole.io -port 22
        This example checks network connectivity with a VMware Aria Operations analytics node on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a VMware Aria Operations cluster or analytics node.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with VMware Aria Operations cluster or node ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vROPSConnection

Function Test-vROPSAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:vropsHeaders -Force -Confirm:$false -ErrorAction Ignore

    Try {
        Request-vROPSToken -fqdn $server -username $user -password $pass | Out-Null
        if ($vropsHeaders.Authorization) {
            $vropsAuthentication = $True
            Return $vropsAuthentication
        } else {
            Write-Error "Unable to obtain access token from VMware Aria Operations ($server), check credentials: PRE_VALIDATION_FAILED"
            $vropsAuthentication = $False
            Return $vropsAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-vROPSAuthentication

Function Test-vRLIConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a VMware Aria Operations for Logs cluster or node.

        .DESCRIPTION
        Checks the network connectivity to a VMware Aria Operations for Logs cluster or node.
        Supports testing a connection on ports 443 (HTTPS), 80 (HTTP), 22 (SSH), 9000 (CFAPI), 9543 (CFAPI SSL), 514 (SYSLOG), 1514 (SYSLOG), 6514 (SYSLOG). Default: 443 (HTTPS).

        .EXAMPLE
        Test-vRLIConnection -server sfo-vrli01.sfo.rainpole.io
        This example checks network connectivity with a VMware Aria Operations for Logs cluster or node on default port, 443 (HTTPS).

        .EXAMPLE
        Test-vRLIConnection -server sfo-vrli01.sfo.rainpole.io -port 443
        This example checks network connectivity with a VMware Aria Operations for Logs cluster or node. on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-vRLIConnection -server sfo-vrli01a.sfo.rainpole.io -port 22
        This example checks network connectivity with a VMware Aria Operations for Logs node on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a VMware Aria Operations for Logs cluster or node.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS), 80 (HTTP), 22 (SSH), 9000 (CFAPI), 9543 (CFAPI SSL), 514 (SYSLOG), 1514 (SYSLOG), 6514 (SYSLOG). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22", "80", "9000", "9543", "514", "1514", "6514")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with VMware Aria Operations for Logs cluster or node ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vRLIConnection

Function Test-vRLIAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:vrliHeaders -Force -Confirm:$false -ErrorAction Ignore

    Try {
        Request-vRLIToken -fqdn $server -Username $user -Password $pass | Out-Null
        if ($vrliHeaders.Authorization) {
            $vrliAuthentication = $True
            Return $vrliAuthentication
        } else {
            Write-Error "Unable to obtain access token from VMware Aria Operations for Logs ($server), check credentials: PRE_VALIDATION_FAILED"
            $vrliAuthentication = $False
            Return $vrliAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-vRLIAuthentication

Function Test-vRAConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a VMware Aria Automation cluster or node.

        .DESCRIPTION
        Checks the network connectivity to a VMware Aria Automation cluster or node.
        Supports testing a connection on ports 443 (HTTPS), 8080 (HTTP), 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-vRAConnection -server xint-vra01.rainpole.io
        This example checks network connectivity with a VMware Aria Automation cluster or node on default port, 443 (HTTPS).

        .EXAMPLE
        Test-vRAConnection -server xint-vra01.rainpole.io -port 443
        This example checks network connectivity with a VMware Aria Automation cluster or node. on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-vRAConnection -server xint-vra01a.rainpole.io -port 22
        This example checks network connectivity with a VMware Aria Automation node on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a VMware Aria Automation cluster or node.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS), 8080 (HTTP). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22", "8080")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with VMware Aria Automation cluster or node ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-vRAConnection

Function Test-vRAAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:vraHeaders -Force -Confirm:$false -ErrorAction Ignore

    Try {
        Request-vRAToken -fqdn $server -Username $user -Password $pass | Out-Null
        if ($vraHeaders.Authorization) {
            $vraAuthentication = $True
            Return $vraAuthentication
        } else {
            Write-Error "Unable to obtain access token from VMware Aria Automation ($server), check credentials: PRE_VALIDATION_FAILED"
            $vraAuthentication = $False
            Return $vraAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-vRAAuthentication

Function Test-WSAConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a Workspace ONE Access cluster or node.

        .DESCRIPTION
        Checks the network connectivity to a Workspace ONE Access cluster or node.
        Supports testing a connection on ports 443 (HTTPS), 8443 (HTTPS), 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-WSAConnection -server xint-wsa01.rainpole.io
        This example checks network connectivity with a Workspace ONE Access cluster or node on default port, 443 (HTTPS).

        .EXAMPLE
        Test-WSAConnection -server xint-wsa01.rainpole.io -port 443
        This example checks network connectivity with a Workspace ONE Access cluster or node on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-WSAConnection -server xint-wsa01.rainpole.io -port 22
        This example checks network connectivity with a Workspace ONE Access node. on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a Workspace ONE Access cluster or node.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS), 8443 (HTTPS). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "8443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with Workspace ONE Access cluster or node ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-WSAConnection

Function Test-WSAAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Item variable:sessionToken -Force -Confirm:$false -ErrorAction Ignore

    Try {
        Request-WSAToken -fqdn $server -user $user -pass $pass | Out-Null
        if ($sessionToken) {
            $wsaAuthentication = $True
            Return $wsaAuthentication
        } else {
            Write-Error "Unable to obtain access token from Workspace ONE Access ($server), check credentials: PRE_VALIDATION_FAILED"
            $wsaAuthentication = $False
            Return $wsaAuthentication
        }
    } Catch {
        # Do Nothing
    }
}
Export-ModuleMember -Function Test-WSAAuthentication

Function Test-VrmsVamiConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a vSphere Replication instance VAMI.

        .DESCRIPTION
        Checks the network connectivity to a vSphere Replication instance VAMI.
        Supports testing a connection on ports 5480 (HTTPS/VAMI). Default: 5480 (HTTPS/VAMI).

        .EXAMPLE
        Test-VrmsVamiConnection -server sfo-vrms01.sfo.rainpole.io
        This example checks network connectivity with a vSphere Replication instance VAMI on default port, 5480 (HTTPS/VAMI).

        .EXAMPLE
        Test-VrmsVamiConnection -server sfo-vrms01.sfo.rainpole.io -port 5480
        This example checks network connectivity with a vSphere Replication instance VAMI on port 5480 (HTTPS/VAMI). This is the default port.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a vSphere Replication instance.

        .PARAMETER port
        The port number to test the connection. One of the following: 5480 (HTTPS/VAMI). Default: 5480 (HTTPS/VAMI).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("5480")] [Int32]$port = "5480"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with vSphere Replication instance ($server) VAMI on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-VrmsVamiConnection

Function Test-VrmsVamiAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Variable -Name vrmsHeader -Scope Global -Force -Confirm:$false -ErrorAction Ignore

    Try {
        $response = Request-VrmsToken -fqdn $server -username $user -password $pass
        if ($vrmsHeader) {
            $vrmsVamiConnection = $True
            Return $vrmsVamiConnection
        } else {
            Write-Error $response
            $vrmsVamiConnection = $False
            Return $vrmsVamiConnection
        }
    } Catch {
        Write-Error $response
    }
}
Export-ModuleMember -Function Test-VrmsVamiAuthentication

Function Test-SrmVamiConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a Site Recovery Manager instance VAMI.

        .DESCRIPTION
        Checks the network connectivity to a Site Recovery Manager instance VAMI.
        Supports testing a connection on ports 5480 (HTTPS/VAMI). Default: 5480 (HTTPS/VAMI).

        .EXAMPLE
        Test-SrmVamiConnection -server sfo-srm01.sfo.rainpole.io
        This example checks network connectivity with a Site Recovery Manager instance VAMI on default port, 5480 (HTTPS/VAMI).

        .EXAMPLE
        Test-SrmVamiConnection -server sfo-srm01.sfo.rainpole.io -port 5480
        This example checks network connectivity with a Site Recovery Manager instance VAMI on port 5480 (HTTPS/VAMI). This is the default port.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a Site Recovery Manager instance.

        .PARAMETER port
        The port number to test the connection. One of the following: 5480 (HTTPS/VAMI). Default: 5480 (HTTPS/VAMI).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("5480")] [Int32]$port = "5480"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with vSphere Replication instance ($server) VAMI on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-SrmVamiConnection

Function Test-SrmVamiAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass
    )

    Remove-Variable -Name srmHeader -Scope Global -Force -Confirm:$false -ErrorAction Ignore

    Try {
        $response = Request-SrmToken -fqdn $server -username $user -password $pass
        if ($srmHeader) {
            $srmVamiConnection = $True
            Return $srmVamiConnection
        } else {
            Write-Error $response
            $srmVamiConnection = $False
            Return $srmVamiConnection
        }
    } Catch {
        Write-Error $response
    }
}
Export-ModuleMember -Function Test-SrmVamiAuthentication

Function Test-SrmConnection {
    <#
        .SYNOPSIS
        Check network connectivity to a Site Recovery Manager instance.

        .DESCRIPTION
        Checks the network connectivity to a Site Recovery Manager instance.
        Supports testing a connection on ports 443 (HTTPS) and 22 (SSH). Default: 443 (HTTPS).

        .EXAMPLE
        Test-SrmConnection -server sfo-srm01.sfo.rainpole.io
        This example checks network connectivity with a Site Recovery Manager instance on default port, 443 (HTTPS).

        .EXAMPLE
        Test-SrmConnection -server sfo-srm01.sfo.rainpole.io -port 443
        This example checks network connectivity with a Site Recovery Manager instance on port 443 (HTTPS). This is the default port.

        .EXAMPLE
        Test-SrmConnection -server sfo-srm01.sfo.rainpole.io -port 22
        This example checks network connectivity with a Site Recovery Manager instance on port 22 (SSH).

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the a Site Recovery Manager instance.

        .PARAMETER port
        The port number to test the connection. One of the following: 443 (HTTPS) or 22 (SSH). Default: 443 (HTTPS).
    #>


    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $false)] [ValidateSet("443", "22")] [Int32]$port = "443"
    )

    Try {
        if ($status = Test-EndpointConnection -server $server -port $port ) {
            Return $status
        } else { 
            Write-Error "Unable to communicate with Site Recovery Manager instance ($server) on port ($port), check FQDN/IP Address: PRE_VALIDATION_FAILED"
            Return $status
        } 
    } Catch {
        $_.Exception.Message
    }
}
Export-ModuleMember -Function Test-SrmConnection

Function Test-SrmAuthentication {
    Param (
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$remoteUser,
        [Parameter (Mandatory = $false)] [ValidateNotNullOrEmpty()] [String]$remotePass
    )

    Try {
        if ($remoteUser -and $remotePass) {
            Connect-SrmServer -SrmServerAddress $server -user $user -password $pass -remoteUser $remoteUser -remotePassword $remotePass | Out-Null
        } else {
            Connect-SrmServer -SrmServerAddress $server -user $user -password $pass | Out-Null
        }
    } Catch {
        if ($_.Exception.Message -eq "Cannot complete login due to an incorrect user name or password.") {
            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    ([System.Security.Authentication.InvalidCredentialException]"Unable to authenticate with Site Recovery Manager ($server), check credentials: PRE_VALIDATION_FAILED"),
                    'Test-SrmAuthentication',
                    [System.Management.Automation.ErrorCategory]::AuthenticationError,
                    ""
                )
            )
        } elseif ($_.Exception.Message -eq "Unable to connect to the remote server: One or more errors occurred.") {
            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    ([System.Management.Automation.ProviderNotFoundException]"Unable to authenticate with Site Recovery Manager ($server), check server IP address/FQDN: PRE_VALIDATION_FAILED"),
                    'Test-SrmAuthentication',
                    [System.Management.Automation.ErrorCategory]::InvalidArgument,
                    ""
                )
            )
        } elseif ($_.Exception.Message -eq "Unable to connect to the remote server: The connection to the remote server is down.") {
            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    ([System.Management.Automation.RemoteException]"Unable to authenticate with the remote Site Recovery Manager instance: PRE_VALIDATION_FAILED"),
                    'Test-SrmAuthentication',
                    [System.Management.Automation.ErrorCategory]::ConnectionError,
                    ""
                )
            )
        }
    }
    if ($defaultSrmServers) {
        $srmAuthentication = $True
        Return $srmAuthentication
    } else {
        $srmAuthentication = $False
        Return $srmAuthentication
    }
}
Export-ModuleMember -Function Test-SrmAuthentication

Function Test-SrmAuthenticationREST {
    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory=$false)] [ValidateNotNullOrEmpty()] [String]$remoteUser,
        [Parameter (Mandatory=$false)] [ValidateNotNullOrEmpty()] [String]$remotePass
    )

    Try {
        $srmServerConnection = Request-SrmTokenREST -fqdn $server -username $user -password $pass
    
        if ($srmServerConnection -match "Successfully") {
            $srmAuthentication = $True
        } else {
            $srmAuthentication = $False
        }
        if ($remoteUser -and $remotePass) {
            $srmRemoteConnection = Connect-SrmRemoteSession -username $remoteUser -password $remotePass
            if ($srmRemoteConnection -match "Successfully") {
                $srmRemoteAuthentication = $True
            } else {
                $srmRemoteAuthentication = $False
            }
        }
        $outputObject = [PSCustomObject]@{
            srmAuthentication = $srmAuthentication
            srmRemoteAuthentication = $srmRemoteAuthentication
        }
        return $outputObject
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Test-SrmAuthenticationREST

Function Test-VrmsAuthenticationREST {
    Param (
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$server,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$user,
        [Parameter (Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$pass,
        [Parameter (Mandatory=$false)] [ValidateNotNullOrEmpty()] [String]$remoteUser,
        [Parameter (Mandatory=$false)] [ValidateNotNullOrEmpty()] [String]$remotePass
    )

    Try {
        $vrmsServerConnection = Request-VrmsTokenREST -fqdn $server -username $user -password $pass
    
        if ($vrmsServerConnection -match "Successfully") {
            $vrmsAuthentication = $True
        } else {
            $vrmsAuthentication = $False
        }
        if ($remoteUser -and $remotePass) {
            $vrmsRemoteConnection = Connect-VrmsRemoteSession -username $remoteUser -password $remotePass
            if ($vrmsRemoteConnection -match "Successfully") {
                $vrmsRemoteAuthentication = $True
            } else {
                $vrmsRemoteAuthentication = $False
            }
        }
        $outputObject = [PSCustomObject]@{
            vrmsAuthentication = $vrmsAuthentication
            vrmsRemoteAuthentication = $vrmsRemoteAuthentication
        }
        return $outputObject
    } Catch {
        Debug-ExceptionWriter -object $_
    }
}
Export-ModuleMember -Function Test-VrmsAuthenticationREST

Function Test-WMSubnetInput {
    <#
        .SYNOPSIS
        Tests whether an IPv4 subnet is sized correctly for Developer Ready Infrastructure pools.

        .DESCRIPTION
        The Test-WMSubnetInput cmdlet tests whether an IPv4 subnet is sized correctly for Developer Ready Infrastructure pools
        
        .EXAMPLE
        Test-WMSubnetInput -Subnet 192.168.21.0/24 -SubnetType Ingress
        This example will return as 'true'.

        .PARAMETER Subnet
        The IPv4 subnet to test.

        .PARAMETER SubnetType
        The type of subnet to test. One of the following: Pod, Service, Egress, Ingress.
        #>


    Param (
        [Parameter (Mandatory = $true)] [String]$Subnet,
        [Parameter (Mandatory = $true)][ValidateSet("Pod", "Service", "Egress", "Ingress")] [String]$SubnetType
    )

    Switch ($subnetType) {
        "Pod" {
            $subnetMinimum = 23
            Break
        }
        "Service" {
            $subnetMinimum = 22
            Break
        }
        "Egress" {
            $subnetMinimum = 27
            Break
        }
        "Ingress" {
            $subnetMinimum = 27
            Break
        }
        default {
            Write-Error "Unsuported Subnet Type ($subnetType)"
            Break
        }
    }

    Try {
        $checkSubnet = $null
        $subnetStart = $null
        [bool]$testElement = $false

        $subnetStart = $Subnet.Split("/")[0]
        Try {
            $checkSubnet = [IPAddress]$subnetStart
        } Catch {
            #Do nothing
        }

        if ($checksubnet.IPAddressToString -ne $subnetStart -or !$checkSubnet) {
            Write-Error "Improperly formatted subnet ($subnet): PRE_VALIDATION_FAILED"
        } else {
            $testElement = $true
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }

    Try {
        [bool]$testSufix = $false
        $suffix = $Subnet.Split("/")[1]
        $checkSuffix = [int[]]$suffix
        if ($checkSuffix -gt $subnetMinimum -or !$checkSuffix) {
            Write-Error "Improperly sized $subnetType subnet ($subnet). Host prefix length should be at least {$subnetminimum)"
        } else {
            $testSufix = $true
        }
    } Catch {
        Debug-ExceptionWriter -object $_
    }

    if ($testElement -and $testSufix) {
        Return $true
    } else {
        Return $false
    }
    
}
Export-ModuleMember -Function Test-WMSubnetInput

Function Test-IpAddress {
    <#
        .SYNOPSIS
        Tests whether an IPv4 address is in a specified subnet.

        .DESCRIPTION
        The Test-IpAddress cmdlet tests whether an IPv4 address is in a specified subnet.

        .EXAMPLE
        Test-IpAddress -ipAddress 192.168.20.10 -Subnet 192.168.20.0/24
        This example will test whether the IPv4 address 192.168.20.10 is in the 192.168.20.0/24 subnet.

        .PARAMETER ipAddress
        The IPv4 address to test.

        .PARAMETER subnet
        The IPv4 subnet to test against.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$ipAddress,
        [Parameter (Mandatory = $true)] [String]$Subnet
    )

    $subnetStart = $Subnet.Split("/")[0]
    $suffix = $Subnet.Split("/")[1]

    $subnetStartBinary = $subnetStart -split '\.' | ForEach-Object { [System.Convert]::ToString($_, 2).PadLeft(8, '0') }
    $subnetStartBinary = $subnetStartBinary -join ""
    $subnetStartBinary = ($subnetStartBinary).ToCharArray()

    $ipAddressBinary = $ipAddress -split '\.' | ForEach-Object { [System.Convert]::ToString($_, 2).PadLeft(8, '0') }
    $ipAddressBinary = $ipAddressBinary -join ""
    $ipAddressBinary = ($ipAddressBinary).ToCharArray()

    for ($i = 0; $i -lt $subnetStartBinary.length; $i++) {
        if ($i -ge $suffix) {
            $subnetStartBinary[$i] = "1"
        } 
    }

    for ($i = 0; $i -lt $subnetStartBinary.length; $i++) {
        $partSubnetStartBinary += $subnetStartBinary[$i] 
        if (($i + 1) % 8 -eq 0) {
            $partSubnetStartBinary = $partSubnetStartBinary -join ""
            $subnetBroadcastBinary += $partSubnetStartBinary -join ""
            $partSubnetStartBinary = ""
        }
    }

    $subnetBroadcastBinary = $subnetBroadcastBinary.ToCharArray()

    [Int[]]$suffixComparison = (1..32)

    for ($i = 0; $i -lt $suffixComparison.length; $i++) {
        if ($suffixComparison[$i] -gt $suffix) {
            $suffixComparison[$i] = "0"
        } else {
            $suffixComparison[$i] = "1"
        }
    }
        
    [string]$suffixBinaryString = $suffixComparison -join ""
    [char[]]$suffixBinary = $suffixBinaryString.ToCharArray()
    $comparison = $true

    for ($i = 0; $i -le $subnetStartBinary.length; $i++) {
        if ($subnetStartBinary[$i] -ne $ipAddressBinary[$i] -and $suffixBinary[$i] -ne "0") {
            $comparison = $false
        } 
    }

    $output = New-Object -TypeName PSCustomObject
    $output | Add-Member -notepropertyname 'IpAddress' -notepropertyvalue $ipAddress
    $output | Add-Member -notepropertyname 'Subnet' -notepropertyvalue $subnet
    $output | Add-Member -notepropertyname 'Validated' -notepropertyvalue $comparison
    $output
}
Export-ModuleMember -Function Test-IpAddress

Function Test-IPaddressArray {

    <#
        .SYNOPSIS
        Tests whether an array of strings can be converted to valid IPv4 addresses.

        .DESCRIPTION
        The Test-IpAddressArray cmdlet tests whether an array of strings can be converted to valid IPv4 addresses.
        Returns $true if all strings are valid IPv4 address or $false when at least one is not valid IPv4 address

        .EXAMPLE
        Test-IpAddressArray -ipAddressArray @("192.168.20.10","172.16.31.1")
        This example will test whether the strings "192.168.20.10","172.16.31.1" can be converted to valid IPv4 addresses.

        .EXAMPLE
        Test-IpAddressArray -ipAddressArray "192.168.20.10"
        This example will test whether the string "192.168.20.10" can be converted to valid IPv4 addresses.

        .PARAMETER ipAddressArray
        The array of strings to test.
    #>


    Param (
        [Parameter (Mandatory = $true)] [Array]$IPaddressArray
    )

    Foreach ($ipAddress in $IPaddressArray) {
        [bool]$testElement = $false
        Try {
            $convertToIPv4 = [ipaddress]$ipAddress
        } Catch {
            Write-Error "Can not convert $ipAddress to valid IPv4 address."
            Return $false 
        }
        if (($convertToIPv4.IPAddressToString -ne $ipAddress) -or (!$convertToIPv4)) {
            Write-Error "Can not convert $ipAddress to valid IPv4 address due to missing octet"
            Return $false
        } else {
            $testElement = $true
        }
    }
    Return $testElement
}
Export-ModuleMember -Function Test-IPaddressArray

Function Test-DnsServers {

    <#
        .SYNOPSIS
        Tests whether an array of DNS servers can resolve given domain name.

        .DESCRIPTION
        The Test-DnsServers cmdlet tests whether an array of DNS servers can resolve given domain name.
        Returns $true if all servers can resolve the given domain name or $false when at least one fails.

        .EXAMPLE
        Test-DnsServers -dnsServers @("192.168.20.10","172.16.31.1") -domainName vmware.com
        This example will test whether all dns servers "192.168.20.10","172.16.31.1" can can resolve domain name vmware.com.

        .EXAMPLE
        Test-DnsServers -dnsServers "192.168.20.10" -domainName vmware.com
        This example will test whether dns server "192.168.20.10" can resolve domain name vmware.com.

        .PARAMETER dnsServers
        The array of DNS servers to test.

        .PARAMETER domainName
        The domain name to resolve.
    #>


    Param (
        [Parameter (Mandatory = $true)] [Array]$dnsServers,
        [Parameter (Mandatory = $false)] [string]$domainName = "vmware.com"
    )

    if (Test-IPaddressArray -IPaddressArray $dnsServers) {
    
        Foreach ($dnsServer in $dnsServers) {
            [bool]$resolveResult = $false
                                                                
            Try {
                $checkDnsServer = Resolve-DnsName -Name $domainName -Type A -Server $dnsServer -QuickTimeout -ErrorAction Stop
            } Catch [System.ComponentModel.Win32Exception] {
                Write-Error "Can not resolve: $domainName using dns server: $dnsServer"
                Return $false
            }
            if (!$checkDnsServer) {
                Write-Error "Can not resolve: $domainName using dns server: $dnsServer"
                $resolveResult = $false
            } else {
                $resolveResult = $true
            }
        }
        Return $resolveResult
    }
}
Export-ModuleMember -Function Test-DnsServers

Function Test-NtpServer {
    <#
        .SYNOPSIS
        Checks the status of an NTP server.

        .DESCRIPTION
        The Test-NtpServer cmdlet checks the status of an NTP server

        .EXAMPLE
        Test-NtpServer -Server pool.ntp.org
        This example will return the status of the NTP server responding at pool.ntp.org.

        .PARAMETER server
        The fully qualified domain name (FQDN) or IP address of the NTP server to check.
    #>


    Param (
        [Parameter (Mandatory = $true)] [String]$server
    )

    $ntpStatus = $null
    Try {
        [Byte[]]$NtpData = , 0 * 48
        $NtpData[0] = 0x1B
    
        $Socket = New-Object Net.Sockets.Socket([Net.Sockets.AddressFamily]::InterNetwork,
                                                [Net.Sockets.SocketType]::Dgram,
                                                [Net.Sockets.ProtocolType]::Udp)
        $Socket.ReceiveTimeout = 2000
        $Socket.SendTimeout = 2000
        $Socket.Connect($Server,123)
        [Void]$Socket.Send($NtpData)
        [Void]$Socket.Receive($NtpData)  
        $Socket.Close()
    } Catch {
        # Do nothing
    }   

    if ($ntpData -eq 0x1B) {
        $ntpStatus = $false
    } else {
        $ntpStatus = $true
    }
    Return $ntpStatus
}
Export-ModuleMember -Function Test-NtpServer

#EndRegion End of Test Functions ######
###################################################################################

#EndRegion E N D O F F U N C T I O N S ###########
#######################################################################################################################