HPOneView.500.psm1

##############################################################################
# HPE OneView PowerShell Library
##############################################################################
##############################################################################
## (C) Copyright 2013-2019 Hewlett Packard Enterprise Development LP
##############################################################################
<#
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
 
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.
 
#>


<#
 Note: This library requires the following installed:
 Microsoft .NET Framework 4.6: http://go.microsoft.com/fwlink/?LinkId=528259
 Windows Management Framework (aka PowerShell) 4: https://www.microsoft.com/en-us/download/details.aspx?id=40855
#>


# Set HPOneView POSH Library Version
[Version]$ModuleVersion = '5.00.2152.1665'
New-Variable -Name PSLibraryVersion -Scope Global -Value (New-Object HPOneView.Library.Version($ModuleVersion)) -Option Constant -ErrorAction SilentlyContinue
$Global:CallStack = Get-PSCallStack
$script:ModuleVerbose = [Bool]($Global:CallStack | Where-Object { $_.Command -eq "<ScriptBlock>" }).position.text -match "-verbose"
[void][Reflection.Assembly]::LoadWithPartialName("System.Web")

# Check to see if another module is loaded in the console, but allow Import-Module to Process normally if user specifies the same module name
if (Get-Module -Name HPOneView* | Where-Object Name -ne "HPOneView.500")
{

    write-Host "CRITICAL: Another HP OneView module is already loaded: "  -ForegroundColor Yellow -BackgroundColor Black 
    Write-Host " |"  -ForegroundColor Yellow -BackgroundColor Black 
    get-module -name HPOneView* | ForEach-Object { write-host " |--> $($_.name) ($($_.Version))"  -ForegroundColor Yellow -BackgroundColor Black }
    write-host ""

    [System.String]$Exception                                  = 'InvalidOperationException'
    [System.String]$ErrorId                                    = 'CannotLoadMultipleLibraries'
    [System.Object]$TargetObject                               = 'Import-Module HPOneView.500'
    [System.Management.Automation.ErrorCategory]$ErrorCategory = 'ResourceExists'
    [System.String]$Message                                    = 'Another HPE OneView module is already loaded. The HPE OneView PowerShell library does not support loading multiple versions of libraries within the same console.'
    
    $_exception  = New-Object $Exception $Message
    $ErrorRecord = New-Object Management.Automation.ErrorRecord $_exception, $ErrorID, $ErrorCategory, $TargetObject
    throw $ErrorRecord

}

# Region URIs and Enums
${Global:ConnectedSessions}         = New-Object HPOneView.Library.ConnectedSessionsList
${Global:ResponseErrorObject}       = [System.Collections.ArrayList]::new()
New-Variable -Name DefaultTimeout -Value (New-Timespan -Minutes 20) -Option Constant
$script:FSOpenMode                  = [System.IO.FileMode]::Open
$script:FSRead                      = [System.IO.FileAccess]::Read
[MidpointRounding]$MathMode         = 'AwayFromZero' 
[String]$MinXAPIVersion             = "1200"
[String]$MaxXAPIVersion             = "1200"
[String]$Repository                 = "https://api.github.com/repos/HewlettPackard/POSH-HPOneView/releases"

if ($Global:IgnoreCertPolicy)
{

    [HPOneView.PKI.SslValidation]::IgnoreCertErrors = $true

}

$ResourceCategoryEnum = @{
    Baseline                    = 'firmware-drivers';
    ServerHardware              = 'server-hardware';
    ServerHardwareType          = 'server-hardware-types';
    ServerProfile               = 'server-profiles';
    ServerProfileTemplate       = 'server-profile-templates';
    Enclosure                   = 'enclosures';
    LogicalEnclosure            = 'logical-enclosures';
    EnclosureGroup              = 'enclosure-groups';
    Interconnect                = 'interconnects';
    LogicalInterconnect         = 'logical-interconnects';
    LogicalInterconnectGroup    = 'logical-interconnect-groups';
    UplinkSet                   = 'uplink-sets';
    SasInterconnect             = 'sas-interconnects';
    SasLogicalInterconnect      = 'sas-logical-interconnects';
    SasLogicalInterconnectGroup = 'sas-logical-interconnect-groups';
    ClusterProfile              = 'hypervisor-cluster-profiles';
    ClusterNode                 = 'hypervisor-host-profiles';
    HypervisorManager           = 'hypervisor-managers';
    HypervisorCluster           = 'hypervisor-cluster-profiles';
    FabricManager               = 'fabric-managers';
    FabricManagerTenant         = 'tenants';
    RackManager                 = 'rack-managers';
    NetworkSet                  = 'network-sets';
    EthernetNetwork             = 'ethernet-networks';
    StorageVolumeSet            = 'storage-volume-sets';
    StorageVolume               = 'storage-volumes';
    StorageVolumeTemplate       = 'storage-volume-templates';
    StoragePool                 = 'storage-pools';
    IPv4Subnet                  = 'id-range-IPv4-subnet';
    IPv4Range                   = 'id-range-IPv4';
    IPv6Subnet                  = 'id-range-IPv6-subnet';
    IPv6Range                   = 'id-range-IPv6'
}

#------------------------------------
# Appliance Configuration
#------------------------------------
    [Int]$ApplianceStartupTimeout               = 900
    [String]$ApplianceStartProgressUri          = '/rest/appliance/progress'
    [String]$ApplianceVersionUri                = '/rest/appliance/nodeinfo/version'
    [String]$ApplianceEulaStatusUri             = '/rest/appliance/eula/status'
    [String]$ApplianceEulaSaveUri               = '/rest/appliance/eula/save'
    [String]$ApplianceNetworkConfigUri          = '/rest/appliance/network-interfaces'
    [String]$ApplianceNetworkStatusUri          = '/rest/appliance/network-interfaces/status'
    [String]$ApplianceNetworkMacAddrUri         = '/rest/appliance/network-interfaces/mac-addresses'
    [String]$ApplianceDateTimeUri               = '/rest/appliance/configuration/time-locale'
    [String]$ApplianceGlobalSettingsUri         = '/rest/global-settings?sort:name'
    [String]$ApplianceBaselineRepoUri           = '/rest/firmware-drivers'
    [String]$ApplianceRepositoriesUri           = '/rest/repositories'
    [String]$ApplianceBaselineRepositoriesUri   = '/rest/firmware-repositories/defaultOneViewRepo'
    [Hashtable]$RepositoryType                  = @{
        External = 'FirmwareExternalRepo';
        Internal = 'FirmwareInternalRepo'
    }
    [String]$ApplianceXApiVersionUri            = '/rest/version'
    [String]$ApplianceHANodesUri                = '/rest/appliance/ha-nodes'
    [String]$ApplianceBackupUri                 = '/rest/backups'
    [String]$ApplianceRestoreRepoUri            = '/rest/backups/archive'
    [String]$ApplianceAutoBackupConfUri         = '/rest/backups/config'
    [String]$ApplianceRestoreUri                = '/rest/restores'
    [String]$ApplianceProxyConfigUri            = '/rest/appliance/proxy-config'
    [Hashtable]$ApplianceUpdateProgressStepEnum = @{

        COMPLETED            = "Restore Completed";
        FAILED               = "Restore Failed";
        PREPARING_TO_RESTORE = "Preparing to Restore";
        RESTORING_DB         = "Restoring Database";
        RESTORING_FILES      = "Restoring Files";
        STARTING_SERVICES    = "Starting Services";
        UNKNOWN              = "The restore step is unknown"

    }
    [Hashtable]$ApplianceLocaleSetEnum          = @{

        'en-US' = 'en_US.UTF-8';
        'en_US' = 'en_US.UTF-8';
        'zh_CN' = 'zh_CN.UTF-8';
        'zh-CN' = 'zh_CN.UTF-8';
        'ja_JP' = 'ja_JP.UTF-8';
        'ja-JP' = 'ja_JP.UTF-8';

    }
    [Hashtable]$ApplianceLocaleEnum             = @{

        'en_US.UTF-8' = 'English (United States)';
        'zh_CN.UTF-8' = 'Chinese (China)';
        'ja_JP.UTF-8' = 'Japanese (Japan)';

    }
    [Hashtable]$DayOfWeekEnum                   = @{

        Sunday    = 'SU';
        SU        = 'SU';
        SUN       = 'SU';
        Monday    = 'MO';
        MO        = 'MO';
        MON       = 'MO';
        Tuesday   = 'TU';
        TU        = 'TU';
        TUE       = 'TU';
        TUES      = 'TU';
        Wednesday = 'WE';
        WE        = 'WE';
        WED       = 'WE';
        Thursday  = 'TH';
        Thur      = 'TH';
        Thurs     = 'TH';
        TH        = 'TH';
        Friday    = 'FR';
        Fri       = 'FR';
        FR        = 'FR';
        Saturday  = 'SA';
        Sat       = 'SA';
        SA        = 'SA';

    }
    [Hashtable]$AppliancePlatformType           = @{

        hardware = 'Composer';
        vm       = 'VMA'

    }
    [String]$ApplianceSupportDumpUri                 = "/rest/appliance/support-dumps"
    [String]$ApplianceHealthStatusUri                = "/rest/appliance/health-status"
    [String]$ApplianceUpdateImageUri                 = "/rest/appliance/firmware/image"
    [String]$ApplianceUpdatePendingUri               = "/rest/appliance/firmware/pending"
    [String]$ApplianceUpdateNotificationUri          = "/rest/appliance/firmware/notification"
    [String]$ApplianceUpdateMonitorUri               = "/cgi-bin/status/update-status.cgi"
    [String]$ApplianceSnmpReadCommunityUri           = "/rest/appliance/device-read-community-string"
    [String]$script:applianceRebootUri               = '/rest/appliance/shutdown?type=REBOOT'
    [String]$script:applianceShutDownUri             = '/rest/appliance/shutdown?type=HALT'
    [String]$script:applianceCsr                     = '/rest/certificates/https/certificaterequest'
    [String]$script:applianceSslCert                 = '/rest/certificates/https'
    [String]$Script:appliancePingTestUri             = '/rest/appliance/reachable'
    [String]$script:applianceDebugLogSetting         = '/logs/rest/debug/'
    [String]$script:RemoteSyslogUri                  = '/rest/remote-syslog'
    [String]$script:IPSubnetAddressPattern           = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' +
                                                       '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' +
                                                       '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' +
                                                       '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' +
                                                       '(/0*([1-9]|[12][0-9]|3[0-2]))?$'
    [String]$LabelsUri                               = '/rest/labels'
    [String]$LabelsResourcesBaseUri                  = '/rest/labels/resources'
    [String]$ApplianceSnmpV3TrapDestUri              = '/rest/appliance/snmpv3-trap-forwarding/destinations'
    [String]$ApplianceSnmpV3UsersUri                 = '/rest/appliance/snmpv3-trap-forwarding/users'
    [String]$ApplianceSnmpV1TrapDestUri              = '/rest/appliance/trap-destinations'
    [String]$ApplianceSnmpV1TrapDestValidationUri    = '/rest/appliance/trap-destinations/validation'
    [String]$ApplianceSnmpV3TrapDestUri              = '/rest/appliance/snmpv3-trap-forwarding/destinations'
    [String]$ApplianceSnmpV3TrapDestValidationUri    = '/rest/appliance/snmpv3-trap-forwarding/destinations/validation'
    [String]$ApplianceSnmpV3EngineIdUri              = '/rest/global-settings/appliance/global/applianceSNMPv3EngineId'
    [Regex]$ApplianceSnmpV3EngineIdValidationPattern = '^[A-Za-z0-9]{16}$'
    [String]$ApplianceFixmeLogsDownloadUri           = '/rest/fixme-logs/download'

#------------------------------------
# Remote Support
#------------------------------------
    [String]$RemoteSupportUri                         = '/rest/support'
    [String]$RemoteSupportConfigUri                   = '/rest/support/configuration'
    [String]$RemoteSupportRegistrationUri             = '/rest/support/registration'
    [String]$RemoteSupportContactsUri                 = '/rest/support/contacts'
    [String]$RemoteSupportSitesUri                    = '/rest/support/sites'
    [String]$RemoteSupportDefaultSitesUri             = '/rest/support/sites/default'
    [String]$ServerHardwareRemoteSupportSettingsUri   = '/rest/support/server-hardware'
    [String]$EnclosureRemoteSupportSettingsUri        = '/rest/support/server-hardware'
    [String]$RemoteSupportDataCollectionsUri          = '/rest/support/data-collections'
    [String]$RemoteSupportDataCollectionsDownloadUri  = '/rest/support/data-collections/download'
    [String]$InsightOnlinePortalRegistraionUri        = '/rest/support/portal-registration'
    [String]$RemoteSupportChannelPartnersUri          = '/rest/support/channel-partners'
    [String]$RemoteSupportChannelPartnersValidatorUri = '/rest/support/channel-partners/validator'
    [String]$RemoteSupportDataCollectionScheduleUri   = '/rest/support/schedules'
    [String]$RemoteSupportComputeSettingsUri          = '/rest/support/server-hardware'
    [String]$RemoteSupportEnclosureSettingsUri        = '/rest/support/enclosures'
    [HashTable]$RemoteSupportResourceSettingEnum      = @{
        'salesChannelPartnerUri'   = 'SalesChannelPartner';
        'supportChannelPartnerUri' = 'SupportChannelPartner';
        'primaryContactUri'        = 'PrimaryContact'; 
        'secondaryContactUri'      = 'SecondaryContact'
    }
    [Hashtable]$RemoteSupportCollectionEnum           = @{
        'AHS'   = 'AHS';
        'Basic' = 'Basic'
    }
    [Array]$RemoteSupportUris                         = @(
        $RemoteSupportUri,
        $RemoteSupportConfigUri,
        $RemoteSupportRegistrationUri,
        $RemoteSupportContactsUri,
        $RemoteSupportSitesUri,
        $RemoteSupportDefaultSitesUri
    )
#------------------------------------
# Remote Technician
#------------------------------------
    [String]$RemoteTechnicianUri                                  = '/rest/appliance/rda-cas'
    [String]$RemoteTechnicianAclUri                               = '{0}/access-control' -f $RemoteTechnicianUri
    [String]$RemoteTechnicianActiveTechniciaConnectionsUri        = '{0}/connections' -f $RemoteTechnicianUri
    [String]$RemoteTechnicianActiveApplianceConnectivityStatusUri = '{0}/connectivity' -f $RemoteTechnicianUri
    [String]$RemoteTechnicianAgentInfoUri                         = '{0}/info' -f $RemoteTechnicianUri
    [String]$RemoteTechnicianConnectivitySessionsUri              = '{0}/sessions' -f $RemoteTechnicianUri
    [String]$RemoteTechnicianTunnelSessionsUri                    = '{0}/tunnel' -f $RemoteTechnicianUri
#------------------------------------
# Image Streamer (I3S) Management
#------------------------------------
    [String]$DeploymentServersUri          = '/rest/deployment-servers' # Mapped to Get-HPOVOSDeploymentServer?
    [String]$AvailableDeploymentServersUri = '/rest/deployment-servers/image-streamer-appliances' # Mapped to Show-HPOVImageStreamer?
    [String]$DeploymentPlansUri            = '/rest/os-deployment-plans/' # Mapped to Get-HPOVOsDeploymentPlan
#------------------------------------
# Server Resource Management
#------------------------------------
    [String]$CClassEnclosureTypeUri              = "/rest/enclosure-types/c7000"
    [String]$SynergyEnclosureTypeUri             = "/rest/enclosure-types/SY12000"
    [String]$ServerHardwareUri                   = "/rest/server-hardware"
    [String]$ServerHardwareFirmwareComplianceUri = '{0}/firmware-compliance' -f $ServerHardwareUri
    [String]$ServerHardwareTypesUri              = "/rest/server-hardware-types"
    [String]$EnclosuresUri                       = "/rest/enclosures"
    [String]$LogicalEnclosuresUri                = '/rest/logical-enclosures'
    [String]$EnclosureGroupsUri                  = "/rest/enclosure-groups"
    [String]$EnclosureGroupType                  = 'EnclosureGroupV8'
    [String]$EnclosurePreviewUri                 = "/rest/enclosure-preview"
    [String]$VCMigratorUri                       = "/rest/migratable-vc-domains"
    [String]$ApplianceFwBundlesUri               = "/rest/firmware-bundles"
    [String]$ApplianceFwCompSigUri               = "/rest/firmware-bundles/addCompsig?uploadfilename={0}"
    [String]$ApplianceFwDriversUri               = "/rest/firmware-drivers"
    [String]$RackManagerUri                      = '/rest/rack-managers'
    [String]$PowerDevicesUri                     = "/rest/power-devices"
    [String]$PowerDevicesDiscoveryUri            = "/rest/power-devices/discover"
    [String]$PowerDevicePotentialConnections     = "/rest/power-devices/potentialConnections?providerUri="
    [String]$UnmanagedDevicesUri                 = "/rest/unmanaged-devices?sort=name:asc"
    [PSCustomObject]$MpModelTable                   = @{
        ilo2 = "RI7";
        ilo3 = "RI9";
        ilo4 = "RI10"
        iLO5 = "RI11"
    }
    [HashTable]$Script:ServerPowerControlEnum       = @{

        PressAndHold   = 'PressAndHold';
        MomentaryPress = 'MomentaryPress';
        ColdBoot       = 'ColdBoot';
        Reset          = 'Reset'

    }
    [String]$SyngergyEnclosureTypeUri               = '/rest/enclosure-types/SY12000'
    [String]$C7000EnclosureTypeUri                  = '/rest/enclosure-types/c7000'
    [Hashtable]$EnclosureGroupIpAddressModeEnum     = @{

        DHCP        = 'DHCP';
        External    = 'External';
        AddressPool = 'IpPool'

    }
    [Hashtable]$FramePowerModeEnum                  = @{

        RedundantPowerSupply = 'RedundantPowerSupply';
        RedundantPowerFeed   = 'RedundantPowerFeed'

    }
    [Hashtable]$FrameAmbientTemperatureEnum         = @{
        
        'ASHRAE_A3' = 'ASHRAE_A3';    
        'ASHRAE_A4' = 'ASHRAE_A4';
        'Standard'  = 'Standard';
        'Telco'     = 'Telco'
    }
    [Hashtable]$LogicalEnclosureFirmwareUpdateMethodEnum = @{
        EnclosureOnly                         = 'EnclosureOnly';
        SharedInfrastructureOnly              = 'SharedInfrastructureOnly';
        SharedInfrastructureAndServerProfiles = 'SharedInfrastructureAndServerProfiles'
    }
    [Hashtable]$LogicalInterconnectUpdateModeEnum = @{
        Orchestrated = 'Orchestrated';
        Parallel     = 'Parallel'
    }
    [Hashtable]$ServerHardwareOneTimeBootEnum = @{ 
        Normal   = 'Normal'; 
        CD       = 'CDROM'; 
        USB      = 'USB'; 
        HardDisk = 'HDD'; 
        PXE      = 'NETWORK'; 
        CDROM    = 'CD'; 
        HDD      = 'HardDisk'; 
        NETWORK  = 'PXE' 
    }
#------------------------------------
# Storage Resource Management
#------------------------------------
    [String]$SasLogicalInterconnectType                     = 'sas-logical-interconnectV2'
    [String]$SasLogicalInterconnectCategory                 = 'sas-logical-interconnect'
    [String]$SasLogicalInterconnectGroupType                = 'sas-logical-interconnect-groupV2'
    [String]$SasLogicalInterconnectGroupCategory            = 'sas-logical-interconnect-groups'
    [String]$DriveEnclosureUri                              = '/rest/drive-enclosures'
    [String]$script:SasInterconnectTypeUri                  = '/rest/sas-interconnect-types'
    [String]$script:SasInterconnectsUri                     = '/rest/sas-interconnects'
    [String]$SasLogicalInterconnectsUri                     = '/rest/sas-logical-interconnects'
    [String]$script:SasLogicalInterconnectGroupsUri         = '/rest/sas-logical-interconnect-groups'
    [String]$StorageSystemsUri                              = "/rest/storage-systems"
    [String]$StorageVolumesUri                              = "/rest/storage-volumes"
    [String]$StorageVolumeFromSnapshotUri                   = '/rest/storage-volumes/from-snapshot'
    [String]$StoragePoolsUri                                = "/rest/storage-pools"
    [String]$ReachableStoragePoolsUri                       = '/rest/storage-pools/reachable-storage-pools'
    [String]$AttachableStorageVolumesUri                    = '/rest/storage-volumes/attachable-volumes'
    [String]$script:StorageVolumeTemplateUri                = "/rest/storage-volume-templates"
    [String]$script:ApplStorageVolumeTemplateRequiredPolicy = '/rest/global-settings/appliance/global/StorageVolumeTemplateRequired'
    [String]$script:fcSanManagerProvidersUri                = "/rest/fc-sans/providers"  # List available SAN Manager plugins, and create SAN Manager
    [Hashtable]$StorageVolumeProvisioningTypeEnum           = @{
        'Thin'              = 'Thin';
        'Full'              = 'Full';
        'ThinDeduplication' = 'Thin Deduplication'
    }
    [Hashtable]$SnmpAuthLevelEnum                           = @{
        None        = "noauthnopriv";
        AuthOnly    = "authnopriv";
        AuthAndPriv = "authpriv"
    }
    [Hashtable]$Snmpv3UserAuthLevelEnum                     = @{
        None        = "None";
        AuthOnly    = "Authentication";
        AuthAndPriv = "Authentication and privacy"
    }
    [Hashtable]$SnmpAuthProtocolEnum                            = @{

        'none'   = 'none';
        'md5'    = 'MD5';
        'SHA'    = 'SHA';
        'sha1'   = 'SHA1';
        'sha2'   = 'SHA2';
        'sha256' = 'SHA256';
        'sha384' = 'SHA384';
        'sha512' = 'SHA512'

    }
    [Hashtable]$SnmpPrivProtocolEnum                            = @{
        'none'    = 'none';    
        'aes'     = "AES128";
        'aes-128' = "AES128";
        'aes-192' = "AES192";
        'aes-256' = "AES256";
        'aes128'  = "AES128";
        'aes192'  = "AES192";
        'aes256'  = "AES256";
        'des56'   = "DES56";
        '3des'    = "3DES";
        'tdea'    = 'TDEA'
    }
    [Hashtable]$ApplianceSnmpV3PrivProtocolEnum             = @{
        'none'   = 'none';
        "des56"  = 'DES';
        '3des'   = '3DES';
        'aes128' = 'AES-128';
        'aes192' = 'AES-192';
        'aes256' = 'AES-256'
    }
    [String]$script:FcSanManagersUri                        = "/rest/fc-sans/device-managers" # Created SAN Managers
    [String]$script:FcManagedSansUri                        = "/rest/fc-sans/managed-sans" # Discovered managed SAN(s) that the added SAN Manager will manage
    [String]$script:FcZonesUri                              = '/rest/fc-sans/zones'
    [String]$Script:SanEndpoints                            = '/rest/fc-sans/Endpoints'
    [RegEx]$Script:iQNPattern                               = '^(?:iqn\.[0-9]{4}-[0-9]{2}(?:\.[A-Za-z](?:[A-Za-z0-9\-]*[A-Za-z0-9])?)+(?::.*)?|eui\.[0-9A-Fa-f]{16})'
    [RegEx]$StoreServeTargetPortIDPattern                   = '\d:\d:\d'
    [Hashtable]$StorageVolShareableEnum                     = @{

        Private = $false;
        Shared  = $true

    }
    [Hashtable]$StorageSystemFamilyTypeEnum                 = @{
        StoreVirtual = 'StoreVirtual';
        StoreServ    = 'StoreServ';
        Nimble       = 'Nimble'
    }
    [Hashtable]$Global:StorageSystemPortModeEnum            = @{

        AutoSelectExpectedSan = 'Auto';
        Ignore                = 'Ignore';
        Managed               = 'Managed'

    }
    [Hashtable]$StorageVolumeProvisioningTypeEnum           = @{
        Full = 'Full';
        Thin = 'Thin';
        TPDD = 'Thin'
    }
    [Hashtable]$DataProtectionLevelEnum                     = @{
        NetworkRaid0None         = 'NetworkRaid0None';
        NetworkRaid5SingleParity = 'NetworkRaid5SingleParity';
        NetworkRaid10Mirror2Way  = 'NetworkRaid10Mirror2Way';
        NetworkRaid10Mirror3Way  = 'NetworkRaid10Mirror3Way';
        NetworkRaid10Mirror4Way  = 'NetworkRaid10Mirror4Way';
        NetworkRaid6DualParity   = 'NetworkRaid6DualParity'
    }
#------------------------------------
# Network Resource Management
#------------------------------------
    [String]$LogicalInterconnectGroupType        = 'logical-interconnect-groupV7'
    [String]$LogicalInterconnectGroupCategory    = 'logical-interconnect-groups'
    [String]$InterconnectLinkTopologies          = '/rest/interconnect-link-topologies'
    [String]$NetworkSetsUri                      = "/rest/network-sets"
    [String]$NetworkSetType                      = 'network-setV5'
    [String]$EthernetNetworksUri                 = "/rest/ethernet-networks"
    [String]$EthernetNetworkType                 = "ethernet-networkV4"
    [String]$EthernetNetworkBulkType             = "bulk-ethernet-networkV2"
    [String]$FCNetworksUri                       = "/rest/fc-networks"
    [String]$FCNetworkType                       = "fc-networkV4"
    [String]$FCoENetworksUri                     = "/rest/fcoe-networks"
    [String]$FCoENetworkType                     = "fcoe-networkV4"
    [String]$ConnectionTemplatesUri              = "/rest/connection-templates"
    [String]$LogicalInterconnectGroupsUri        = "/rest/logical-interconnect-groups"
    [String]$LogicalInterconnectsUri             = "/rest/logical-interconnects"
    [String]$InterconnectsUri                    = "/rest/interconnects"
    [String]$InterconnectTypesUri                = '/rest/interconnect-types'
    [String]$UplinkSetsUri                       = "/rest/uplink-sets"
    [String]$LogicalDownlinksUri                 = "/rest/logical-downlinks"
    [String]$SwitchTypesUri                      = '/rest/switch-types'
    [String]$LogicalSwitchGroupsUri              = '/rest/logical-switch-groups'
    [String]$LogicalSwitchesUri                  = '/rest/logical-switches'
    [String]$SwitchesUri                         = '/rest/switches'
    [String]$FabricManagersUri                   = '/rest/fabric-managers'
    [String]$DomainFabrics                       = '/rest/fabrics'
    [Hashtable]$LogicalSwitchManagementLevelEnum = @{ 
        Managed         = 'BASIC_MANAGED'; 
        Monitored       = 'MONITORED'; 
        ManagedSnmpV3   = 'BASIC_MANAGED'; 
        MonitoredSnmpV3 = 'MONITORED'
    }
    [String]$ApplianceVmacPoolsUri             = '/rest/id-pools/vmac'
    [String]$ApplianceVmacPoolRangesUri        = '/rest/id-pools/vmac/ranges'
    [String]$ApplianceVwwnPoolsUri             = '/rest/id-pools/vwwn'
    [String]$ApplianceVwwnPoolRangesUri        = '/rest/id-pools/vwwn/ranges'
    [String]$ApplianceVsnPoolsUri              = '/rest/id-pools/vsn'
    [String]$ApplianceVsnPoolRangesUri         = '/rest/id-pools/vsn/ranges'
    [String]$ApplianceIPv4PoolsUri             = '/rest/id-pools/ipv4'
    [String]$ApplianceIPv4SubnetsUri           = '/rest/id-pools/ipv4/subnets'
    [String]$ApplianceIPv4PoolRangesUri        = '/rest/id-pools/ipv4/ranges'
    [String]$ApplianceIPv6PoolsUri             = '/rest/id-pools/ipv6'
    [String]$ApplianceIPv6SubnetsUri           = '/rest/id-pools/ipv6/subnets'
    [String]$ApplianceIPv6PoolRangesUri        = '/rest/id-pools/ipv6/ranges'
    [String]$ApplianceVmacGenerateUri          = '/rest/id-pools/vmac/generate'
    [String]$ApplianceVwwnGenerateUri          = '/rest/id-pools/vwwn/generate'
    [String]$ApplianceVsnPoolGenerateUri       = '/rest/id-pools/vsn/generate'
    [Regex]$MacAddressPattern                  = '^(?:[A-Fa-f0-9]{2}[:-]){5}(?:[A-Fa-f0-9]{2})$'
    [Regex]$WwnAddressPattern                  = '^([0-9a-fA-F]{2}:){7}([0-9a-fA-F]{2})$'
    [Regex]$WwnLongAddressPattern              = '^([0-9a-fA-F]{2}:){15}([0-9a-fA-F]{2})$'
    [RegEx]$IPv4AddressPattern                 = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"
    [RegEx]$SnmpV3EngineIdPattern              = "^10x([A-Fa-f0-9]{2}){5,32}"
    [HashTable]$Global:FCNetworkFabricTypeEnum = @{

        FA           = 'FabricAttach';
        FabricAttach = 'FabricAttach';
        DA           = 'DirectAttach';
        DirectAttach = 'DirectAttach'

    }
    [Hashtable]$global:GetUplinkSetPortSpeeds    = @{
        Speed0M   = "0";
        Speed100M = "100Mb";
        Speed10G  = "10Gb";
        Speed10M  = "10Mb";
        Speed1G   = "1Gb";
        Speed1M   = "1Mb";
        Speed20G  = "20Gb";
        Speed2G   = "2Gb";
        Speed2_5G = "2.5Gb";
        Speed40G  = "40Gb";
        Speed4G   = "4Gb";
        Speed8G   = "8Gb";
        Auto       = "Auto"
    }
    [Hashtable]$global:SetUplinkSetPortSpeeds    = @{
        '0'    = "Speed0M";
        '100M' = "Speed100M";
        '100'  = "Speed100M";
        '10G'  = "Speed10G";
        '10'   = "Speed10G";
        '10M'  = "Speed10M";
        '1G'   = "Speed1G";
        '1'    = "Speed1G";
        '1M'   = "Speed1M";
        '20G'  = "Speed20G";
        '2G'   = "Speed2G";
        '2'    = "Speed2G";
        '2.5G' = "Speed2_5G";
        '40G'  = "Speed40G";
        '4G'   = "Speed4G";
        '8G'   = "Speed8G";
        '4'    = "Speed4G";
        '8'    = "Speed8G";
        'Auto' = "Auto"
    }
    [Hashtable]$global:LogicalInterconnectConsistencyStatusEnum = @{

        'CONSISTENT'     = "Consistent" ;
        'NOT_CONSISTENT' = "Inconsistent with group" 

    }
    [Array]$IngressDscpClassMappingEnum                       = @('DSCP 18, AF21','DSCP 20, AF22','DSCP 22, AF23','DSCP 26, AF31','DSCP 28, AF32','DSCP 30, AF33','DSCP 34, AF41','DSCP 36, AF42','DSCP 38, AF43','DSCP 16, CS2','DSCP 24, CS3','DSCP 32, CS4','DSCP 10, AF11','DSCP 12, AF12','DSCP 14, AF13','DSCP 8, CS1','DSCP 0, CS0','DSCP 46, EF','DSCP 40, CS5','DSCP 48, CS6','DSCP 56, CS7')
    [Hashtable]$Global:UplinkSetNetworkTypeEnum               = @{

        Ethernet      = 'Ethernet';
        FibreChannel  = 'FibreChannel';
        Untagged      = 'Ethernet';
        Tunnel        = 'Ethernet';
        ImageStreamer = 'Ethernet'

    }
    [Hashtable]$Global:UplinkSetEthNetworkTypeEnum            = @{

        Ethernet      = 'Tagged'
        Untagged      = 'Untagged'
        Tunnel        = 'Tunnel'
        ImageStreamer = 'ImageStreamer'

    }
    [Hashtable]$Global:LogicalInterconnectGroupRedundancyEnum = @{

        HighlyAvailable = 'HighlyAvailable';
        ASide           = 'NonRedundantASide';
        BSide           = 'NonRedundantBSide';
        Redundant       = 'Redundant'

    }
    [Array]$Script:SnmpEneTrapCategoryEnums                   = @('Other', 'PortStatus', 'PortThresholds')
    [Array]$Script:SnmpFcTrapCategoryEnums                    = @('Other', 'PortStatus')
    [Array]$Script:SnmpVcmTrapCategoryEnums                   = @('Legacy')
    [Array]$Script:SnmpTrapSeverityEnums                      = @('Critical', 'Info', 'Major', 'Minor', 'Normal', 'Unknown', 'Warning')
    [Net.IPAddress]$Script:ExcludedIPSubnetID                 = '172.30.254.0' # Synergy Specific
    [Net.IPAddress]$Script:ExcludedIPSubnetEnd                = '172.30.254.254' # Synergy Specific
    [Hashtable]$EthernetNetworkPurposeEnum = @{

        General        = "General";
        Management     = "Management";
        VMMigration    = "VMMigration";
        FaultTolerance = "FaultTolerance";
        ISCSI          = 'ISCSI'

    }
    [String]$FabricManagersUri = '/rest/fabric-managers'
    [Array]$FCTrunkCapablePartnumbers = @(

        '751465-B21',
        '779227-B21',
        '876259-B21',
        'P08477-B21'

    )
    [Array]$SynergyVCEthModulePartNumbers = @(
        
        '794502-B23'

    )
    [Hashtable]$LIGConsistencyCheckingEnum = @{

        Exact   = 'ExactMatch';
        None    = 'NotChecked'

    }
#------------------------------------
# Profile Management
#------------------------------------

    [String]$ServerProfileType                          = "ServerProfileV11"
    [String]$ServerProfilesCategory                     = $ResourceCategoryEnum.ServerProfile
    [String]$ServerProfileTemplateType                  = "ServerProfileTemplateV7"
    [String]$ServerProfileTemplatesCategory             = 'server-profile-templates'
    [String]$ServerProfilesUri                          = "/rest/{0}" -f $ServerProfilesCategory
    [String]$ServerProfileTemplatesUri                  = '/rest/{0}?sort=name:asc' -f $ServerProfileTemplatesCategory
    [String]$ServerProfileIndexListUri                  = "/rest/index/resources?sort=name:asc&category={0}" -f $ServerProfilesCategory
    [String]$ServerProfileAvailStorageSystemsUri        = '/rest/{0}/available-storage-systems' -f $ServerProfilesCategory
    [String]$ServerProfilesAvailableNetworksUri         = '/rest/{0}/available-networks' -f $ServerProfilesCategory
    [Hashtable]$ServerProfileConnectionBootPriorityEnum = @{ 
        none           = 'NotBootable'; 
        NotBootable    = 'NotBootable'; 
        Primary        = 'Primary'; 
        Secondary      = 'Secondary'; 
        IscsiPrimary   = 'Primary'; 
        IscsiSecondary = 'Secondary';
        LoadBalanced   = 'LoadBalanced'
    }
    [Hashtable]$ServerProfileSanManageOSType            = @{
        CitrixXen  = "Citrix Xen Server 5.x/6.x";
        CitrisXen7 = "Citrix Xen Server 7.x";
        AIX        = "AIX";
        IBMVIO     = "IBM VIO Server";
        RHEL4      = "RHE Linux (Pre RHEL 5)";
        RHEL3      = "RHE Linux (Pre RHEL 5)";
        RHEL       = "RHE Linux (5.x, 6.x, 7.x)";
        RHEV       = "RHE Virtualization (5.x, 6.x)";
        RHEV7      = "RHE Virtualization 7.x";
        VMware     = "VMware (ESXi)";
        Win2k3     = "Windows 2003";
        Win2k8     = "Windows 2008/2008 R2";
        Win2k12    = "Windows 2012 / WS2012 R2";
        Win2k16    = "Windows Server 2016";
        OpenVMS    = "OpenVMS";
        Egenera    = "Egenera";
        Exanet     = "Exanet";
        Solaris9   = "Solaris 9/10";
        Solaris10  = "Solaris 9/10";
        Solaris11  = "Solaris 11";
        ONTAP      = "NetApp/ONTAP";
        OEL        = "OE Linux UEK (5.x, 6.x)";
        OEL7       = "OE Linux UEK 7.x";
        HPUX11iv1  = "HP-UX (11i v1, 11i v2)"
        HPUX11iv2  = "HP-UX (11i v1, 11i v2)";
        HPUX11iv3  = "HP-UX (11i v3)";
        SUSE       = "SuSE (10.x, 11.x, 12.x)";
        SUSE9      = "SuSE Linux (Pre SLES 10)";
        Inform     = "InForm"
    }
    [Hashtable]$ServerProfileConnectionTypeEnum         = @{

        'ethernet-networks' = 'Ethernet';
        'network-sets'      = 'Ethernet';
        'fcoe-networks'     = 'FibreChannel';
        'fc-networks'       = 'FibreChannel';
        'FC'                = 'FibreChannel';
        'FibreChannel'      = 'FibreChannel';
        'FCoE'              = 'FibreChannel';
        'Eth'               = 'Ethernet';
        'Ethernet'          = 'Ethernet';
        'iSCSI'             = 'iSCSI'

    }
    [Hashtable]$LogicalDiskTypeEnum                     = @{

        'Sas'     = 'SasHdd';
        'SASHDD'  = 'SasHdd';
        'Sata'    = 'SataHdd';
        'SATAHDD' = 'SataHdd';
        'Sasssd'  = 'SasSsd';
        'Satassd' = 'SataSsd';
        'Auto'    = $Null

    }
    [Hashtable]$ServerProfileFirmwareControlModeEnum    = @{

        FirmwareOnly            = 'FirmwareOnly';
        FirmwareAndSoftware     = 'FirmwareAndOSDrivers';
        FirmwareOffline         = 'FirmwareOnlyOfflineMode';
        FirmwareAndOSDrivers    = 'FirmwareAndOSDrivers';
        FirmwareOnlyOfflineMode = 'FirmwareOnlyOfflineMode'

    }
    [Hashtable]$ServerProfileFirmareActivationModeEnum  = @{
        Immediate    = 'Immediate';
        NotScheduled = 'NotScheduled';
        Scheduled    = 'Scheduled'
    }
    [Hashtable]$IscsiInitiatorNameAssignmetEnum         = @{
        Virtual     = 'AutoGenerated';
        UserDefined = 'UserDefined'
    }
    [Hashtable]$ConsistencyCheckingEnum = @{

        Exact   = 'Checked';
        None    = 'Unchecked';
        Minimum = 'CheckedMinimum'

    }
#------------------------------------
# Cluster Profile Management
#------------------------------------
    [String]$ClusterProfileType                         = 'HypervisorClusterProfileV3'
    [String]$ClusterProfileHostType                     = 'HypervisorHostProfileV2'
    [String]$ClusterProfileHostCategory                 = 'hypervisor-host-profiles'
    [String]$ClusterProfilesUri                         = '/rest/hypervisor-cluster-profiles'
    [Hashtable]$ClusterProfileHostPowerStateEnum        = @{
        On                 = 'On';
        Off                = 'Off';
        InMaintenanceMode  = 'InMaintenance';
        ExitMaintenaneMode = 'ExitMaintenance'
    }
    [String]$ClusterHostProfilesUri                     = '/rest/hypervisor-host-profiles'
    [String]$ClusterProfileCompliancePreviewUri         = '/rest/hypervisor-cluster-profiles/{0}/compliance-preview'
    [String]$HypervisorManagersUri                      = '/rest/hypervisor-managers'
    [String]$HypervisorClustersUri                      = '/rest/hypervisor-clusters'
    [String]$GenerateClusterProfileNetworkingLayoutUri  = '/rest/hypervisor-cluster-profiles/virtualswitch-layout'
    [Hashtable]$ClusterProfileDistributedSwitchTypeEnum = @{
        Distributed = 'Distributed';
        Standard    = 'Standard'
    }
    $ClusterProfileComplianceStateEnum = [PSCustomObject]@{
        ClusterConfigInconsistent = [PSCustomObject] @{
            State   = 'ClusterConfigInconsistent';
            Message = 'Hypervisor cluster is inconsistent hypervisor cluster profile. '
        };
        ClusterTemplateError = [PSCustomObject] @{
            State   = 'ClusterTemplateError';
            Message = 'Hypervisor cluster profile is out of sync with server profile template connections and volumes.'
        };
        ClusterTemplateStorageVolError = [PSCustomObject] @{
            State   = 'ClusterTemplateStorageVolError';
            Message = 'Hypervisor cluster profile is out of sync with server profile template volumes.' 
        };
        ClusterTemplateVSwitchError = [PSCustomObject]@{
            State   = 'ClusterTemplateVSwitchError';
            Message = 'Hypervisor cluster profile is out of sync with server profile template connections.'
        };
        Consistent = [PSCustomObject]@{
            State   = 'Consistent';
            Message = 'Cluster or Hypervisor profile is consistent with its template.'
        };
        HostProfileInconsistent = [PSCustomObject]@{
            State   = 'HostProfileInconsistent';
            Message = 'Hypervisor profile is inconsistent with host profile template.'
        };
        Inconsistent = [PSCustomObject]@{
            State   = 'Inconsistent';
            Message = 'Hypervisor Profile is inconsistent with its template. Remediate Indicates cluster of hypervisor profile should be made consistent with its template.'
        };
        ServerProfileInconsistent = [PSCustomObject]@{
            State   = 'ServerProfileInconsistent';
            Message = 'Server profile is inconsistent with server profile template.'
        };
        Unknown      = [PSCustomObject]@{
            State   = 'Unknown';
            Message = 'Unable to determine compliance state of profile.'
        }
    }
#------------------------------------
# Datacenter/Facilities
#------------------------------------
    [String]$DataCentersUri     = '/rest/datacenters'
    [String]$DataCenterRacksUri = '/rest/racks'
#------------------------------------
# Index Search
#------------------------------------
    [String]$IndexUri                    = "/rest/index/resources" 
    [String]$AssociationsUri             = "/rest/index/associations"
    [String]$IndexAssociatedResourcesUri = '{0}/resources' -f $AssociationsUri
    [String]$AssociationTreesUri         = "/rest/index/trees"
#------------------------------------
# Tasks
#------------------------------------
    [String]$AllNonHiddenTaskUri    = "/rest/tasks?filter=hidden=$false"
    [String]$TasksUri               = "/rest/tasks"
    [Array]$TaskFinishedStatesEnum  = @(
        
        "Error",
        "Warning",
        "Completed",
        "Terminated",
        "Killed"
        
    ) 
#------------------------------------
# Alerts and Events
#------------------------------------
    $AlertsUri                   = "/rest/alerts"
    $script:eventsUri            = "/rest/events"
    [String]$SmtpConfigUri       = "/rest/appliance/notifications/email-config"
    [String]$TestNotificationUri = "/rest/appliance/notifications/send-email"
    [String]$HtmlPattern         = "</?\w+((\s+\w+(\s*=\s*(?:`".*?`|'.*?'|[\^'`">\s]+))?)+\s*|\s*)/?>"
    [Hashtable]$SmtpConnectionSecurityEnum = @{

        None     = 'PLAINTEXT';
        Tls      = 'TLS';
        StartTls = 'STARTTLS'

    }
#------------------------------------
# Licenses
#------------------------------------
    $ApplianceLicensePoolUri = "/rest/licenses"
#------------------------------------
# Security
#------------------------------------
    [String]$ApplianceSecurityModesUri                  = '/rest/security-standards/modes'
    [String]$ApplianceCurrentSecurityModeUri            = '/rest/security-standards/modes/current-mode'
    [String]$ApplianceSecurityModeCompatibiltyReportUri = '/rest/security-standards/compatibility-report'
    [String]$ApplianceSecurityProtocolsUri              = '/rest/security-standards/protocols'
    [String]$UserLoginSessionUri                        = '/rest/sessions'
    [String]$ApplianceLoginSessionsUri                  = '/rest/login-sessions'
    [String]$ApplianceLoginSessionsSmartCardAuthUri     = '/rest/login-sessions/smartcards'
    [String]$UpdateApplianceSessionAuthUri              = '/rest/login-sessions/auth-token'
    [String]$ActiveUserSessionsUri                      = '/rest/active-user-sessions'
    [String]$ApplianceUserAccountsUri                   = '/rest/users'
    [String]$ApplianceUserAccountRoleUri                = "/rest/users/role"
    [String]$ApplianceTrustedCertStoreUri               = '/rest/certificates'
    [String]$ApplianceCertificateValidatorUri           = '/rest/certificates/validator-configuration'
    [String]$ApplianceCertificateAuthorityUri           = '/rest/certificates/ca'
    [String]$ApplianceInternalCertificateAuthority      = '/rest/certificates/ca?filter=certType:INTERNAL'
    [String]$ApplianceTrustedCAValidatorUri             = '/rest/certificates/ca/validator'
    [String]$ApplianceTrustedSslHostStoreUri            = '/rest/certificates/servers'
    [String]$ApplianceScmbRabbitmqUri                   = "/rest/certificates/client/rabbitmq"
    [String]$ApplianceRabbitMQKeyPairUri                = "/rest/certificates/client/rabbitmq/keypair/default"
    [String]$ApplianceRabbitMQKeyPairCertUri            = '/rest/certificates/ca/rabbitmq_readonly'
    [String]$RetrieveHttpsCertRemoteUri                 = "/rest/certificates/https/remote/"
    [String]$AuthnProvidersUri                          = '/rest/logindomains'
    [String]$Authn2FALoginCertificateConfigUri          = '/rest/logindomains/logincertificates'
    [String]$AuthnAllowLocalLoginUri                    = '/rest/logindomains/global-settings/allow-local-login'
    [String]$AuthnDefaultLoginDomainUri                 = '/rest/logindomains/global-settings/default-login-domain'
    [String]$AuthnProviderValidatorUri                  = "/rest/logindomains/validator"
    [String]$AuthnSettingsUri                           = "/rest/logindomains/global-settings"
    [String]$AuthnDirectoryGroupsUri                    = "/rest/logindomains/groups"
    [String]$AuthnDirectorySearchContextUri             = '/rest/logindomains/contexts'
    [String]$AuthnEgroupRoleMappingUri                  = "/rest/logindomains/grouptorolemapping"
    [String]$ApplAuditLogsUri                           = "/rest/audit-logs"
    [String]$ApplAuditLogDownloadUri                    = "/rest/audit-logs/download"
    [String]$ApplianceAuditLogForwardingUri             = '/rest/audit-logs/settings'
    [String]$ApplianceTestAuditLogForwardingUri         = '/rest/audit-logs/test-forwarding'
    [String]$ApplianceRolesUri                          = '/rest/roles'
    [String]$ApplianceLoginDomainDetailsUri             = '/rest/logindetails'
    [String]$ScopesUri                                  = '/rest/scopes'
    [String]$ApplianceServiceAccessUri                  = '/rest/appliance/settings/serviceaccess'
    [String]$ApplianceEnableServiceAccessUri            = '/rest/appliance/settings/enableServiceAccess'
    [String]$ApplianceSshAccessUri                      = '/rest/appliance/ssh-access'
    [Hashtable]$ScopeCategoryEnum                       = @{

        'enclosures'                  = 'Enclosure';
        'enclosure-groups'            = 'EnclosureGroup';
        'logical-enclosures'          = 'LogicalEnclosure';
        'server-hardware'             = 'ServerHardware';
        'network-sets'                = 'NetworkSet';
        'interconnects'               = 'Interconnect';
        'logical-interconnects'       = 'LogicalInterconnect';
        'logical-interconnect-groups' = 'LogicalInterconnectGroup';
        'ethernet-networks'           = 'EthernetNetwork';
        'fc-networks'                 = 'FCNetwork';
        'fcoe-networks'               = 'FCoENetwork';
        'logical-switches'            = 'LogicalSwitch';
        'logical-switch-groups'       = 'LogicalSwitchGroup';
        'switches'                    = 'Switch';
        'server-profiles'             = 'ServerProfile';
        'server-profile-templates'    = 'ServerProfileTemplate';
        'firmware-drivers'            = 'FirmwareBundle';
        'os-deployment-plans'         = 'OSDeploymentPlan';
        'storage-pools'               = 'StoragePool';
        'storage-volumes'             = 'StorageVolume';
        'storage-volume-templates'    = 'StorageVolumeTemplate';
        'scopes'                      = 'Scope';
        'hypervisor-managers'         = 'HypervisorManagers'
        'hypervisor-cluster-profiles' = 'ClusterProfile';
        'hypervisor-hosts'            = 'ClusterNode'

    }
    [Hashtable]$LdapDirectoryAccountBindTypeEnum    = @{
        USERACCOUNT    = 'USER_ACCOUNT';
        SERVICEACCOUNT = 'SERVICE_ACCOUNT'
    }
    [Hashtable]$TwoFactorLocalLoginTypeEnum         = @{
        NONE                          = 'NONE';
        APPLIANCECONSOLEONLY          = 'APPLIANCE_CONSOLE_ONLY';
        APPLIANCE_CONSOLE_ONLY        = 'APPLIANCECONSOLEONLY';
        NETWORK_AND_APPLIANCE_CONSOLE = 'NETWORKANDAPPLIANCECONSOLE';
        NETWORKANDAPPLIANCECONSOLE    = 'NETWORK_AND_APPLIANCE_CONSOLE'
    }
    $Script:OrganizationalUnitPattern = '^(?:(?:CN|OU|DC)\=[\w\s]+,)*(?:CN|OU|DC)\=[\w\s]+$'
    $CommonNamePattern                = '^CN=(.+?),(?:CN|OU)=.+'
    $JsonPasswordRegEx                = New-Object System.Text.RegularExpressions.Regex ('\"password\"\:[\s]*?\"(.*?)\"', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)

# Endregion

$WhiteListedURIs = @(

    $ApplianceLoginSessionsUri,
    $ApplianceLoginSessionsSmartCardAuthUri,
    $ApplianceUpdateMonitorUri,
    $ApplianceXApiVersionUri,
    "/ui-js/pages/",
    $ApplianceEulaStatusUri,
    $ApplianceEulaSaveUri,
    ($ApplianceUserAccountsUri + "/changePassword"),
    "/startstop/rest/component?fields=status",
    $ApplianceStartProgressUri,
    $ApplianceLoginDomainDetailsUri

)

$ExtendedTimeoutUris = @(
    $ApplianceSupportDumpUri,
    $ApplianceBackupUri,
    "$LogicalInterconnectsUri/*/support-dumps",
    $ApplianceScmbRabbitmqUri,
    $RemoteSupportUri
)

#######################################################
# Resource Objects
#

class ServerProfileUnmanagedFCConnection
{

    $id            = 1;
    $name          = $null;
    $functionType  = 'FibreChannel';
    $portId        = $null; 
    $networkUri    = $null; 
    $requestedMbps = $null; 
    $boot          = $null;
    $wwpn           = $null;
    $managed       = $false;

    ServerProfileUnmanagedFCConnection ([Object]$Object)
    {

        $this.id = $Object.id
        $this.name = $Object.name
        $this.networkUri = $Object.networkUri
        
        if (-not [String]::IsNullOrEmpty($Object.wwpn))
        {

            $this.managed = $null
            $this.wwpn = $Object.wwpn

        }
        
    }

}

function NewObject 
{

    [CmdletBinding ()]
    Param
    (

        [Object]$InputObject, 
        [Switch]$FabricManagerClusterNodeInfo,
        [Switch]$AddFabricManager,
        [Switch]$AddStorageVolume,
        [Switch]$AddRackManager,
        [Switch]$AlertFilter,
        [Switch]$AllApiResponse,
        [Switch]$ApplianceCSR,
        [Switch]$ApplianceDebug,
        [Switch]$ApplianceGlobalCertificateValidationConfig,
        [Switch]$ApplianceProxy,
        [Switch]$ApplianceSslCertificate,
        [Switch]$ApplianceSecurityProtocols,
        [Switch]$ApplianceTimeLocale,
        [Switch]$ApplianceTrustedCertAuthority,
        [Switch]$ApplianceTrustedSslCertificate,
        [Switch]$ApplianceVersion,
        [Switch]$AuthDirectory,
        [Switch]$AuthDirectoryServer,
        [Switch]$AuthLoginCredential,
        [Switch]$AutoBackupConfig,
        [Switch]$BaseTrafficClass,
        [Switch]$BulkEthernetNetworks,
        [Switch]$CertificateToImport,
        [Switch]$CertificateDetails,
        [Switch]$ClusterProfile,
        [Switch]$ClusterProfileManager,
        [Switch]$ClusterProfileSharedStorageVolume,
        [Switch]$ClusterVirtualSwitchConfig,
        [Switch]$ClusterProfileOverrideMgmtIPSettings,
        [Switch]$ClusterNetworkingSettings,
        [Switch]$ClusterNetworkingLayout,
        [Switch]$ClusterNetworkingConfigPolicy,
        [Switch]$ClusterProfileVirtualSwitchUplink,
        [Switch]$ClusterProfileVirtualSwitchPortGroup,
        [Switch]$ClusterProfileVirtualSwitchPort,
        [Switch]$ConvertSnapshotToVol,
        [Switch]$CustomBaselineRestore,
        [Switch]$DataCenter,
        [Switch]$DataCenterItem,
        [Switch]$DefaultBestEffortTrafficClass,
        [Switch]$DefaultFCoELosslessQosTrafficClassifiers,
        [Switch]$DefaultNoFCoELosslessQosTrafficClassifiers,
        [Switch]$DeploymentModeSettings,
        [Switch]$DirectoryGroup,
        [Switch]$DirectoryGroupPermissions,
        [Switch]$DirectoryGroupCredentials,
        [Switch]$DownloadFileStatus,
        [Switch]$EnclosureGroup,
        [Switch]$SynergyEnclosureGroup,
        [Switch]$EnclosureGroupPreview,
        [Switch]$EnclosureGroupI3SDeploymentSettings,
        [Switch]$EnclosureImport,
        [Switch]$EnclosureRefresh,
        [Switch]$EnclosureRefreshForceOptions,
        [Switch]$EphemeralStorageVolume,
        [Switch]$EthernetNetwork,
        [Switch]$EulaStatus,
        [Switch]$ExternalRepository,
        [Switch]$FCNetwork,
        [Switch]$FCoELossLessTrafficClass,
        [Switch]$FCoENetwork,
        [Switch]$FCAlias,
        [Switch]$FCZone,
        [Switch]$GlobalSetting,
        [Switch]$IPIDPoolRange,
        [Switch]$IDPoolStartStopFragment,
        [Switch]$IDPoolRange,
        [Switch]$I3SAdd,
        [Switch]$IloRestSession,
        [Switch]$IPv4Subnet,
        [Switch]$IPv6Subnet,
        [Switch]$InterconnectBayMapping,
        [Switch]$InterconnectMapEntryTemplate,
        [Switch]$InsightOnlineRegistration,
        [Switch]$IscsiBootEntry,
        [Switch]$IscsiIPv4Configuration,
        [Switch]$LogicalInterconnectBaseline,
        [Switch]$C7kLIG,
        [Switch]$SELIG,
        [Switch]$SESASLIG,
        [Switch]$LiUplinkSetObject,
        [Switch]$LigUplinkSetObject,
        [Switch]$LicenseKey,
        [Switch]$LocationEntry,
        [Switch]$LogicalEnclosure,
        [Switch]$LogicalEnclosureFirmareUpdate,
        [Switch]$LogicalSwitchGroup,
        [Switch]$LogicalSwitch,
        [Switch]$LogicalSwitchCredentials,
        [Switch]$LogicalSwitchSnmpV3Config,
        [Switch]$LogialSwitchConnectionProperties,
        [Switch]$LogicalSwitchConnectionProperty,
        [Switch]$LoginMessageObject,
        [Switch]$NetworkSet,
        [Switch]$NimbleEphemeralVolumeProperties,
        [Switch]$OSDeploymentSettings,
        [Switch]$OSDeploymentPlanSetting,
        [Switch]$PatchOperation,
        [Switch]$Ping,
        [Switch]$PowerDeliveryDeviceAdd,
        [Switch]$Rack,
        [Switch]$RackItem,
        [Switch]$RabbitmqCertReq,
        [Switch]$RemoteSupportConfig,
        [Switch]$RemoteSupportContact,
        [Switch]$RemoteSupportPartner,
        [Switch]$RemoteSupportSchedule,
        [Switch]$RemoteSupportSite,
        [Switch]$RemoteSyslog,
        [Switch]$ReservedVlanRange,
        [Switch]$QosConfiguration,
        [Switch]$SanManager,
        [Switch]$SanManagerConnectInfo,
        [Switch]$ScopeCollection,
        [Switch]$ScopeMemberUpdate,
        [Switch]$SecurityModeCompatabilityReport,
        [Switch]$SelfSignedCert,
        [Switch]$ServerImport,
        [Switch]$ServerProfile,
        [Switch]$ServerProfileBootMode,
        [Switch]$ServerProfileBootModeLegacyBios,
        [Switch]$ServerProfileEthernetConnection,
        [Switch]$ServerProfileIscsiConnection,
        [Switch]$ServerProfileFCConnection,
        [Switch]$ServerProfileUnmanagedFCConnection,
        [Switch]$ServerProfileEthBootableConnection,
        [Switch]$ServerProfileEthBootableConnectionWithTargets,
        [Switch]$ServerProfileIscsiBootableConnectionWithTargets,
        [Switch]$ServerProfileFcBootableConnection,
        [Switch]$ServerProfileConnectionFcBootTarget,
        [Switch]$ServerProfileLocalStorageController,
        [Switch]$ServerProfileLocalStorageLogicalDrive,
        [Switch]$ServerProfileSanStorage,
        [Switch]$ServerProfileTemplateSanStorage,
        [Switch]$ServerProfileSasLogicalJBOD,
        [Switch]$ServerProfileStorageVolume,
        [Switch]$ServerProfileTemplate,
        [Switch]$ServerProfileTemplateLocalStorage,
        [Switch]$SPTOSDeploymentSettings,
        [Switch]$SmtpConfig,
        [Switch]$SnmpConfig,
        [Switch]$SnmpTrapDestination,
        [Switch]$StoragePath,
        [Switch]$StorageSystemCredentials,
        [Switch]$StorageSystemManagedPort,
        [Switch]$StorageVolume,
        [Switch]$StorageVolumeTemplate,
        [Switch]$StoreVirtualEphemeralVolumeProperties,
        [Switch]$StoreServeEphemeralVolumeProperties,
        [Switch]$SwitchLogicalLocation,
        [Switch]$TemporaryConnection,
        [Switch]$TestSmtpConfig,
        [Switch]$UpdateAlert,
        [Switch]$UplinkSetLocation,
        [Switch]$UplinkSetLocationEntry,
        [Switch]$UplinkSetLogicalLocation,
        [Switch]$UplinkSetLogicalLocationEntry,
        [Switch]$UnmanagedDevice,
        [Switch]$UserAccount,
        [Switch]$UpdateUserPassword,
        [Switch]$UpdateToActivePermissions,
        [Switch]$VcMigration,
        [Switch]$VCMigratorReport,
        [Switch]$VolSnapshot

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {

        switch($PSBoundParameters.Keys)
        {

            'ServerProfileSanStorage'
            {
                
                Return [PSCustomObject]@{
                                
                    hostOSType        = $null;
                    manageSanStorage  = $false;
                    volumeAttachments = [System.Collections.ArrayList]::new()
                
                }
                
            }

            'ServerProfileTemplateSanStorage'
            {

                $_Object = NewObject -ServerProfileSanStorage
                $_Object | Add-Member -NotePropertyName complianceControl -NotePropertyValue $ConsistencyCheckingEnum.Exact
                Return $_Object

            }

            'ReservedVlanRange'
            {

                Return [PSCustomObject]@{
                    start  = 0;
                    length = 0;
                    type   = "vlan-pool"
                }

            }

            'AddRackManager'
            {

                return @{
                    hostname = $null;
                    username = $null;
                    password = $null;
                    force    = $false
                 }

            }

            'ApplianceSecurityProtocols'
            {

                Return @(  
                    @{
                        type = "ProtocolV1";
                        protocolName = "TLSv1";
                        enabled = $false
                    },
                    @{  
                        type = "ProtocolV1";
                        protocolName = "TLSv1.1";
                        enabled = $false
                    },
                    @{  
                        type = "ProtocolV1";
                        protocolName = "TLSv1.2";
                        enabled = $false
                    }
                )
            }

            'SecurityModeCompatabilityReport'
            {

                return [PSCustomObject]@{

                    currentMode = $null
                    targetMode  = $null
                    
                }

            }

            'LogicalEnclosureFirmareUpdate'
            {
                Return [PSCustomObject]@{

                    firmwareBaselineUri                       = $null;
                    firmwareUpdateOn                          = "SharedInfrastructureAndServerProfiles";
                    forceInstallFirmware                      = $false;
                    validateIfLIFirmwareUpdateIsNonDisruptive = $false;
                    logicalInterconnectUpdateMode             = "Orchestrated"

                }

            }

            'AddFabricManager'
            {

                Return [PSCustomObject]@{
                    name                         = $null;
                    fabricManagerType            = "Cisco ACI";
                    userName                     = $null;
                    password                     = $null;
                    fabricManagerClusterNodeInfo = New-Object 'System.Collections.Generic.List[PSCustomObject]'
                    type                         = "FabricManager"
                }
            
            }

            'FabricManagerClusterNodeInfo'
            {

                Return [PSCustomObject]@{

                    oobMgmtAddr = $null

                }

            }

            'ClusterProfile'
            {

                Return [PSCustomObject]@{
                    type                          = "HypervisorClusterProfileV3";
                    name                          = $null;
                    hypervisorManagerUri          = $null;
                    path                          = $null;
                    initialScopeUris              = New-Object 'System.Collections.Generic.List[String]';
                    description                   = "";
                    hypervisorType                = "Vmware";
                    hypervisorClusterSettings     = [PSCustomObject]@{ 
                        type                     = "Vmware";
                        drsEnabled               = $true;
                        haEnabled                = $false;
                        multiNicVMotion          = $false;
                        virtualSwitchType        = "Standard";
                        distributedSwitchUsage   = $null;
                        distributedSwitchVersion = $null
                    };
                    hypervisorHostProfileTemplate = [PSCustomObject]@{
                        serverProfileTemplateUri = $null;
                        deploymentPlan           = [PSCustomObject]@{
                            serverPassword       = $null
                            deploymentCustomArgs = New-Object 'System.Collections.Generic.List[PSCustomObject]';
                        };
                        hostprefix       = $null;
                        virtualSwitches  = New-Object 'System.Collections.Generic.List[PSCustomObject]';
                        hostConfigPolicy = [PSCustomObject]@{
                            leaveHostInMaintenance  = $false;
                            useHostPrefixAsHostname = $false;
                            useHostnameToRegister   = $false
                        };
                        virtualSwitchConfigPolicy = [PSCustomObject]@{
                            manageVirtualSwitches = $true;
                            configurePortGroups   = $true
                        }
            
                    };
                    addHostRequests               =     New-Object 'System.Collections.Generic.List[HPOneView.Cluster.AddHostRequest]';            
                    sharedStorageVolumes          =     New-Object 'System.Collections.Generic.List[PSCustomObject]';            
                
                }

            }

            'ClusterProfileOverrideMgmtIPSettings'
            {

                Return [PSCustomObject]@{

                    netmask      = $null;
                    gateway      = $null;
                    dnsDomain    = $null;
                    primaryDns   = $null;
                    secondaryDns = $null;
                    tertiaryDNS  = $null

                }

            }

            'ClusterProfileSharedStorageVolume'
            {

                Return [PSCustomObject]@{

                    storageVolumeUri     = $null;
                    volumeFileSystemType = $null

                }

            }

            'ClusterVirtualSwitchConfig'
            {

                Return [PSCustomObject]@{
                    name                    = $null;
                    virtualSwitchType       = "Standard";
                    version                 = $null;
                    virtualSwitchPortGroups = New-Object 'System.Collections.Generic.List[PSCustomObject]';
                    virtualSwitchUplinks    = New-Object 'System.Collections.Generic.List[PSCustomObject]';
                    action                  = "NONE";
                    networkUris             = New-Object 'System.Collections.Generic.List[String]';
                }

            }

            'ClusterProfileVirtualSwitchUplink'
            {

                Return [PSCustomObject]@{
                    name   = $null;
                    mac    = $null;
                    vmnic  = $null;
                    action = "NONE";
                    active = $false
                }

            }

            'ClusterProfileVirtualSwitchPortGroup'
            {

                Return [PSCustomObject]@{
                    name        = $null;
                    networkUris = New-Object 'System.Collections.Generic.List[String]';
                    vlan        = "0";
                    virtualSwitchPorts = @(
                        
                    );
                    action = "NONE"
                }

            }

            'ClusterProfileVirtualSwitchPort'
            {

                Return [PSCustomObject]@{
                    virtualPortPurpose = New-Object "System.Collection.Generic.List[String]";
                    ipAddress          = $null;
                    subnetMask         = $null;
                    dhcp               = $true;
                    action             = "NONE"
                }

            }

            'ClusterNetworkingLayout'
            {
                Return [PSCustomObject] @{ 
 
                    serverHardwareUri         = $null;
                    serverProfileTemplateUri  = $null;
                    hypervisorClusterSettings = NewObject -ClusterNetworkingSettings;
                    virtualSwitchConfigPolicy = NewObject -ClusterNetworkingConfigPolicy

                }

            }

            'ClusterNetworkingSettings'
            {

                Return [PSCustomObject] @{

                    multiNicVMotion          = $false;
                    virtualSwitchType        = "Standard";
                    distributedSwitchUsage   = $null;
                    distributedSwitchVersion = $null;
                    type                     = "Vmware"

                }
                
            }

            'ClusterNetworkingConfigPolicy'
            {

                Return [PSCustomObject]@{

                    configurePortGroups = $true;
                    customVirtualSwitches = $false;
                    manageVirtualSwitches = $true

                }

            }

            'ServerProfileBootMode'
            {

                return [PSCustomObject]@{

                    manageMode    = $false;
                    mode          = $null;
                    secureBoot    = "Unmanaged";
                    pxeBootPolicy = "Auto"
                
                }
                        
            }

            'ServerProfileBootModeLegacyBios'
            {

                return [PSCustomObject]@{

                    manageMode    = $false;
                    mode          = $null;
                    secureBoot    = "Unmanaged"
                
                }
                        
            }
            
            'ClusterProfileManager'
            {

                return [PSCustomObject]@{

                    displayName      = $null;
                    name             = $null;
                    username         = $null
                    password         = $null;
                    port             = "443"
                    initialScopeUris = [System.Collections.ArrayList]::new();
                    type             = "HypervisorManagerV2"
                
                }
                        
            }

            'CertificateToImport'
            {

                Return [PSCustomObject]@{

                    type = 'CertificateInfoV2';
                    certificateDetails = @(NewObject -CertificateDetails)
                    
                }

            }

            'CertificateDetails'
            {

                Return [PSCustomObject]@{

                    base64Data = $null;
                    aliasName  = $null;
                    type       = "CertificateDetailV2"
                
                }

            }

            'UpdateToActivePermissions' 
            {

                Return [PSCustomObject]@{

                    sessionID = $null;
                    permissionsToActivate = [System.Collections.ArrayList]::new()

                }

            }

            'ApplianceGlobalCertificateValidationConfig'
            {
                
                Return [PSCustomObject]@{
                    type = "CertValidationConfig";
                    okToReboot = $False;
                    certValidationConfig = @{
        
                        'global.validateCertificate'                         = $false;
                        'global.enableExpiryCheckForSelfSignedLeafAtConnect' = $false;
                        'global.checkCertificateRevocation'                  = $true;
                        'global.allow.noCRL'                                 = $true;
                        'global.allow.invalidCRL'                            = $true
        
                    }
        
                }
    
            }

            'ApplianceTrustedCertAuthority'
            {

                Return [PSCustomObject]@{

                    certificateDetails = [PSCustomObject]@{
                        aliasName  = $null;
                        base64Data = $null;
                        type       = "CertificateDetailV2"
                    };

                    type = "CertificateAuthorityInfo"
            
                }

            }
            
            'IloRestSession'
            {

                Return [PSCustomObject]@{
                    
                    RootUri        = $null;
                    "X-Auth-Token" = $null;
                    Location       = $null
                
                }

            }

            'SPTOSDeploymentSettings'
            {

                Return [PSCustomObject]@{

                    osCustomAttributes  = $null;
                    osDeploymentPlanUri = $null

                }

            }

            'ApplianceSslCertificate'
            {

                Return [PSCustomObject]@{

                    type       = "CertificateDataV2";
                    base64Data = $null

                }

            }

            'ApplianceTrustedSslCertificate'
            {

                Return [PSCustomObject]@{

                    aliasName  = $null;
                    base64Data = $null;
                    type       = "CertificateDetailV2"

                }

            }

            'ExternalRepository'
            {

                Return [PSCustomObject]@{

                    repositoryName = $null;
                    userName       = $null;
                    password       = $null;
                    repositoryURI  = $null;
                    repositoryType = "FirmwareExternalRepo";
                    base64Data     = $null

                }

            }

            'OSDeploymentPlanSetting'
            {

                Return [PSCustomObject]@{

                    name  = $null;
                    value = $null

                }

            }

            'OSDeploymentSettings'
            {

                Return [PSCustomObject]@{

                    osDeploymentPlanUri = $null;
                    osCustomAttributes  = [System.Collections.ArrayList]::new()

                }

            }

            'DataCenter'
            {

                Return [PSCustomObject]@{

                    name                    = $null;
                    coolingCapacity         = 5;
                    costPerKilowattHour     = 0.10;
                    currency                = 'USD';
                    deratingType            = 'NaJp';
                    deratingPercentage      = 20.0;
                    defaultPowerLineVoltage = 220;
                    coolingMultiplier       = 1.5;
                    width                   = 0;
                    depth                   = 0;
                    contents                = [System.Collections.ArrayList]::new()                        

                }

            }

            'Rack'
            {

                Return [PSCustomObject]@{
                    
                    name         = $null;
                    thermalLimit = $null;
                    serialNumber = $null;
                    partNumber   = $null;
                    model        = $null;
                    uHeight      = 0;
                    depth        = 0;
                    height       = 0;
                    width        = 0;
                    rackMounts   = [System.Collections.ArrayList]::new()

                }

            }

            'DataCenterItem'
            {

                Return [PSCustomObject]@{

                    resourceUri = $null;
                    rotation    = 0;
                    x           = 0;
                    y           = 0

                }

            }

            'RackItem'
            {

                Return [PSCustomObject]@{

                    mountUri = $null;
                    location = 'CenterFront';
                    relativeOrder = -1;
                    topUSlot = 0;
                    uHeight  = 0

                }

            }

            'RemoteSupportSchedule'
            {

                Return [PSCustomObject]@{

                    type         = "Schedule";
                    taskType     = $null;
                    hourOfDay    = $null;
                    taskKey      = $null;
                    scheduleName = $null;
                    repeatOption = $null;
                    factory      = $true;
                    viewable     = $true;
                    serviceName  = $null;
                    minute       = $null;
                    dayOfMonth   = $null;
                    dayOfWeek    = $null;
                    enabled      = $true;
                    priority     = $null

                }

            }

            'RemoteSupportPartner'
            {

                Return [PSCustomObject]@{

                    type        = "ChannelPartner";
                    id          = $null;
                    default     = $false;
                    partnerType = "RESELLER"
                
                }

            }

            'ApplianceProxy'
            {

                Return [PSCustomObject] @{

                    type                  = "ProxyServerV2";
                    server                = $null;
                    port                  = $null;
                    username              = $null;
                    password              = $null;
                    credUri               = $null;
                    communicationProtocol = 'HTTP'

                }

            }

            'InsightOnlineRegistration'
            {

                Return [PSCustomObject]@{
                    
                    type     = "PortalRegistration";
                    userName = "username";
                    password = "password"
                
                }

            }

            'RemoteSyslog'
            {

                Return [PSCustomObject]@{

                    type                    = "RemoteSyslog";
                    sendTestLog             = $false;
                    remoteSyslogPort        = "514";
                    remoteSyslogDestination = $null;
                    enabled                 = $true

                }

            }

            'I3SAdd'
            {

                Return [PSCustomObject]@{

                    description      = $null;
                    name             = $null;
                    mgmtNetworkUri   = $null;
                    applianceUri     = $null;
                    deplManagersType = 'Image Streamer'

                }

            }

            'LogicalSwitch'
            {
                Return [PSCustomObject]@{

                    logicalSwitch = [PSCustomObject]@{
                        type = 'logical-switchV4';
                        name = $null;
                        managementLevel = $null
                        logicalSwitchGroupUri = $null;
                        switchCredentialConfiguration = [System.Collections.ArrayList]::new()
                    
                    };
                    logicalSwitchCredentials = [System.Collections.ArrayList]::new()

                }

            }

            'LogicalSwitchCredentials'
            {

                Return [PSCustomObject]@{

                    snmpV1Configuration = [PSCustomObject] @{communityString = $null};
                    snmpV3Configuration = NewObject -LogicalSwitchSnmpV3Config;
                    logicalSwitchManagementHost = $null;
                    snmpVersion = "SNMPv1";
                    snmpPort = 161

                }
                
            }

            'LogicalSwitchSnmpV3Config'
            {

                Return [PSCustomObject]@{

                    authorizationProtocol = $null;
                    privacyProtocol = $null;
                    securityLevel = $null

                }

            }

            'LogialSwitchConnectionProperties'
            {

                Return [PSCustomObject] @{ connectionProperties = [System.Collections.ArrayList]::new() }
                
            }

            'LogicalSwitchConnectionProperty'
            {

                Return [PSCustomObject]@{
                
                    propertyName = $null;
                    value        = $null;
                    valueFormat  = 'Unknown';
                    valueType    = $null;
                
                }

            }

            'LogicalSwitchGroup'
            {

                Return [PSCustomObject]@{ 

                    type              = "logical-switch-groupV4";
                    name              = $null;
                    state             = "Active"
                    switchMapTemplate = [PSCustomObject]@{

                        switchMapEntryTemplates = [System.Collections.ArrayList]::new()

                    }

                }

            }

            'SwitchLogicalLocation'
            {

                Return [PSCustomObject]@{

                    logicalLocation = [PSCustomObject]@{

                        locationEntries = [System.Collections.ArrayList]::new()
                        
                    };
                    permittedSwitchTypeUri = $null
                }

            }
            
            'ScopeMemberUpdate'
            {

                Return [PSCustomObject]@{

                    type                = "ScopeV2";
                    addedResourceUris   = [System.Collections.ArrayList]::new();
                    removedResourceUris = [System.Collections.ArrayList]::new()
                                
                }

            }

            'EulaStatus'
            {
            
                Return [PSCustomObject]@{

                    EulaAccepted         = $false;
                    SupportAccessEnabled = $false

                }
                
            }  
            
            'EnclosureGroupPreview'
            {

                Return [PSCustomObject]@{

                    hostname = $null;
                    username = $null;
                    password = $null;
                    logicalInterconnectGroupNeeded = $true;
                    ligPrefix = $null

                }

            }

            'FCZone'
            {

                Return [PSCustomObject]@{
                
                    Name = $null;
                    State = $null;
                    Status = $null;
                    ManagedSan = $null;
                    Members = [System.Collections.ArrayList]::new();
                    Created = $null;
                    Modified = $null;
                    ApplianceConnection = $null    
                
                }

            }

            'FCAlias'
            {

                Return [PSCustomObject]@{
                
                    Name = $null;
                    WWN = $null;
                
                }

            }

            'UpdateUserPassword'
            {

                Return [PSCustomObject]@{

                    type            = 'UserAndPermissions';
                    currentPassword = $null;
                    password        = $null;
                    userName        = $Null
                }

            }

            'VCMigratorReport'
            {

                Return [PSCustomObject]@{

                    apiVcMigrationReport = @{};
                    issueCount           = [Int]$null;
                    migrationState       = [String]$Null;
                    VcemManaged          = [Bool]$False;
                    outReport            = [System.Collections.ArrayList]::new()

                }

            }

            'EnclosureRefresh'
            {

                Return [PSCustomObject]@{ 

                    refreshState        = "RefreshPending"; 
                    refreshForceOptions = $null 
                }

            }

            'EnclosureRefreshForceOptions'
            {

                Return [PSCustomObject]@{

                    address  = $null;
                    username = $null;
                    password = $null

                }

            }

            'AutoBackupConfig'
            {

                Return [PSCustomObject]@{

                    remoteServerName      = $null;
                    remoteServerDir       = '';
                    remoteServerPublicKey = $null;
                    userName              = $null;
                    password              = $null;
                    enabled               = $true;
                    protocol              = 'SCP';
                    scheduleInterval      = 'NONE';
                    scheduleDays          = [System.Collections.ArrayList]::new()
                    scheduleTime          = $null;
                    eTag                  = $null

                }     

            }

            'DirectoryGroupCredentials'
            {

                Return [PSCustomObject]@{

                    userName = $null;
                    password = $null

                }

            }

            'ApplianceTimeLocale'
            {

                Return [PSCustomObject]@{

                    type            = 'TimeAndLocale';
                    locale          = $null;
                    timezone        = 'UTC';
                    ntpServers      = [System.Collections.ArrayList]::new()
                    pollingInterval = $null;

                }

            }

            'RemoteSupportConfig'
            {

                Return [PSCustomObject]@{

                    type                = 'Configuration';
                    eTag                = $null;
                    enableRemoteSupport = $false;
                    companyName         = $null;
                    marketingOptIn      = $false

                }

            }

            'RemoteSupportContact'
            {

                Return [PSCustomObject]@{

                    type           = 'Contact';
                    default        = $false;
                    alternatePhone = $null;
                    email          = $null;
                    firstName      = $null;
                    lastName       = $null;
                    language       = $null;
                    notes          = $null;
                    primaryPhone   = $null

                }

            }

            'RemoteSupportSite'
            {

                Return [PSCustomObject]@{

                    type           = 'Site';
                    name           = 'DEFAULT SITE'
                    default        = $true;
                    city           = $null;
                    postalCode     = $null;
                    provinceState  = $null;
                    streetAddress1 = $null;
                    streetAddress2 = $null;
                    countryCode    = $null;
                    timeZone       = $null

                }

            }

            'SnmpConfig'
            {

                Return [PSCustomObject]@{

                    type              = 'snmp-configuration'
                    readCommunity     = 'public';
                    enabled           = $true;
                    systemContact     = $null;
                    v3Enabled         = $false;
                    snmpUsers         = [System.Collections.ArrayList]::new();
                    snmpAccess        = [System.Collections.ArrayList]::new();
                    trapDestinations  = [System.Collections.ArrayList]::new()

                }
            
            }

            'SnmpTrapDestination'
            {

                Return [PSCustomObject]@{

                    trapDestination    = $null;
                    communityString    = $null;
                    trapFormat         = $null;
                    trapSeverities     = [System.Collections.ArrayList]::new();
                    vcmTrapCategories  = [System.Collections.ArrayList]::new();
                    enetTrapCategories = [System.Collections.ArrayList]::new();
                    fcTrapCategories   = [System.Collections.ArrayList]::new();
                    userName           = $null;
                    inform             = $true;
                    engineId           = $null;
                    port               = '162';

                }

            }

            'PatchOperation'
            {

                Return [PSCustomObject]@{

                    op    = $null;
                    path  = $null;
                    value = $null

                }

            }

            'IPv4Subnet'
            {

                Return [PSCustomObject]@{

                    type           = 'Subnet';
                    category       = $ResourceCategoryEnum.IPv4Subnet;
                    name           = $null;
                    networkId      = $null;
                    subnetmask     = $null;
                    gateway        = $null;
                    domain         = $null;
                    dnsServers     = [System.Collections.ArrayList]::new();

                }

            }

            'IPv6Subnet'
            {

                Return [PSCustomObject]@{

                    type         = "SubnetIPv6";
                    networkId    = $null;
                    prefixLength = $null;
                    gateway      = $null;
                    domain       = $null;
                    dnsServers   = [System.Collections.ArrayList]::new()
                    
                }

            }

            'LogicalEnclosure'
            {

                Return [PSCustomObject] @{ 
                    
                    name                 = $null;
                    enclosureUris        = [System.Collections.ArrayList]::new();
                    enclosureGroupUri    = $null;
                    firmwareBaselineUri  = $null;
                    forceInstallFirmware = $false;
                    initialScopeUris     = [System.Collections.ArrayList]::new()

                }

            }

            'InterconnectMapEntryTemplate'
            {

                Return [PSCustomObject] @{
                        
                    # LogicalDownlinkUri = $null;
                    permittedInterconnectTypeUri = $null;
                    enclosureIndex               = $null;
                    logicalLocation = [PSCustomObject]@{

                        locationEntries = [System.Collections.ArrayList]::new()

                    }

                }

            }

            'InterconnectMapEntryTemplate'
            {

                Return [PSCustomObject] @{
                        
                    logicalDownlinkUri           = $null;
                    permittedInterconnectTypeUri = $null;
                    enclosureIndex               = $null;
                    logicalLocation = [PSCustomObject]@{

                        locationEntries = [System.Collections.ArrayList]::new()

                    }

                }

            }

            'LocationEntry'
            {

                Return [PSCustomObject]@{

                    relativeValue = 1;
                    type          = $Null

                }

            }

            'LoginMessageObject'
            {

                Return [PSCustomObject]@{

                    Message             = $null;
                    Acknowledgment      = $null;
                    ApplianceConnection = $null

                }

            }

            'ConvertSnapshotToVol'
            {

                Return [PSCustomObject]@{

                    properties           = [PSCustomObject] @{

                        name             = $null;
                        description      = $null;
                        provisioningType = 'Thin';
                        storagePool      = $null;
                        snapshotPool     = $null;
                        isShareable      = $false

                    };
                    snapshotUri          = $null;
                    templateUri          = $null;
                    isPermanent          = $true;
                  
                }

            }

            'VolSnapshot'
            {

                Return [PSCustomObject]@{

                    name        = '{volumeName}_{timestamp}';
                    description = $null

                }

            }

            'LogicalInterconnectBaseline'
            {

                Return [PsCustomObject]@{ 
            
                    command                 = 'Update'; 
                    ethernetActivationType  = 'OddEven';
                    ethernetActivationDelay = 5;
                    fcActivationType        = 'OddEven';
                    fcActivationDelay       = 5;
                    sppUri                  = $null; 
                    force                   = $false
        
                }

            }

            'StoragePath'
            {

                Return [PSCustomObject]@{

                    targetSelector = "Auto";
                    targets        = [System.Collections.ArrayList]::new();
                    connectionId   = 1;
                    isEnabled      = $true

                }

            }

            'LicenseKey'
            {

                Return [PsCustomObject] @{

                    type = "LicenseV500";
                    key  = $null

                }

            }

            'UnmanagedDevice'
            {

                Return [PSCustomObject]@{ 
                
                    name           = [String]$null; 
                    model          = [String]$null; 
                    height         = [Int]1; 
                    mac            = [String]$null;
                    ipv4Address    = [String]$null;
                    ipv6Address    = [String]$null;
                    maxPwrConsumed = [Int]100 
                
                }

            }

            'RabbitmqCertReq'
            {

                Return [PSCustomObject] @{
        
                    commonName = 'default';
                    type       = 'RabbitMqClientCertV2'
            
                }

            }

            'AuthLoginCredential'
            {

                Return [PSCustomObject] @{
        
                    userName        = $null;
                    password        = $null;
                    authLoginDomain = $null
            
                }

            }

            'DownloadFileStatus'
            {

                Return [PSCustomObject]@{

                    status              = $null;
                    file                = $null;
                    ApplianceConnection = $null

                }

            }

            'GlobalSetting'
            {

                Return [PSCustomObject]@{
                    
                    type  = "SettingV2"; 
                    name  = $null; 
                    value = $null
                
                }

            }

            'StorageVolumeTemplate'
            {

                Return [PSCustomObject]@{
                    
                    name             = $null;
                    description      = $null;
                    rootTemplateUri  = $null;
                    initialScopeUris = [System.Collections.ArrayList]::new();
                    properties       = @{}

                }

            }

            'CustomBaselineRestore'
            {

                Return [PSCustomObject]@{

                    baselineUri        = $null;
                    hotfixUris         = [System.Collections.ArrayList]::new();
                    customBaselineName = $null

                }

            }

            'SmtpConfig'
            {

                Return [PSCustomObject]@{
        
                    type               = "EmailNotificationV3";
                    senderEmailAddress = $null;
                    password           = $null;
                    smtpServer         = $null;
                    smtpPort           = 25;
                    smtpProtocol       = 'TLS';
                    alertEmailDisabled = $false;
                    alertEmailFilters  = [System.Collections.ArrayList]::new()
                
                }

            }

            'TestSmtpConfig'
            {

                Return [PSCustomObject]@{
        
                    type            = "Email";
                    subject         = $null;
                    htmlMessageBody = $null;
                    textMessageBody = $null;
                    toAddress       = [System.Collections.ArrayList]::new()
                
                }

            }

            'UpdateAlert'
            {

                Return [PSCustomObject] @{ 
            
                    alertState     = $null;
                    assignedToUser = $null;
                    notes          = $null;
                    eTag           = $null
                
                } 

            }

            'SelfSignedCert'
            {
            
                Return [PSCustomObject]@{

                    type               = "CertificateDtoV3";
                    country            =  $null;
                    state              =  $null;
                    locality           =  $null;
                    organization       =  $null;
                    commonName         =  $null;
                    organizationalUnit =  $null;
                    alternativeName    =  $null;
                    contactPerson      =  $null;
                    email              =  $null;
                    surname            =  $null;
                    givenName          =  $null;
                    initials           =  $null;
                    dnQualifier        =  $null

                }    
            
            }

            'ApplianceCSR'
            {

                Return [PSCustomObject]@{

                    type               = "CertificateSigningRequest";
                    country            = $null;
                    state              = $null;
                    locality           = $null;
                    organization       = $null;
                    commonName         = $null;
                    organizationalUnit = $null;
                    alternativeName    = $null;
                    contactPerson      = $null;
                    email              = $null;
                    surname            = $null;
                    givenName          = $null;
                    initials           = $null;
                    dnQualifier        = $null;
                    unstructuredName   = $null;
                    challengePassword  = $null;
                    cnsaCertRequested  = $false

                }    

            }

            'AuthDirectory'
            {

                Return [PSCustomObject]@{
                    
                    type                 = 'LoginDomainConfigV600';
                    directoryBindingType = $LdapDirectoryAccountBindTypeEnum['USERACCOUNT'];
                    authnType            = "CREDENTIAL";
                    authProtocol         = 'AD';
                    baseDN               = $null;
                    orgUnits             = [System.Collections.ArrayList]::new()
                    userNamingAttribute  = 'UID';
                    name                 = $null;
                    credential           = [PSCustomObject]@{
                        
                        userName = $null; 
                        password = $null
                    
                    };
                    directoryServers    = [System.Collections.ArrayList]::new();

                }

            }

            'DirectoryGroup'
            {

                Return [PSCustomObject]@{

                    type                     = 'LoginDomainGroupCredentials';
                    group2PermissionPerGroup = [PSCustomObject]@{
                    
                        type        = 'LoginDomainGroupPermission';
                        loginDomain = $null;
                        egroup      = $null;
                        permissions = [System.Collections.ArrayList]::new();

                    }
                    credentials = NewObject -DirectoryGroupCredentials

                }

            }

            'DirectoryGroupPermissions'
            {

                Return [PSCustomObject]@{
                    
                    roleName = $null;
                    scopeUri = $null

                }

            }

            'AuthDirectoryServer'
            {

                Return [PSCustomObject]@{

                    type                                 = 'LoginDomainDirectoryServerInfoDto'
                    directoryServerCertificateStatus     = "";
                    directoryServerCertificateBase64Data = "";
                    serverStatus                         = "";
                    directoryServerIpAddress             = $null;
                    directoryServerSSLPortNumber         = "636";

                }

            }

            'IPIDPoolRange'
            {

                Return [PsCustomObject]@{ 

                    type               = 'Range'; 
                    rangeCategory      = 'Custom';
                    name               = $null;
                    enabled            = $true;
                    startStopFragments = [System.Collections.ArrayList]::new()
                    subnetUri          = $null

                }

            }

            'IDPoolStartStopFragment'
            {

                Return @{

                    startAddress = $null;
                    endAddress   = $null

                }

            }

            'IDPoolRange'
            {

                Return [PsCustomObject]@{ 

                    type          = 'Range'; 
                    rangeCategory = 'Custom';
                    name          = $null;
                    enabled       = $true;
                    startAddress  = $null; 
                    endAddress    = $null

                }

            }

            'UserAccount'
            {

                Return [PsCustomObject]@{

                    type         = "UserAndPermissions";
                    userName     = $null; 
                    fullName     = $null; 
                    password     = $null; 
                    emailAddress = $emailAddress; 
                    officePhone  = $null; 
                    mobilePhone  = $null; 
                    enabled      = $True;
                    permissions  = [System.Collections.ArrayList]::new()

                }

            }

            'PowerDeliveryDeviceAdd'
            {

                Return [PSCustomObject]@{

                    hostname = $null;
                    username = $null;
                    password = $null;
                    force    = $null

                }

            }
            
            'ApplianceDebug'
            {

                Return [PSCustomObject]@{

                    scope      = $null;
                    loggerName = $null;
                    level      = $null

                }

            }

            'AlertFilter'
            {

                Return [PSCustomObject]@{

                    filterName      = $null;
                    disabled        = $False;
                    filter          = $null;
                    displayFilter   = $null;
                    userQueryFilter = $null;
                    emails          = $null;
                    scopeQuery      = $null 

                }

            }

            'ServerProfile'
            {

                Return [PSCustomObject]@{

                    type                  = $ServerProfileType; 
                    name                  = $null; 
                    description           = $null; 
                    affinity              = $null;
                    hideUnusedFlexNics    = $true;
                    initialScopeUris      = [System.Collections.ArrayList]::new();
                    bios                  = [PSCustomObject]@{

                        manageBios         = $false;
                        overriddenSettings = $null

                    }; 
                    firmware                 = [PSCustomObject]@{

                        manageFirmware           = $false;
                        firmwareBaselineUri      = $null;
                        forceInstallFirmware     = $false;
                        firmwareInstallType      = 'FirmwareAndOSDrivers';
                        firmwareActivationType   = 'Immediate';
                        firmwareScheduleDateTime = $null
                            
                    };
                    boot           = [PSCustomObject]@{
                       
                        manageBoot = $false; 
                        order      = [System.Collections.ArrayList]::new()
                           
                    };
                    bootMode                 = $null;
                    localStorage             = [PSCustomObject]@{

                        sasLogicalJBODs = [System.Collections.ArrayList]::new(); 
                        controllers     = [System.Collections.ArrayList]::new()

                    }
                    serialNumberType         = 'Virtual'; 
                    macType                  = 'Virtual';
                    wwnType                  = 'Virtual';
                    connectionSettings       = [PSCustomObject]@{
                        connections              = [System.Collections.ArrayList]::new();
                    }
                    serialNumber             = $null;
                    iscsiInitiatorNameType   = 'AutoGenerated'
                    serverHardwareUri        = $null;
                    serverHardwareTypeUri    = $null;
                    serverProfileTemplateUri = $null;
                    enclosureBay             = $null;
                    enclosureGroupUri        = $null;
                    enclosureUri             = $null;
                    sanStorage               = $null;
                    uuid                     = $null;
                }

            }

            'ServerProfileTemplate'
            {

                Return [PSCustomObject]@{
                    
                    type                     = $ServerProfileTemplateType; 
                    serverProfileDescription = $null;
                    serverHardwareTypeUri    = $null;
                    enclosureGroupUri        = $null;
                    serialNumberType         = 'Virtual'; 
                    macType                  = 'Virtual';
                    wwnType                  = 'Virtual';
                    name                     = $null; 
                    description              = $null; 
                    affinity                 = $null;
                    initialScopeUris         = [System.Collections.ArrayList]::new();
                    connectionSettings       = @{

                        connections              = [System.Collections.ArrayList]::new();
                        manageConnections        = $true

                    }
                    
                    boot                     = [PSCustomObject]@{
                        
                        complianceControl = $ConsistencyCheckingEnum.Exact;
                        manageBoot        = $true; 
                        order             = [System.Collections.ArrayList]::new()
                                   
                    };
                    bootMode                 = $null;
                    firmware                 = [PSCustomObject]@{

                        complianceControl      = $ConsistencyCheckingEnum.Exact;
                        manageFirmware         = $false;
                        firmwareBaselineUri    = $null;
                        forceInstallFirmware   = $false;
                        firmwareInstallType    = 'FirmwareAndOSDrivers';
                        firmwareActivationType = 'Immediate'
                            
                    };
                    bios                     = [PSCustomObject]@{

                        complianceControl  = $ConsistencyCheckingEnum.Exact;
                        manageBios         = $false;
                        overriddenSettings = [System.Collections.ArrayList]::new()

                    }; 
                    hideUnusedFlexNics       = $true;
                    iscsiInitiatorNameType   = "AutoGenerated";
                    localStorage             = [PSCustomObject]@{

                        complianceControl = $ConsistencyCheckingEnum.Exact;
                        sasLogicalJBODs = [System.Collections.ArrayList]::new(); 
                        controllers     = [System.Collections.ArrayList]::new()

                    }
                    sanStorage               = $null;

                }

            } 

            'ServerProfileTemplateLocalStorage'
            {

                Return [PSCustomObject]@{

                    slotNumber          = '0';
                    managed             = $true;
                    mode                = 'RAID'
                    initialize          = $false;
                    logicalDrives       = [System.Collections.ArrayList]::new()

                }

            }

            'ServerProfileLocalStorageController'
            {

                Return [PSCustomObject]@{

                    deviceSlot          = 'Embedded';
                    importConfiguration = $false;
                    mode                = 'RAID'
                    initialize          = $false;
                    driveWriteCache     = "Unmanaged";
                    logicalDrives       = [System.Collections.ArrayList]::new()

                }

            }

            'ServerProfileLocalStorageLogicalDrive'
            {

                Return [PSCustomObject]@{ 

                    name              = $null;
                    bootable          = $false;
                    raidLevel         = $null;
                    numPhysicalDrives = $null;
                    driveTechnology   = $null;
                    sasLogicalJBODId  = $null;
                    accelerator       = "Unmanaged"
                
                }

            }

            'ServerProfileSasLogicalJBOD'
            {

                Return [PSCustomObject]@{

                    id                = 1;
                    deviceSlot        = $null;
                    name              = $null
                    numPhysicalDrives = 1;
                    driveMinSizeGB    = 0;
                    driveMaxSizeGB    = 0;
                    driveTechnology   = $null;
                    eraseData         = $false

                }

            }

            'EnclosureImport'
            {

                Return [PSCustomObject]@{

                    hostname             = $null;
                    username             = $null;
                    password             = $null;
                    licensingIntent      = 'OneView';
                    force                = $false;
                    enclosureGroupUri    = $null;
                    firmwareBaselineUri  = $null;
                    forceInstallFirmware = $false;
                    updateFirmwareOn     = $null;
                    state                = $null;
                    initialScopeUris     = [System.Collections.ArrayList]::new()
                
                }

            }

            'ServerImport'
            {

                Return [PSCustomObject]@{

                    hostname             = $null;
                    username             = $null;
                    password             = $null;
                    force                = $false;
                    licensingIntent      = 'OneView';
                    configurationState   = $null;
                    initialScopeUris     = [System.Collections.ArrayList]::new()
                
                }

            }

            'StorageSystemCredentials'
            {

                Return [PSCustomObject]@{
                    
                    hostname = $null; 
                    username = $null; 
                    password = $null;
                    family   = $null
                
                }

            }

            'StorageSystemManagedPort'
            {

                Return [PSCustomObject]@{

                    type                = "StorageTargetPortV4"; 
                    portName            = $null; 
                    name                = $null;
                    expectedNetworkUri  = $null; 
                    expectedNetworkName = $null;
                    actualNetworkUri    = $null; 
                    actualNetworkSanUri = $null;
                    portWwn             = $null; 
                    groupName           = 'Auto'; 
                    label               = $null;
                    protocolType       = 'FC'

                }

            }

            'StorageVolume'
            {

                Return [PSCustomObject]@{

                    properties = @{};
                    templateUri = $null;
                    isPermanent = $true;
                    initialScopeUris = [System.Collections.ArrayList]::new()

                }

            }

            'StoreVirtualStorageVolume'
            {

                Return [PSCustomObject]@{

                    properties = @{
                        name                          = $null;
                        description                   = $null;
                        storagePool                   = $null;
                        size                          = 107374182400;
                        provisioningType              = "Thin";
                        isShareable                   = $false;
                        dataProtectionLevel           = $null
                        isAdaptiveOptimizationEnabled = $false
                    };
                    templateUri = $null; ;
                    isPermanent = $true;
                    initialScopeUris = [System.Collections.ArrayList]::new()

                }

            }

            'ServerProfileStorageVolume'
            {

                Return [PsCustomObject]@{
            
                    id                     = $null;
                    lun                    = $null;
                    volumeUri              = $null;
                    volumeStoragePoolUri   = $null;
                    volumeStorageSystemUri = $null;
                    lunType                = 'Auto';
                    storagePaths           = [System.Collections.ArrayList]::new();
                    bootVolumePriority     = 'NotBootable';
                    ApplianceConnection    = $null;

                }   

            }

            'AddStorageVolume'
            {

                Return [PSCustomObject]@{

                    description      = $null;
                    deviceVolumeName = $null;
                    isShareable      = $false;
                    name             = $null;
                    storageSystemUri = $null;
                    initialScopeUris = [System.Collections.ArrayList]::new()

                }

            }

            'EphemeralStorageVolume'
            {

                Return [PsCustomObject]@{
            
                    id                     = 1
                    volumeUri              = $null;
                    volumeStorageSystemUri = $null;
                    volume                 = [PSCustomObject]@{
                        properties       = @{}
                        templateUri      = $null;
                        isPermanent      = $true;
                        initialScopeUris = $null
                    };
                    bootVolumePriority     = 'NotBootable';
                    lunType                = 'Auto';
                    lun                    = $null;
                    ApplianceConnection    = $null;
                    storagePaths           = [System.Collections.ArrayList]::new()

                }

            }

            'StoreVirtualEphemeralVolumeProperties'
            {

                Return [PSCustomObject]@{
                    name                          = $null;
                    description                   = $null;
                    storagePool                   = $null;
                    templateVersion               = "1.0";
                    provisioningType              = 'Thin';
                    size                          = '10737418240';
                    isShareable                   = $false;
                    dataProtectionLevel           = $null;
                    isAdaptiveOptimizationEnabled = $false
                }

            }

            'StoreServeEphemeralVolumeProperties'
            {

                Return [PSCustomObject]@{
                    name             = $null;
                    description      = $null;
                    storagePool      = $null;
                    templateVersion   = "1.0";
                    provisioningType = 'Thin';
                    size             = '10737418240';
                    isShareable      = $false;
                    snapshotPool     = $null
                }

            }

            'NimbleEphemeralVolumeProperties'
            {

                Return [PSCustomObject]@{
                    name              = $null;
                    description       = $null;
                    storagePool       = $null;
                    provisioningType  = 'Thin';
                    size              = '10737418240';
                    isShareable       = $false;
                    templateVersion   = "1.0";
                    isDeduplicated    = $false;
                    performancePolicy = $null;
                    folder            = $null;
                    volumeSet         = $null;
                    isEncrypted       = $false;
                    isPinned          = $false;
                    iopsLimit         = $null;
                    dataTransferLimit = $null
                }

            }

            'ServerProfileEthernetConnection'
            {

                Return [PSCustomObject]@{
            
                    id                  = 1;
                    functionType        = 'Ethernet';
                    name                = $null;
                    portId              = $null; 
                    networkUri          = $null; 
                    requestedMbps       = 2000; 
                    boot                = $null;
                    macType             = 'Virtual';
                    mac                    = $null;
                    requestedVFs        = '0';
                    lagName             = $null;
                    ApplianceConnection = $null

                }

            }

            'ServerProfileIscsiConnection'
            {

                Return [PSCustomObject]@{
            
                    id                  = 1;
                    functionType        = 'Ethernet';
                    name                = $null;
                    portId              = $null; 
                    networkUri          = $null; 
                    requestedMbps       = 2000; 
                    boot                = $null;
                    macType             = 'Virtual';
                    mac                    = $null;
                    ipv4                = $null;
                    lagName             = $null;
                    ApplianceConnection = $null

                }

            }

            'ServerProfileFCConnection'
            {

                Return [PSCustomObject]@{
            
                    id                  = 1;
                    functionType        = 'FibreChannel';
                    name                = $null;
                    portId              = $null; 
                    networkUri          = $null; 
                    requestedMbps       = 2000; 
                    boot                = $null;
                    macType             = 'Virtual';
                    mac                    = $null;
                    wwpnType            = 'Virtual';
                    wwnn                = $null;
                    wwpn                = $null;
                    ApplianceConnection = $null

                }

            }

            'ServerProfileUnmanagedFCConnection'
            {

                Return [PSCustomObject]@{
            
                    id                  = 1;
                    name                = $null;
                    functionType        = 'FibreChannel';
                    portId              = $null; 
                    networkUri          = $null; 
                    requestedMbps       = $null; 
                    boot                = $null;
                    wwpn                = $null;
                    managed             = $false;
                    ApplianceConnection = $null

                }

            }

            'ServerProfileEthBootableConnection'
            {

                Return [PSCustomObject]@{

                    priority         = 'NotBootable';
                    ethernetBootType = "PXE";
                    iscsi            = $null

                }

            }

            'ServerProfileEthBootableConnectionWithTargets'
            {

                Return [PSCustomObject]@{

                    priority         = 'NotBootable';
                    targets          = [System.Collections.ArrayList]::new();
                    bootVolumeSource = 'AdapterBIOS';
                    ethernetBootType = "PXE";
                    iscsi            = $null

                }

            }

            'ServerProfileIscsiBootableConnectionWithTargets'
            {

                Return [PSCustomObject]@{

                    priority         = 'NotBootable';
                    targets          = [System.Collections.ArrayList]::new();
                    bootVolumeSource = 'AdapterBIOS';
                    iscsi            = $null

                }

            }

            'ServerProfileFcBootableConnection'
            {

                Return [PSCustomObject]@{

                    priority         = 'NotBootable';
                    targets          = [System.Collections.ArrayList]::new();
                    bootVolumeSource = 'AdapterBIOS'

                }

            }

            'ServerProfileConnectionFcBootTarget'
            {

                Return [PSCustomObject]@{

                    arrayWwpn = $null;
                    lun       = $null

                }

            }

            'IscsiBootEntry'
            {

                Return [PSCustomObject]@{
                        
                    initiatorNameSource  = "ProfileInitiatorName";
                    firstBootTargetIp    = $null;
                    firstBootTargetPort  = $null;
                    secondBootTargetIp   = $null;
                    secondBootTargetPort = $null;
                    chapLevel            = $null;
                    initiatorName        = $null;
                    bootTargetName       = $null;
                    bootTargetLun        = $null;
                    chapName             = $null;
                    chapSecret           = $null;
                    mutualChapName       = $null;
                    mutualChapSecret     = $null

                }

            }

            'IscsiIPv4Configuration'
            {

                Return [PSCustomObject]@{
                        
                    ipAddress       = $null;
                    subnetMask      = $null;
                    gateway         = $null;
                    ipAddressSource = 'UserDefined'

                }

            }

            'SanManager'
            {

                Return [PSCustomObject]@{
            
                    "connectionInfo" = [System.Collections.ArrayList]::new()
                    
                }

            }

            'SanManagerConnectInfo'
            {

                Return [PSCustomObject]@{
                
                    name  = $null;
                    Value = $null
                
                }

            }

            'EthernetNetwork'
            {

                Return [pscustomobject]@{
                            
                    type                = $EthernetNetworkType; 
                    vlanId              = 1; 
                    ethernetNetworkType = 'Tagged'; 
                    purpose             = 'General'; 
                    name                = $null; 
                    smartLink           = $false;
                    privateNetwork      = $false;
                    subnetUri           = $null;
                    ipv6SubnetUri       = $null;
                    initialScopeUris    = [System.Collections.ArrayList]::new()

                }

            }

            'BulkEthernetNetworks'
            {

                Return [pscustomobject]@{

                    type           = $EthernetNetworkBulkType; 
                    vlanIdRange    = $null; 
                    purpose        = 'General'; 
                    namePrefix     = $null; 
                    smartLink      = $false; 
                    privateNetwork = $false;
                    bandwidth      = [PSCustomObject]@{
                                    
                        typicalBandwidth = 2500;
                        maximumBandwidth = 20000
                                    
                    };
                    networkSetUris      = [System.Collections.ArrayList]::new()
                    initialScopeUris    = [System.Collections.ArrayList]::new()

                }

            }

            'FCNetwork'
            {

                [pscustomobject]@{

                    type                    = $FCNetworkType; 
                    name                    = $Name; 
                    linkStabilityTime       = 30; 
                    autoLoginRedistribution = $true; 
                    fabricType              = 'FabricAttach'; 
                    connectionTemplateUri   = $null;
                    managedSanUri           = $null;
                    initialScopeUris        = [System.Collections.ArrayList]::new()
                        
                }

            }

            'FCoENetwork'
            {

                Return [pscustomobject]@{
                        
                    type                  = $FCoENetworkType; 
                    name                  = $null; 
                    vlanId                = 1; 
                    connectionTemplateUri = $null;
                    managedSanUri         = $null;
                    initialScopeUris      = [System.Collections.ArrayList]::new()

                }
                
            }

            'NetworkSet'
            {

                Return [PSCustomObject] @{

                    type             = $NetworkSetType; 
                    name             = $null; 
                    networkUris      = [System.Collections.ArrayList]::new(); 
                    nativeNetworkUri = $null;
                    initialScopeUris = [System.Collections.ArrayList]::new()
                
                }

            }

            'SynergyEnclosureGroup'
            {

                Return [PSCustomObject]@{

                    name                        = $null;
                    interconnectBayMappings     = [System.Collections.ArrayList]::new();
                    configurationScript         = $null;
                    powerMode                   = 'RedundantPowerFeed';
                    ipAddressingMode            = $null;
                    ipRangeUris                 = [System.Collections.ArrayList]::new();
                    ipv6AddressingMode          = $null;
                    ipv6RangeUris               = [System.Collections.ArrayList]::new();
                    enclosureCount              = 1;
                    osDeploymentSettings        = $null;
                    initialScopeUris            = [System.Collections.ArrayList]::new();

                }

            }

            'EnclosureGroup'
            {

                Return [PSCustomObject]@{

                    name                        = $null;
                    interconnectBayMappings     = [System.Collections.ArrayList]::new();
                    configurationScript         = $null;
                    powerMode                   = 'RedundantPowerFeed';
                    enclosureCount              = 1;
                    initialScopeUris            = [System.Collections.ArrayList]::new();
                    ambientTemperatureMode      = 'Standard'

                }

            }

            'DeploymentModeSettings'
            {

                Return [PSCustomObject]@{

                    deploymentModeSettings = $null;
                    manageOSDeployment     = $false

                }

            }

            'EnclosureGroupI3SDeploymentSettings'
            {

                Return [PSCustomObject]@{

                    deploymentMode       = 'None';
                    deploymentNetworkUri = $null

                }

            }

            'InterconnectBayMapping'
            {

                Return [PSCustomObject]@{
                    
                    enclosureIndex              = 1;
                    interconnectBay             = 1; 
                    logicalInterconnectGroupUri = $null
                
                }

            }

            'ApplianceVersion'
            {

                Return [PSCustomObject]@{

                    applianceName    = $null;
                    softwareVersion  = $null; 
                    major            = $null;
                    minor            = $null;
                    xapiVersion      = $null;
                    modelNumber      = $null

                }

            }

            'AllApiResponse'
            {

                Return [PSCustomObject]@{

                    type        = [String]$null;
                    nextPageUri = [String]$null;
                    start       = [Int]0;
                    prevPageUri = [String]$null;
                    total       = [Int]0;
                    count       = [Int]0;
                    members     = [System.Collections.ArrayList]::new();
                    eTag        = [String]$null;
                    created     = [String]$null;
                    modified    = [String]$null;
                    category    = [String]$null;
                    uri         = [String]$null

                }

            }

            # Default LIG Object
            "C7KLIG"
            {
            
                Return [PSCustomObject]@{
                    name                    = $Null;
                    uplinkSets              = [System.Collections.ArrayList]::new(); 
                    interconnectMapTemplate = [PSCustomObject]@{
                        
                        interconnectMapEntryTemplates = [System.Collections.ArrayList]::new()};

                    internalNetworkUris                    = [System.Collections.ArrayList]::new(); 
                    consistencyCheckingForInternalNetworks = $LIGConsistencyCheckingEnum.Exact;
                    ethernetSettings                       = [PSCustomObject]@{

                        type                        = "EthernetInterconnectSettingsV6";
                        enableIgmpSnooping          = $false;
                        igmpIdleTimeoutInterval     = 260; 
                        enableFastMacCacheFailover  = $true;
                        macRefreshInterval          = 5;
                        enableNetworkLoopProtection = $false;
                        enablePauseFloodProtection  = $false;
                        enableRichTLV               = $false;
                        enableTaggedLldp            = $false;
                        consistencyChecking         = $LIGConsistencyCheckingEnum.Exact
                        
                    };
                    snmpConfiguration       = $Null;
                    qosConfiguration        = [PSCustomObject]@{
                        
                        type                     = "qos-aggregated-configuration";
                        activeQosConfig          = $Null;
                        inactiveFCoEQosConfig    = $null;
                        inactiveNonFCoEQosConfig = $null;
                        consistencyChecking      = $LIGConsistencyCheckingEnum.Exact

                            
                    };
                    stackingMode            = "Enclosure";
                    enclosureType           = "C7000";
                    type                    = $LogicalInterconnectGroupType

                }

            }

            "SELIG"
            {
            
                Return [PSCustomObject]@{
                    type                    = $LogicalInterconnectGroupType
                    name                    = $Null;
                    uplinkSets              = [System.Collections.ArrayList]::new(); 
                    interconnectMapTemplate = [PSCustomObject]@{
                        interconnectMapEntryTemplates = [System.Collections.ArrayList]::new()
                    };
                    internalNetworkUris                    = [System.Collections.ArrayList]::new(); 
                    consistencyCheckingForInternalNetworks = $LIGConsistencyCheckingEnum.Exact;
                    ethernetSettings = [PSCustomObject]@{

                        type                        = "EthernetInterconnectSettingsV6";
                        enableIgmpSnooping          = $false;
                        igmpIdleTimeoutInterval     = 260; 
                        enableFastMacCacheFailover  = $true;
                        macRefreshInterval          = 5;
                        enableNetworkLoopProtection = $false;
                        enablePauseFloodProtection  = $false;
                        enableRichTLV               = $false;
                        enableTaggedLldp            = $false;
                        consistencyChecking         = $LIGConsistencyCheckingEnum.Exact
                        
                    };
                    snmpConfiguration       = $Null;
                    qosConfiguration        = [PSCustomObject]@{
                        
                        type                     = "qos-aggregated-configuration";
                        activeQosConfig          = $Null;
                        inactiveFCoEQosConfig    = $null;
                        inactiveNonFCoEQosConfig = $null;
                        consistencyChecking      = $LIGConsistencyCheckingEnum.Exact

                    };
                    enclosureType      = 'SY12000';
                    enclosureIndexes   = [System.Collections.ArrayList]::new();
                    interconnectBaySet = 1;
                    redundancyType     = 'Redundant'
                    
                }

            }

            "SESASLIG"
            {
            
                Return [PSCustomObject]@{
                    type                    = "sas-logical-interconnect-groupV2"
                    name                    = $Null;
                    interconnectMapTemplate = [PSCustomObject]@{
                        
                        interconnectMapEntryTemplates = [System.Collections.ArrayList]::new()};

                    enclosureType      = 'SY12000';
                    enclosureIndexes   = @(1);
                    interconnectBaySet = 1
                    
                }

            }
            
            # Default qosConfiguration Object for LIG
            "QosConfiguration"
            {
                
                Return [PSCustomObject]@{
                
                    type                       = "QosConfiguration";
                    configType                 = "Passthrough";
                    qosTrafficClassifiers      = [System.Collections.ArrayList]@()
                    uplinkClassificationType   = $Null; # Leave Null to support default 'Passthrough'
                    downlinkClassificationType = $Null; # Leave Null to support default 'Passthrough'
                
                }

            }

            'QosIngressClassMapping'
            {

                Return [PSCustomObject]@{
                        
                    dot1pClassMapping = [System.Collections.ArrayList]::new();
                    dscpClassMapping  = [System.Collections.ArrayList]::new()
                            
                }

            }

            # Default With FCoE Lossless Traffic Classifiers Object
            "DefaultFCoELosslessQosTrafficClassifiers"
            {
            
                Return @(

                    #1
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "65";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Best effort";
                        enabled          = $true;
            
                    };
                            
                    qosClassificationMapping = [PSCustomObject]@{
            
                        dot1pClassMapping = [System.Collections.ArrayList]@(1,0);
                        dscpClassMapping  = [System.Collections.ArrayList]@(
            
                            "DSCP 10, AF11",
                            "DSCP 12, AF12",
                            "DSCP 14, AF13",
                            "DSCP 8, CS1",
                            "DSCP 0, CS0"
            
                        )
            
                    }
            
                },
                            
                    #2
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "0";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Class1";
                        enabled          = $false;
            
                    };
                                
                    qosClassificationMapping = $null
            
                },
                
                    #3
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "0";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Class2";
                        enabled          = $false;
            
                    };
                                
                    qosClassificationMapping = $null
            
                },
                
                    #4
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "0";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Class3";
                        enabled          = $false;
            
                    };
                                
                    qosClassificationMapping = $null
            
                },
                
                    #5
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "0";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Class4";
                        enabled          = $false;
            
                    };
                                
                    qosClassificationMapping = $null
            
                },
                
                    #6
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "fcoe";
                        egressDot1pValue = 3;
                        realTime         = $false;
                        className        = "FCoE lossless";
                        enabled          = $true;
            
                    };                    
                            
                    qosClassificationMapping = [PSCustomObject]@{
            
                        dot1pClassMapping = [System.Collections.ArrayList]@(3);
                        dscpClassMapping  = [System.Collections.ArrayList]@()
            
                    }
            
                },
                
                    #7
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 100;
                        bandwidthShare   = "25";
                        egressDot1pValue = 2;
                        realTime         = $false;
                        className        = "Medium";
                        enabled          = $true;
            
                    };
                                
                    qosClassificationMapping = [PSCustomObject]@{
            
                        dot1pClassMapping = [System.Collections.ArrayList]@(4,3,2);
                        dscpClassMapping  = [System.Collections.ArrayList]@(
            
                            "DSCP 18, AF21",
                            "DSCP 20, AF22",
                            "DSCP 22, AF23",
                            "DSCP 26, AF31",
                            "DSCP 28, AF32",
                            "DSCP 30, AF33",
                            "DSCP 34, AF41",
                            "DSCP 36, AF42",
                            "DSCP 38, AF43",
                            "DSCP 16, CS2",
                            "DSCP 24, CS3",
                            "DSCP 32, CS4"
            
                        )
            
                    }
            
                },
                
                    #8
                    [PSCustomObject]@{ 
                    qosTrafficClass = [PSCustomObject]@{
            
                        maxBandwidth     = 10;
                        bandwidthShare   = "10";
                        egressDot1pValue = 5;
                        realTime         = $true;
                        className        = "Real time";
                        enabled          = $true;
            
                    };
                                
                    qosClassificationMapping = [PSCustomObject]@{
            
                        dot1pClassMapping = [System.Collections.ArrayList]@(5,6,7);
                        dscpClassMapping  = [System.Collections.ArrayList]@(
            
                            "DSCP 46, EF",
                            "DSCP 40, CS5",
                            "DSCP 48, CS6",
                            "DSCP 56, CS7"
            
                        )
            
                    }
            
                }
                
                )

            }

            # Default With No FCoE Lossless Traffic Classifiers Object
            "DefaultNoFCoELosslessQosTrafficClassifiers" 
            {
                
                Return @(

                    #1
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "65";
                            egressDot1pValue = 0;
                            realTime         = $false;
                            className        = "Best effort";
                            enabled          = $true;

                        };
                                
                        qosClassificationMapping = [PSCustomObject]@{

                            dot1pClassMapping = [System.Collections.ArrayList]@(1,0);
                            dscpClassMapping  = [System.Collections.ArrayList]@(

                                "DSCP 10, AF11",
                                "DSCP 12, AF12",
                                "DSCP 14, AF13",
                                "DSCP 8, CS1",
                                "DSCP 0, CS0"

                            )

                        }

                    },
                                            
                    #2
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "0";
                            egressDot1pValue = 0;
                            realTime         = $false;
                            className        = "Class1";
                            enabled          = $false;

                        };
                                    
                        qosClassificationMapping = $null

                    },
                                
                    #3
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "0";
                            egressDot1pValue = 0;
                            realTime         = $false;
                            className        = "Class2";
                            enabled          = $false;

                        };
                                    
                        qosClassificationMapping = $null

                    },
                                
                                    #4
                                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "0";
                            egressDot1pValue = 0;
                            realTime         = $false;
                            className        = "Class3";
                            enabled          = $false;

                        };
                                    
                        qosClassificationMapping = $null

                    },
                                
                    #5
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "0";
                            egressDot1pValue = 0;
                            realTime         = $false;
                            className        = "Class4";
                            enabled          = $false;

                        };
                                    
                        qosClassificationMapping = $null

                    },
                                
                    #6
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "0";
                            egressDot1pValue = 0;
                            realTime         = $false;
                            className        = "Class5";
                            enabled          = $false;

                        };                    
                                
                        qosClassificationMapping = $null

                    },
                                
                    #7
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 100;
                            bandwidthShare   = "25";
                            egressDot1pValue = 2;
                            realTime         = $false;
                            className        = "Medium";
                            enabled          = $true;

                        };
                                    
                        qosClassificationMapping = [PSCustomObject]@{

                            dot1pClassMapping = [System.Collections.ArrayList]@(4,3,2);
                            dscpClassMapping  = [System.Collections.ArrayList]@(

                                "DSCP 18, AF21",
                                "DSCP 20, AF22",
                                "DSCP 22, AF23",
                                "DSCP 26, AF31",
                                "DSCP 28, AF32",
                                "DSCP 30, AF33",
                                "DSCP 34, AF41",
                                "DSCP 36, AF42",
                                "DSCP 38, AF43",
                                "DSCP 16, CS2",
                                "DSCP 24, CS3",
                                "DSCP 32, CS4"

                            )

                        }

                    },
                                
                    #8
                    [PSCustomObject]@{ 
                        qosTrafficClass = [PSCustomObject]@{

                            maxBandwidth     = 10;
                            bandwidthShare   = "10";
                            egressDot1pValue = 5;
                            realTime         = $true;
                            className        = "Real time";
                            enabled          = $true;

                        };
                                    
                        qosClassificationMapping = [PSCustomObject]@{

                            dot1pClassMapping = [System.Collections.ArrayList]@(5,6,7);
                            dscpClassMapping  = [System.Collections.ArrayList]@(

                                "DSCP 46, EF",
                                "DSCP 40, CS5",
                                "DSCP 48, CS6",
                                "DSCP 56, CS7"

                            )

                        }

                    }
                
                )

            }

            # Default BestEffort Traffic Class
            "DefaultBestEffortTrafficClass"
            {
                
                Return [PSCustomObject]@{ 

                    qosTrafficClass = [PSCustomObject]@{

                        maxBandwidth     = 100;
                        bandwidthShare   = "65";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Best effort";
                        enabled          = $true;

                    };
                                
                    qosClassificationMapping = [PSCustomObject]@{

                        dot1pClassMapping = [System.Collections.ArrayList]@(1,0);
                        dscpClassMapping  = [System.Collections.ArrayList]@(

                            "DSCP 10, AF11",
                            "DSCP 12, AF12",
                            "DSCP 14, AF13",
                            "DSCP 8, CS1",
                            "DSCP 0, CS0"

                        )

                    }

                }

            }

            # FCoE Lossless Traffic Class
            "FCoELossLessTrafficClass"
            {

                Return [PSCustomObject]@{ 

                    qosTrafficClass = [PSCustomObject]@{
                
                        maxBandwidth     = 100;
                        bandwidthShare   = "fcoe";
                        egressDot1pValue = 3;
                        realTime         = $false;
                        className        = "FCoE lossless";
                        enabled          = $true;
                
                    };                    
                                
                    qosClassificationMapping = [PSCustomObject]@{
                
                        dot1pClassMapping = [System.Collections.ArrayList]@(3);
                        dscpClassMapping  = [System.Collections.ArrayList]::new()
                
                    }
                
                }

            }
            
            #Basic, not enabled Traffic Class
            "BaseTrafficClass"
            {
                
                Return [PSCustomObject]@{ 
                    
                    qosTrafficClass = [PSCustomObject]@{
                    
                        maxBandwidth     = 100;
                        bandwidthShare   = "0";
                        egressDot1pValue = 0;
                        realTime         = $false;
                        className        = "Class";
                        enabled          = $false;
                    
                    };
                                    
                    qosClassificationMapping = [PSCustomObject]@{
                            
                        dot1pClassMapping = [System.Collections.ArrayList]::new();
                        dscpClassMapping  = [System.Collections.ArrayList]::new()
                            
                    }

                }

            }

            "Ping"
            {

                Return [PSCustomObject]@{

                    type        = "PingDto";
                    address     = "example.com";
                    noOfPackets = 5

                }

            }

            "liUplinkSetObject"
            {
            
                Return [PSCustomObject]@{

                    type                           = "uplink-setV6";
                    name                           = $Name; 
                    networkUris                    = [System.Collections.ArrayList]::new();
                    portConfigInfos                = [System.Collections.ArrayList]::new();
                    networkType                    = $null; 
                    primaryPortLocation            = $null;
                    fcNetworkUris                  = [System.Collections.ArrayList]::new();
                    fcoeNetworkUris                = [System.Collections.ArrayList]::new();                
                    connectionMode                 = $null; 
                    ethernetNetworkType            = $null; 
                    lacpTimer                      = 'Short';
                    logicalInterconnectUri         = $null;
                    manualLoginRedistributionState = 'NotSupported';
                    fcMode                         = 'NA'

                }
            
            }

            'ligUplinkSetObject'
            {

                Return [PSCustomObject]@{

                    logicalPortConfigInfos = [System.Collections.ArrayList]::new();
                    networkUris            = [System.Collections.ArrayList]::new();
                    name                   = $null; 
                    mode                   = 'Auto'; 
                    networkType            = "Ethernet";
                    primaryPort            = $null;
                    ethernetNetworkType    = "NotApplicable"; 
                    lacpTimer              = 'Short';
                    fcMode                 = 'NA';
                    loadBalancingMode      = 'None';
                    consistencyChecking    = $LIGConsistencyCheckingEnum.Exact;
                    networkSetUris         = [System.Collections.ArrayList]::new();
                    privateVlanDomains     = [System.Collections.ArrayList]::new()

                }

            }

            'UplinkSetLogicalLocation'
            {
                
                Return [PSCustomObject]@{
                    
                    desiredSpeed    = $null;
                    logicalLocation = [PSCustomObject]@{
                                        
                        locationEntries =  [System.Collections.ArrayList]::new()
                    
                    }
                    
                }

            }

            'UplinkSetLocation'
            {
                
                Return [PSCustomObject]@{

                    desiredSpeed = $null;
                    location     = [PSCustomObject]@{
                                        
                        locationEntries = [System.Collections.ArrayList]::new()

                    }
                    
                }

            }

            'UplinkSetLogicalLocationEntry'
            {

                Return [PSCustomObject]@{
                                            
                    type          = $Null;
                    relativeValue = 1

                }

            }
                
            'UplinkSetLocationEntry'
            {

                Return [PSCustomObject]@{
                                            
                    type  = $Null;
                    value = 1

                }

            }

            'VcMigration'
            {

                Return [PSCustomObject]@{

                    enclosureGroupUri           = $Null;
                    iloLicenseType              = $Null;
                    credentials                 = [PSCustomObject]@{
                                            
                         oaIpAddress            = $Null;
                         oaUsername             = $Null;
                         oaPassword             = $Null;
                         vcmUsername            = $Null;
                         vcmPassword            = $Null;
                         type                   = "EnclosureCredentials"
                                            
                    };                            
                    category                    = "migratable-vc-domains";
                    type                        = "MigratableVcDomainV300"

                }

            }

        }

    }

}

#######################################################
# Basic Support functions
#

function Wait-Reboot
{

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory, Position = 0)]
        [Int]$Time = 600

    )

    $_Time = $Time

    foreach ($i in (1..$_Time)) 
    {

        $_Percentage = $i / $_Time
        
        $_Remaining = New-TimeSpan -Seconds ($_Time - $i)

        $_Message = "Remaining time {0}" -f $_Remaining

        Write-Progress -Activity $_Message -PercentComplete ($_Percentage * 100)
        
        Start-Sleep 1

    }

    Write-Progress -Activity $_Message -Completed

}

function Join-Scope
{

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory, Position = 0)]
        [Object]$Scope

    )

    Begin
    {

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Debug

    }

    Process
    {

        $_ScopeQueryStringBuilder = New-Object "System.Collections.Generic.List``1[[System.String]]"

        ForEach ($_scope in $Scope)
        {

            if ($_scope -isnot [HPOneView.Appliance.ScopeCollection] -and $_scope -isnot [HPOneView.Appliance.ConnectionPermission])
            {

                "[{0}] Scope {1} is not a valid HPOneView.Appliance.ScopeCollection resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_scope | Write-Verbose

                $ExceptionMessage = "Scope {0} is not a valid HPOneView.Appliance.ScopeCollection resource." -f $_scope
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ScopeResourceException ScopeResourceNotFound ObjectNotFound -TargetObject 'Name' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($_scope -is [HPOneView.Appliance.ScopeCollection])
            {

                $_ScopeName = $_scope.Name

            }

            else
            {

                $_ScopeName = $_scope.ScopeName

            }

            if (-not ($_ScopeQueryStringBuilder | Where-Object { $_ -match $_ScopeName }) -and $_ScopeName -ne 'AllResources')
            {

                "[{0}] Adding Scope {1} to collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeName | Write-Verbose

                [void]$_ScopeQueryStringBuilder.add(("scope:'{0}'" -f $_ScopeName))

            }        

        }

        Return [String]::Join(' OR ', $_ScopeQueryStringBuilder.ToArray())

    }    

}

function Get-InitialScopeUris
{

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory = $false, Position = 0)]
        [HPOneView.Appliance.ScopeCollection[]]$Scopes,

        [Parameter (Mandatory, Position = 1)]
        [ValidateSet ('Server', 'Networking', 'Storage')]
        [String]$ResourceType,

        [Parameter (Mandatory, Position = 2)]
        [Object]$Appliance

    )

    Begin
    {

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Debug

    }

    Process
    {

        $_ScopeUriCol = New-Object "System.Collections.ArrayList"

        if (-not $Scopes)
        {

            $ScopePermissions = ($ConnectedSessions | Where-Object Name -eq $Appliance.Name).ActivePermissions | Where-Object RoleName -match $ResourceType

            ForEach ($_scopePermission in ($ScopePermissions | Where-Object ScopeName -ne 'AllResources'))
            {

                Try
                {

                    $_scope = Get-HPOVScope -Name $_scopePermission.ScopeName
                    [void]$_ScopeUriCol.Add($_scope.Uri)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            ForEach ($_scope in $Scopes)
            {

                [void]$_ScopeUriCol.Add($_scope.Uri)

            }

        }

        return $_ScopeUriCol

    }
    

}

function ConvertFromEmbeddedJsonString
{

    [CmdletBinding ()]

    Param 
    (

        [String]$String

    )

    $_pos1 = $String.IndexOf("{")
    $_pos2 = $String.IndexOf("}")

    if ($_pos1 -ne -1)
    {

        $_SubstringToReplace = $String.Substring($_pos1).SubString(0, ($_pos2 - $_pos1 + 1))

        $_EmbeddedJson = $String.Substring($_pos1).SubString(0, ($_pos2 - $_pos1 + 1)).Replace('\', $null) | ConvertFrom-Json

        Return $String.Replace($_SubstringToReplace, ('"{0}"' -f $_EmbeddedJson.name))

    }

    else
    {

        Return $String
        
    }

}

function New-ErrorRecord 
{

    <#
        .Synopsis
        Creates an custom ErrorRecord that can be used to report a terminating or non-terminating error.
         
        .Description
        Creates an custom ErrorRecord that can be used to report a terminating or non-terminating error.
         
        .Parameter Exception
        The Exception that will be associated with the ErrorRecord.
         
        .Parameter ErrorID
        A scripter-defined identifier of the error. This identifier must be a non-localized string for a specific error type.
         
        .Parameter ErrorCategory
        An ErrorCategory enumeration that defines the category of the error. The supported Category Members are (from: http://msdn.microsoft.com/en-us/library/system.management.automation.errorcategory(v=vs.85).aspx) :
             
            * AuthenticationError - An error that occurs when the user cannot be authenticated by the service. This could mean that the credentials are invalid or that the authentication system is not functioning properly.
            * CloseError - An error that occurs during closing.
            * ConnectionError - An error that occurs when a network connection that the operation depEnds on cannot be established or maintained.
            * DeadlockDetected - An error that occurs when a deadlock is detected.
            * DeviceError - An error that occurs when a device reports an error.
            * FromStdErr - An error that occurs when a non-Windows PowerShell command reports an error to its STDERR pipe.
            * InvalidArgument - An error that occurs when an argument that is not valid is specified.
            * InvalidData - An error that occurs when data that is not valid is specified.
            * InvalidOperation - An error that occurs when an operation that is not valid is requested.
            * InvalidResult - An error that occurs when a result that is not valid is returned.
            * InvalidType - An error that occurs when a .NET Framework type that is not valid is specified.
            * LimitsExceeded - An error that occurs when internal limits prevent the operation from being executed.
            * MetadataError - An error that occurs when metadata contains an error.
            * NotEnabled - An error that occurs when the operation attempts to use functionality that is currently disabled.
            * NotImplemented - An error that occurs when a referenced application programming interface (API) is not implemented.
            * NotInstalled - An error that occurs when an item is not installed.
            * NotSpecified - An unspecified error. Use only when not enough is known about the error to assign it to another error category. Avoid using this category if you have any information about the error, even if that information is incomplete.
            * ObjectNotFound - An error that occurs when an object cannot be found.
            * OpenError - An error that occurs during opening.
            * OperationStopped - An error that occurs when an operation has stopped. For example, the user interrupts the operation.
            * OperationTimeout - An error that occurs when an operation has exceeded its timeout limit.
            * ParserError - An error that occurs when a parser encounters an error.
            * PermissionDenied - An error that occurs when an operation is not permitted.
            * ProtocolError An error that occurs when the contract of a protocol is not being followed. This error should not happen with well-behaved components.
            * QuotaExceeded An error that occurs when controls on the use of traffic or resources prevent the operation from being executed.
            * ReadError An error that occurs during reading.
            * ResourceBusy An error that occurs when a resource is busy.
            * ResourceExists An error that occurs when a resource already exists.
            * ResourceUnavailable An error that occurs when a resource is unavailable.
            * SecurityError An error that occurs when a security violation occurs. This field is introduced in Windows PowerShell 2.0.
            * SyntaxError An error that occurs when a command is syntactically incorrect.
            * WriteError An error that occurs during writing.
         
        .Parameter TargetObject
        The object that was being Processed when the error took place.
         
        .Parameter Message
        Describes the Exception to the user.
         
        .Parameter InnerException
        The Exception instance that caused the Exception association with the ErrorRecord.
        .Parameter TargetType
        To customize the TargetType value, specify the appropriate Target object type. Values can be "Array", "PSObject", "HashTable", etc. Can be provided by ${ParameterName}.GetType().Name.
         
        .Example
    #>


    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory, Position = 0)]
        [System.String]$Exception,

        [Parameter (Mandatory, Position = 1)]
        [Alias ('ID')]
        [System.String]$ErrorId,

        [Parameter (Mandatory, Position = 2)]
        [Alias ('Category')]
        [ValidateSet ('AuthenticationError','ConnectionError','NotSpecified', 'OpenError', 'CloseError', 'DeviceError',
            'DeadlockDetected', 'InvalidArgument', 'InvalidData', 'InvalidOperation',
                'InvalidResult', 'InvalidType', 'MetadataError', 'NotImplemented',
                    'NotInstalled', 'ObjectNotFound', 'OperationStopped', 'OperationTimeout',
                        'SyntaxError', 'ParserError', 'PermissionDenied', 'ResourceBusy',
                            'ResourceExists', 'ResourceUnavailable', 'ReadError', 'WriteError',
                                'FromStdErr', 'SecurityError')]
        [System.Management.Automation.ErrorCategory]$ErrorCategory,

        [Parameter (Mandatory, Position = 3)]
        [System.Object]$TargetObject,

        [Parameter (Mandatory)]
        [System.String]$Message,

        [Parameter (Mandatory = $false)]
        [System.Exception]$InnerException,

        [Parameter (Mandatory = $false)]
        [System.String]$TargetType = "String"

    )

    Process 
    {

        # ...build and save the new Exception depending on present arguments, if it...
        $_exception = if ($Message -and $InnerException) {
            # ...includes a custom message and an inner exception
            New-Object $Exception $Message, $InnerException
        } elseif ($Message) {
            # ...includes a custom message only
            New-Object $Exception $Message
        } else {
            # ...is just the exception full name
            New-Object $Exception
        }

        # now build and output the new ErrorRecord
        "[{0}] Building ErrorRecord object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $record = New-Object Management.Automation.ErrorRecord $_exception, $ErrorID, $ErrorCategory, $TargetObject

        $record.CategoryInfo.TargetType = $TargetType

        Return $record
    }

}

function Enable-HPOVMSDSC 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]

    Param ()

    Begin { }

    Process 
    {

        $RegKey = "HKCU:\Software\Hewlett-Packard\HPOneView"

        if (-not(Test-Path $RegKey)) { New-Item -Path $RegKey -force | Write-Verbose }

        $UseMSDSC = [Bool](Get-ItemProperty -LiteralPath $RegKey -ea silentlycontinue).'UseMSDSC'

        if (-not($UseMSDSC)) { New-ItemProperty -Path $RegKey -Name UseMSDSC -Value 1 -Type DWORD | Write-Verbose }

        else { Set-ItemProperty -Path $RegKey -Name UseMSDSC -Value 1 -Type DWORD | Write-Verbose }

    }

    End { }

}

function Disable-HPOVMSDSC 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]

    Param ()

    Begin { }

    Process 
    {

        $RegKey = "HKCU:\Software\Hewlett-Packard\HPOneView"

        if (-not(Test-Path $RegKey)) { New-Item -Path $RegKey -force | Write-Verbose }

        $UseMSDSC = [Bool](Get-ItemProperty -LiteralPath $RegKey -ea silentlycontinue).'UseMSDSC'

        if (-not($UseMSDSC)) { New-ItemProperty -Path $RegKey -Name UseMSDSC -Value 0 -Type DWORD | Write-Verbose }

        else { Set-ItemProperty -Path $RegKey -Name UseMSDSC -Value 0 -Type DWORD | Write-Verbose }

    }

    End { }

}

function RestClient 
{

    <#
 
        .SYNOPSIS
        Internal Private Class for building a RestClient using [System.Net.WebRequest]
 
        .DESCRIPTION
        This is a private, internal class/function to create a new [System.Net.WebRequest] object with pre-defined properties of the HttpWebReqeuest connection. This class will set the following attributes, which the caller can overload the values with their own after the resource has been created:
 
            Timeout = 20000
            ContentType = "application/json"
            Accept = "application/json"
            Headers.Item("X-API-Version") = $MaxXAPIVersion
            Headers.Item("accept-language") = "en_US"
            Headers.Item("accept-encoding") = "gzip, deflate"
            Headers.Item("auth") = ${Global:ConnectedSessions}.sessionID NOTE: Only if the sessionID exists.
            AutomaticDecompression = "GZip,Deflate,None"
 
        The URI of the WebRequest object will automatically include the connected (or requested if the first call is Connect-HPOVMgmt) appliance address or name ($script:HPOneViewAppliance). This value can be overloaded, but the Auth token that may be included as an HTTP header item could be invalid.
 
        .INPUTS
        None.
 
        .OUTPUTS
        New [System.Net.WebRequest] object.
 
        .Parameter URI
        The URI of the request. Do not include the appaliance hostname or IP Address, only the cononical URI value (i.e. /rest/server-hardware).
 
        .Parameter Method
        Optional. Provide the HTTP method for the request. The default value is 'GET'. Only the following values are allowed:
 
            GET
            PUT
            POST
            DELETE
            PATCH
 
        .Parameter Appliance
        Provide the appliance hostname or FQDN.
 
    #>


    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $False, Position = 0)]
        [ValidateScript({if ("GET","POST","DELETE","PATCH","PUT" -match $_) {$true} else { Throw "'$_' is not a valid Method. Only GET, POST, DELETE, PATCH, or PUT are allowed." }})]
        [String]$method = "GET",

        [Parameter (Mandatory, Position = 1)]
        [ValidateScript({if ($_.startswith('/')) {$true} else {throw "-URI must being with a '/' (eg. /rest/server-hardware) in its value. Please correct the value and try again."}})]
        [String]$uri,

        [Parameter (Mandatory, Position = 2)]
        [ValidateNotNullorEmpty()]
        [String]$Appliance = $Null

    )

    Begin 
    {

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Debug

        $url = 'https://{0}{1}' -f $Appliance, $uri

        "[{0}] Building new [System.Net.HttpWebRequest] object for {1} {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $method, $url | Write-Verbose

    }

    Process 
    {

        $RestClient = (New-Object HPOneView.Utilities.Net).RestClient($url, $Method, $MaxXAPIVersion)

        $GuidRegEx = "$($LogicalInterconnectsUri.Replace('/','\/'))\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\/support-dumps"

        if ($ExtendedTimeoutUris -contains $uri -or ([RegEx]::Match($uri, $GuidRegEx) -and $Uri.StartsWith($LogicalInterconnectsUri)))
        {

            "[{0}] Increasing timeout to 10 minutes for '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Uri | Write-Verbose

            # Increase timeout to 10 minutes.
            $RestClient.Timeout = 600000

        }

    }

    End 
    {

        Return $RestClient

    }

}

function RedactPassword
{

    [CmdletBinding ()]
    Param 
    (

        [Hashtable]$BoundParameters

    )

    $Caller = (Get-PSCallStack)[1].Command

    '[{0}] Redacting users Password from Verbose Output' -f $Caller | Write-Verbose 

    $_Params = @{}

    $PSBoundParameters.BoundParameters.GetEnumerator() | ForEach-Object {

        if ($_Params.($_.Key) -is [PSCustomObject])
        {

            $_Params.Add($_.Key,$PSBoundParameters.BoundParameters.($_.Key).PSObject.Copy())

        }

        else
        {

            $_Params.Add($_.Key,$_.Value)


        }

        # Handle Level 1
        if ($_Params.password)
        {


            $_Params.password = '[*****REDACTED******]'

        } 

        # Handle Level 2
        if ($_Params.($_.Key).password)
        {

            $_Params.($_.Key).password = '[*****REDACTED******]'

        }

    }

    "[{0}] Bound PS Parameters: {1}" -f $Caller, ($_Params | out-string) | Write-Verbose

}

function Send-HPOVRequest 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Position = 0, Mandatory)]
        [ValidateScript ({if ($_.startswith('/')) {$true} else {throw "-URI must being with a '/' (eg. /rest/server-hardware) in its value. Please correct the value and try again."}})]
        [String]$uri,

        [Parameter (Position = 1, Mandatory = $false)]
        [ValidateScript ({if ("GET","POST","DELETE","PATCH","PUT" -match $_) {$true} else { Throw "'$_' is not a valid Method. Only GET, POST, DELETE, PATCH, or PUT are allowed." }})]
        [String]$method = "GET",
        
        [Parameter (Position = 2, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [object]$body,

        [Parameter (Position = 3, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$start = 0,

        [Parameter (Position = 4, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$count = 0,

        [Parameter (Position = 5, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [hashtable]$AddHeader,

        [Parameter (Position = 6, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$OverrideContentType,

        [Parameter (Position = 7, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$OverrideTimeout,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance','ApplianceConnection')]
        [Object]$Hostname = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    { 

        "[{0}] BEGIN" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($uri -eq $ApplianceLoginSessionsUri -and $Method -eq 'POST')
        {

            # RedactPassword -BoundParameters $PSBoundParameters

        }

        else
        {

            "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        }

        # Support getting the Appliance Connection Name from the object being passed within the body Param
        if ($PSBoundParameters['body'] -and $body.ApplianceConnection -and (-not($Hostname)) -and ($body -isnot [System.Collections.IEnumerable]))
        {

            "[{0}] Getting the Appliance Connection Name from the object being passed within the body Param" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $Hostname = $body.ApplianceConnection.Name

        }

        # Collection to return all responses from all specified appliance connections
        $AllResponses = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $c = 1

        if (-not($PSboundParameters['Hostname']) -and (-not([Bool]($Hostname | Measure-Object).count)))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoAuthSession ObjectNotFound 'Hostname' -Message "No appliance Hostname Parameter provided and no valid appliance session(s) found."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        ForEach ($ApplianceHost in $Hostname) 
        {

            "[{0}] Process" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Hostname value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($ApplianceHost | Out-String) | Write-Verbose

            # Clear last error response for the connection we are going to make.
            if (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name)
            {

                "[{0}] Prior Global Response Error Object for '{1}' found. Clearing." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceHost.Name | Write-Verbose

                $_ResponseObject = (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name)

                [void]${Global:ResponseErrorObject}.Remove($_ResponseObject)

            }
            
            # If the value is String, we assume this is the Appliance Hostname, so look up the Connection details in ${Global:ConnectedSessions}
            if ($ApplianceHost -is [String] -and (${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceHost )) 
            {

                "[{0}] Filtering for Connection Object via String: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceHost | Write-Verbose

                $ApplianceHost = ${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceHost

            }

            elseif ($ApplianceHost -isnot [HPOneView.Appliance.Connection] -and $ApplianceHost.Name)
            {

                "[{0}] Filtering for Connection Object via PSObject: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($ApplianceHost | Out-String) | Write-Verbose

                $ApplianceHost = ${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceHost.Name

            }

            "[{0}] Processing '{1}' appliance connection request. {2} of {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceHost.Name,$c,$Hostname.count | Write-Verbose 

            # Need to check for authenticated session when the URI passed is not value of $WhiteListedURIs
            "[{0}] Requested URI '{1}' to '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $uri, ($ApplianceHost.Name -join ',') | Write-Verbose 

            if ($WhiteListedURIs -contains $uri) 
            {

                "[{0}] We have reached the URI Whitelist condition block. Unauth request allowed for '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $uri | Write-Verbose

            }
                
            # Else, require authentication
            elseif (-not($ApplianceHost.SessionID)) 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoAuthSession AuthenticationError 'Send-HPOVRequest' -Message "No valid session ID found for '$($ApplianceHost.Name)'. The call to '$uri' requires authentication. Please use Connect-HPOVMgmt to connect and authenticate to an appliance."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
    
            # Pagination handling:
            $AllMembers = [System.Collections.ArrayList]::new()

            # See if the caller specified a count, either in the URI or as a Param
            # (if so, we will let them handle pagination manually)
            [Bool]$manualPaging = $false

            if ($uri.ToLower().Contains("count=") -or $uri.ToLower().Contains("count =")) 
            {

                $manualPaging = $true

            }

            elseif ($count -gt 0) 
            {

                $manualPaging = $true

                # Add start & count params to the URI
                if (-not ($uri -contains "?")) 
                {

                    $uri += "?"    

                }

                $uri += ("start=" + $start + "&")

                $uri += ("count=" + $count)

            }

            elseif ($start -gt 0) 
            {

                # Start specified, but no count -- just set the start Param & auto-page from there on:
                $manualPaging = $false

                if (-not ($uri -contains "?")) 
                {

                    $uri += "?"   
                 
                }

                $uri += ("start=" + $start)

            }

            do 
            {

                $_TelemetryStopWatch = [system.diagnostics.stopwatch]::startNew()

                # Used to keep track of async task response
                $taskReceived = $False

                [System.Net.WebRequest]$req = RestClient $method $uri $ApplianceHost.Name

                if ($PSBoundParameters['OverrideContentType'])
                {

                    $req.ContentType = $PSBoundParameters['OverrideContentType']

                }

                if ($PSBoundParameters['OverrideTimeout'])
                {

                    $req.Timeout = $OverrideTimeout
                    
                }

                # Add Auth Session token if it exists
                if ($ApplianceHost.SessionID -and $ApplianceHost.SessionID -ne 'TemporaryConnection') 
                { 
                    
                    $req.Headers.Item("auth") = $ApplianceHost.SessionID 
                
                }

                # Handle additional headers being passed in for updated API (storage volume removal)
                # Variable defined as a hashtable in case other API pass more than one additional header
                if($PSBoundParameters['AddHeader'])
                {

                    ForEach ($_header in $AddHeader.GetEnumerator())
                    {

                        # "[{0}] Overloading '{1}' in HttpWebRequest object to: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_header.Key, $_header.Value | Write-Verbose

                        if ($_header.Key -eq 'If-Match')
                        {

                            [void]$req.Headers.Add("If-Match: *")

                            $DateTimeRef = New-Object DateTime

                            if ([DateTime]::TryParse($_header.Value, [ref]$DateTimeRef) -and $_header.Value -is [DateTime])
                            {

                                $_CorrectedEtag = $_header.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")

                                $req.Headers.Item($_header.Key) = $_CorrectedEtag

                                "[{0}] (DELETE) ETag was converted to [DateTime] object by PowerShell. Changing back to string value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_CorrectedEtag | Write-Verbose

                            }

                        }

                        else
                        {

                            "[{0}] Overloading '{1}' in HttpWebRequest object to: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_header.Key, $_header.Value | Write-Verbose

                            $req.Headers.Item($_header.Key) = [String]$_header.Value

                        }
                        
                    }

                }

                # Adding due to X-API-Version 500 requirement to pass If-Match header for DELETE requests.
                if ($Method -eq 'DELETE' -and -not $req.Headers.Item('If-Match') -and $Uri -ne $ApplianceLoginSessionsUri)
                {
                    
                    Throw (New-Object Exception("The Method requested was DELETE but the required 'If-Match' HTTP header is not found."))

                }

                # Remove If-Match for removing users and groups
                if ($Method -eq 'DELETE' -and ($ApplianceUserAccountsUri, $AuthnEgroupRoleMappingUri | % { $Uri.contains($_)}) -contains $True)
                {

                    $req.Headers.Remove('If-Match')

                }

                # $Body will contain the certificate object
                if ($Uri -contains $ApplianceLoginSessionsSmartCardAuthUri -and $Method -eq 'POST')
                {

                    "[{0}] Initiating SmartCard auth. Adding client certificate to request object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [void]$req.ClientCertificates.Add($Body[0])
                    $req.UseDefaultCredentials = $true
                    
                }

                # Send the request with a messege
                elseif ($body) 
                {

                    "[{0}] Body object found. Converting to JSON." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    if (('PUT','PATCH' -contains $method) -and $null -eq $req.Headers.Item('If-Match') -and $null -ne $Body.eTag) 
                    {

                        $_ETag = $body.eTag

                        if ($_ETag -is [DateTime])
                        {

                            "[{0}] (BODY1) ETag was converted to [DateTime] object by PowerShell. Changing back to string value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $DateTimeRef = New-Object DateTime

                            if ([DateTime]::TryParse($_ETag, [ref]$DateTimeRef) -and $_ETag -is [DateTime])
                            {

                                $req.Headers.Item("If-match") = $_ETag.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")

                                "[{0}] (BODY2) ETag was converted to [DateTime] object by PowerShell. Changing back to string value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $req.Headers.Item($_header.Key) | Write-Verbose

                            }

                        }

                        else
                        {

                            $req.Headers.Item("If-match") = $_Etag


                        }

                        "[{0}] HTTP Method is {1} and eTag value found {2}. Setting 'If-Match' HTTP Header." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Method, $_Etag | Write-Verbose

                    }

                    # Remove any found ApplianceConnection property(ies) to not generate REST API Error
                    if ('PUT', 'PATCH', 'POST' -contains $method -and $body -isnot [System.String])
                    {

                        "[{0}] HTTP Method is $method. Removing 'ApplianceConnection' NoteProperty from object(s)." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $body = Remove-ApplianceConnection $body

                    }

                    if ($method -eq "PATCH" -and ($body -isnot [Array]))
                    {

                        "[{0}] Patch Request and body is not an Array." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [Array]$body = @($body)

                    }
                    
                    # Create a new stream writer to write the json to the request stream.
                    if ($body -isnot [String])
                    {

                        $js = ConvertTo-Json $body -Depth 99 -Compress

                    }

                    else
                    {

                        $js = $body

                    }

                    # Needed to remove \r character that ConvertTo-JSON adds which /rest/logindirectories does not support for the directory server SSL certificate
                    if ($body.type -match "LoginDomainConfig*Dto") 
                    { 
                        
                        $js = $js -replace "\\r",$null 
                    
                    }

                    if ($uri -eq $LoginSessionsUri -and $Method -eq 'POST')
                    {

                        '[{0}] Request Body: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), (ConvertTo-Json -InputObject $_Params.body -Depth 99 -Compress) | Write-Verbose 
                    
                    }

                    else
                    {

                        "[{0}] Request Body: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $js | Write-Verbose 

                    }

                    # Send the messege
                    try 
                    {

                        $stream = New-Object IO.StreamWriter($req.GetRequestStream())

                        $stream.AutoFlush = $True
                        $stream.WriteLine($js)
                        $stream.Flush()
                        
                    }

                    catch 
                    {                        

                        $PSCmdlet.ThrowTerminatingError($_)
                        
                    }

                    finally
                    {

                        $stream.Close()

                        if ($stream -is [System.IDisposable])
                        {

                            $stream.Dispose()

                        }

                    }                

                }                

                "[{0}] Request: {1} https://{2}{3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $req.Method, $ApplianceHost.Name, $Uri | Write-Verbose
   
                # Write Verbose the headers if needed
                $i = 0

                foreach ($h in $req.Headers) 
                { 

                    # Remove Auth Token info from Headers
                    if ($h -eq 'auth')
                    {

                        "[{0}] Request Header {1}: {2} = [*****REDACTED******]" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($i+1), $h | Write-Verbose

                    }

                    else
                    {

                        "[{0}] Request Header {1}: {2} = {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($i+1), $h, $req.Headers[$i] | Write-Verbose

                    }

                    $i++ 

                }

                try 
                {

                    # Get response from appliance
                    [System.Net.WebResponse]$LastWebResponse = $req.GetResponse()

                    $_TelemetryStopWatch.Stop()

                    "[{0}] Response time: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_TelemetryStopWatch.Elapsed.ToString() | Write-Verbose

                    # Display the response status if verbose output is requested
                    "[{0}] Response Status: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Int]$LastWebResponse.StatusCode, [String]$LastWebResponse.StatusDescription | Write-Verbose

                    $i = 0

                    foreach ($h in $LastWebResponse.Headers) 
                    { 
                        
                        "[{0}] Response Header {1}: {2} = {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($i+1), $h, $LastWebResponse.Headers[$i] | Write-Verbose
                        
                        $i++ 
                    
                    }

                    # Read the response
                    $reader = New-Object IO.StreamReader($LastWebResponse.GetResponseStream())

                    $FinalResponse = $reader.ReadToEnd()

                    $reader.close()

                    "[{0}] FinalResponse: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $FinalResponse | Write-Verbose

                    # Added for #407
                    $_DuplicateJsonPattern = @('\"NVIDIA TESLA M10\"\:\[[\w]*[\,]?[\w]*\][\,]?', '\"[I|i]LO\"\:\[[null\,]*\"\d\.\d+\"\][,]?')

                    ForEach ($_Pattern in $_DuplicateJsonPattern)
                    {

                        if ([RegEx]::Matches($FinalResponse, $_Pattern))
                        {

                            $FinalResponse = [Regex]::Replace($FinalResponse, $_Pattern, "")

                        }

                    }

                    $resp = ConvertFrom-JSON -InputObject $FinalResponse

                    if ($resp -is [String])
                    {

                        "[{0}] Response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $resp | Write-Verbose 

                    }

                    elseif ($resp -is [Boolean])
                    {

                        "[{0}] Bool Response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Bool]$resp | Write-Verbose 

                    }

                    else
                    {

                        if ($resp -is [PSCustomObject])
                        {

                            if ($resp.PSobject.Properties.name -match "sessionId")
                            {

                                $_resp = $resp.PSObject.Copy()

                                $_resp.sessionId = '[*****REDACTED******]'

                                "[{0}] Response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_resp | Format-List * -force | out-string) | Write-Verbose 

                            }

                        }

                        else
                        {

                            "[{0}] Response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($resp | Format-List * -force | out-string) | Write-Verbose 

                        }

                    }
                    
                    "[{0}] Manual Pagination: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ManualPaging | Write-Verbose

                    # If Asyncronous (HTTP status=202), make sure we return a Task object:
                    if ([Int]$LastWebResponse.StatusCode -eq 202 -and ($LastWebResponse.Headers.Item('X-Task-URI') -or $LastWebResponse.Headers.Item('Location')))
                    {

                        "[{0}] Async Task (HTTP 202) received"-f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        # AsynchronOut operation -- in some cases we get the Task object returned in the body.
                        # In other cases, we only get the Task URI in the Location header.
                        # In either case, return a Task object with as much information as we know
                        if ($LastWebResponse.Headers.Item('X-Task-URI')) 
                        {

                            [String]$TaskUri = $LastWebResponse.Headers.Item('X-Task-URI')

                        }

                        elseif ($LastWebResponse.Headers.Item('Location'))
                        {

                            [String]$TaskUri = $LastWebResponse.Headers.Item('Location')

                        }

                        if ($TaskUri)
                        {

                            "[{0}] Async Task URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $TaskUri | Write-Verbose

                            # First, make sure the task URI is relative:
                            $pos = $TaskUri.IndexOf($TasksUri)

                            if ($pos -gt 0) 
                            {

                                $TaskUri = $taskUri.SubString($pos)

                            }

                            Try
                            {

                                $resp = Send-HPOVRequest -uri $TaskUri -method GET -appliance $ApplianceHost.Name

                                "[{0}] Adding 'HPOneView.Appliance.TaskResource' to PSObject TypeNames for task object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                                $resp | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.TaskResource') }

                            }
                            
                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)
                                
                            }

                        }

                    }

                    elseif ([Int]$LastWebResponse.StatusCode -eq 202)
                    {

                        "[{0}] Return is not an Async task, but HTTP 202 was returned. Labels?" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ($Method -eq 'DELETE' -and $null -eq $resp)
                        {

                            "[{0}] Returning custom delete successful message." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $resp = [PSCustomObject]@{StatusCode = [Int]$LastWebResponse.StatusCode; Message = "Resource deleted successfully." }

                        }                        

                    }

                    # Handle Task Objects that have been directly accessed via task URI and not created async tasks (HTTP 202)
                    if (([Int]$LastWebResponse.StatusCode -eq 200 -or [Int]$LastWebResponse.StatusCode -eq 202) -and ($resp.category -eq "tasks") -and (-not($resp.PSObject.TypeNames -match "HPOneView.Appliance.TaskResource"))) 
                    {
                        
                        $resp | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.TaskResource') }

                    }

                    # User Logoff success message
                    if (([Int]$LastWebResponse.StatusCode -eq 204) -and ($uri -eq $ApplianceLoginSessionsUri))
                    {

                        $resp = [PSCustomObject]@{ Message = "User logoff successful." }

                    }

                    elseif (([Int]$LastWebResponse.StatusCode -eq 204 -or [Int]$LastWebResponse.StatusCode -eq 200) -and $method -eq "DELETE")
                    {
                        
                        $resp = [PSCustomObject]@{StatusCode = [Int]$LastWebResponse.StatusCode; Message = "Resource deleted successfully." }
                        
                    }

                    # Handle multi-page result sets
                    if ([Bool]($resp | Get-Member -Name members -ErrorAction SilentlyContinue) -and (-not($manualPaging))) 
                    {

                         "[{0}] Response members and automatic pagination" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $resp.members | ForEach-Object { 
                            
                            Add-Member -InputObject $_ -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($ApplianceHost.Name, $ApplianceHost.ConnectionId)) -Force 

                            [void]$AllMembers.Add($_) 
                        
                        }

                        "[{0}] total stored '$($AllMembers.count)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] nextPageURI: '$($AllMembers.nextPageUri)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ($resp.nextPageUri) 
                        { 

                            "[{0}] Pagination has occurred. Received $($resp.count) resources of $($resp.total)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $uri = $resp.nextPageUri

                        }

                        else 
                        { 

                            "[{0}] Reached End of pagination. Building AllResults" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $_AllResults = [PsCustomObject]@{
                                
                                members     = $AllMembers; 
                                count       = $AllMembers.Count;
                                total       = $AllMembers.Count;
                                category    = $resp.category; 
                                eTag        = $resp.eTag;
                                nextPageUri = $resp.nextPageUri;
                                start        = $resp.start;
                                prevPageUri    = $resp.prevPageUri;
                                created        = $resp.created;
                                modified    = $resp.modified;
                                uri            = $resp.uri
                            
                            }

                            [void]$AllResponses.Add($_AllResults)
                            
                        }

                    }
                    
                    elseif ($resp.members -and $manualPaging )
                    {

                        "[{0}] Response members and manual paging" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $resp.members | ForEach-Object { 

                            Add-Member -InputObject $_ -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($ApplianceHost.Name, $ApplianceHost.ConnectionId)) -Force 

                        }

                        [void]$AllResponses.Add($resp)

                    }

                    elseif ($resp)
                    {

                        "[{0}] Response object, no paging needed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Add-Member -InputObject $resp -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($ApplianceHost.Name, $ApplianceHost.ConnectionId)) -Force 

                        [void]$AllResponses.Add($resp)

                    }

                }

                catch [System.Net.WebException] 
                { 

                    "[{0}] Net.WebException Error caught" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Exception Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ | Format-List * -force | Out-String) | Write-Verbose

                    "[{0}] Exception Message: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.Message | Write-Verbose

                    "[{0}] InnerException FullyQualifiedErrorId: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.InnerException.FullyQualifiedErrorId | Write-Verbose
                    
                    "[{0}] InnerException Message: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.InnerException.Message | Write-Verbose

                    if ($_.Exception.InnerException.FullyQualifiedErrorId -eq "ApplianceTransportException")
                    {

                        $ExceptionMessage = "Unable to connect to '{0}' appliance. {1}" -f $ApplianceHost.Name, $_.Exception.InnerException.Message
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ApplianceTransportException HostnameAndCertDoNotMatch ResourceUnavailable 'Hostname' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($_.Exception.InnerException -match "System.Net.WebException: Unable to connect to the remote server") 
                    { 
                    
                        $ExceptionMessage = "Unable to connect to '{0}' due to timeout." -f $ApplianceHost.Name
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.NetworkConnectionException ApplianceNotResponding ResourceUnavailable 'Hostname' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                    
                    elseif ($_.Exception.Message -match 'The remote name could not be resolved')
                    {

                        $ExceptionMessage = "Unable to connect to the appliance. {0}" -f $_.Exception.Message
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.NetworkConnectionException RemoteNameLookupFailure ObjectNotFound 'Hostname' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($_.Exception.InnerException) 
                    {

                        if ($_.Exception.InnerException.Response) 
                        {

                            "[{0}] InnerException" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $LastWebResponse = $_.Exception.InnerException.Response

                        }

                        else 
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    } 
                
                    else 
                    {

                        if ($_.Exception.Response) 
                        {

                            "[{0}] Exception" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $LastWebResponse = $_.Exception.Response

                        }

                        else 
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    if ($LastWebResponse) 
                    {

                        Try
                        {

                            "[{0}] Getting Error Response" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                            $reader = New-Object IO.StreamReader($LastWebResponse.GetResponseStream())

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $_JsonErrorResponse = $reader.ReadToEnd() 
                        $ErrorResponse = ConvertFrom-JSON -InputObject $_JsonErrorResponse

                        $reader.Close()        

                        "[{0}] ERROR RESPONSE: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_JsonErrorResponse | Write-Verbose

                        # Set Global Response Error Object
                        if (-not(${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name))
                        {
                        
                            $_NewResponseErrorObject = [PSCustomObject]@{

                                Name            = $ApplianceHost.Name
                                LastWebResponse = $LastWebResponse
                                ErrorResponse   = $ErrorResponse

                            }

                            [void]${Global:ResponseErrorObject}.Add($_NewResponseErrorObject)
                        
                        }

                        else
                        {

                            (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).LastWebResponse = $LastWebResponse
                            (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse   = $ErrorResponse

                        }                       
                        
                        "[{0}] Response Status: HTTP $([Int](${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).LastWebResponse.StatusCode) [$((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).LastWebResponse.StatusDescription)]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        foreach ($h in (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).LastWebResponse.Headers) 
                        { 
                            
                            "[{0}] Response Header: $($h) = $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).LastWebResponse.Headers[$i])" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            $i++ 
                        
                        }

                        switch ([Int](${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).LastWebResponse.StatusCode) 
                        {

                            # HTTP 400 errors
                            400 
                            {
                                
                                "[{0}] HTTP 400 error caught." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                if ([System.String]::IsNullOrWhiteSpace(($Global:ResponseErrorObject | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details))
                                {

                                    $_Message = "{0} {1} " -f ($Global:ResponseErrorObject | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message, ([String]::Join(' ',($global:ResponseErrorObject | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions)).trim()

                                }

                                else
                                {

                                    $_Message = "{0} {1} " -f ($Global:ResponseErrorObject | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details, ([String]::Join(' ',($global:ResponseErrorObject | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions)).trim()

                                }

                                switch ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode)
                                {

                                    'DEVICE_NOT_ELIGIBLE'
                                    {

                                        $ExceptionMessage = "The device is not eligible."
                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportResourceException DeviceNotEligible InvalidOperation "Server" -Message $ExceptionMessage
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    # Hande initial authentication errors
                                    {"AUTHN_AUTH_DIR_FAIL","AUTHN_AUTH_FAIL" -contains $_}
                                    {
                                    
                                        "[{0}] Authentication Directory failure. Likely basd username and/or password from auth dir." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                        $ConnectedSessions.RemoveConnection($ApplianceHost)
                                        
                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException InvalidUsernameOrPassword AuthenticationError "Appliance:$($ApplianceHost.Name)" -Message $_Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    # Handle invalid user session
                                    "AUTHN_LOGOUT_FAILED"
                                    {

                                        "[{0}] User session no longer valid, likely due to session timeout. Clearing library runtime global and script variables." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                        $ConnectedSessions.RemoveConnection($ApplianceHost)

                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException InvalidUserSession AuthenticationError "Appliance:$($ApplianceHost.Name)" -Message $_Message
                                        Throw $ErrorRecord

                                    }

                                    # Handle user not acknowledging login message
                                    "AUTHN_LOGIN_MESSAGE_ACKNOWLEDGMENT_REQUIRED"
                                    {

                                        "[{0}] User needed to accept the Login Message." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException LoginMessageAcknowledgementRequired AuthenticationError "Appliance:$($ApplianceHost.Name)" -Message $_Message
                                        Throw $ErrorRecord

                                    }

                                    # Valid user, but does not belong to a group that has an assigned role
                                    'AUTHN_AUTH_FAIL_NO_ROLES'
                                    {

                                        $ConnectedSessions.RemoveConnection($ApplianceHost)

                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException NoDirectoryRoleMapping AuthenticationError "Appliance:$($ApplianceHost.Name)" -Message $_Message 
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    # Valid User, but no directory group have been added
                                    'AUTHN_LOGINDOMAIN_NO_MEMBER_GROUPS_FOUND'
                                    {

                                        $ConnectedSessions.RemoveConnection($ApplianceHost)

                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException NoDirectoryRoleMapping AuthenticationError "Appliance:$($ApplianceHost.Name)" -Message $_Message 
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    default
                                    {

                                        if ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorSource) 
                                        { 
                                        
                                            $source = (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorSource 
                                    
                                        }

                                        else 
                                        { 
                                        
                                            $source = 'Send-HPOVRequest' 
                                    
                                        }

                                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidOperation InvalidOperation $source -Message $_Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                }

                            }

                            # User is unauthorized
                            401 
                            {

                                "[{0}] HTTP 401 error caught." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                
                                if ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details -cmatch "User not authorized for this operation" -or (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message -cmatch "insufficient privilege for operation") 
                                {

                                    "[{0}] $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.message) Request was '$method' at '$uri'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthPrivilegeException InsufficientPrivilege AuthenticationError 'Send-HPOVRequest' -Message ("[Send-HPOVRequest]: {0}. Request was '{1}' at '{2}'. " -f (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message, $method, $uri )
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                elseif ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode -eq "INSUFFICIENT_PRIVILEGES") 
                                {

                                    "[{0}] $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.message) Request was '$method' at '$uri'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthPrivilegeException InsufficientPrivilege AuthenticationError 'Send-HPOVRequest' -Message ("[Send-HPOVRequest]: {0}. Request was '{1}' at '{2}'. " -f (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message, $method, $uri )
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                elseif ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode -eq "INVALID_REPOSITORY_CREDENTIALS") 
                                {

                                    "[{0}] $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.message) Request was '$method' at '$uri'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthPrivilegeException ExternalRepositoryCredentials AuthenticationError $Caller -Message ("{0}" -f (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message)
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                elseif ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode -eq "AlertAuthorizationException") 
                                {

                                    "[{0}] $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.message) Request was '$method' at '$uri'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthPrivilegeException AlertAuthorizationException AuthenticationError 'Send-HPOVRequest' -Message ("[Send-HPOVRequest]: {0}. Request was '{1}' at '{2}'. " -f (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message, $method, $uri )
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                else 
                                {

                                    $ConnectedSessions.RemoveConnection($ApplianceHost)

                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidOrTimedoutSession AuthenticationError 'Send-HPOVRequest' -Message "[Send-HPOVRequest]: Your session has timed out or is not valid. Please use Connect-HPOVMgmt to authenticate to your appliance."
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                            }

                            403 
                            {
                                
                                $resp = $Null

                                if ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode -eq "PASSWORD_CHANGE_REQUIRED") 
                                { 
                                    
                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.PasswordChangeRequired PasswordExpired PermissionDenied "URI" -Message ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message + " " + (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions) 
                                
                                }
                                
                                else 
                                { 
                                    
                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ResourcePrivledgeException ResourcePrivledge PermissionDenied "URI" -Message ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message + " " + (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions) 
                                
                                }

                                Throw $ErrorRecord

                            }

                            404 
                            {
                                
                                if ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode -eq 'CHANNEL_PARTNER_VALIDATION_FAILED')
                                {

                                    $_ExceptionMessage = (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message
                                    $ErrorRecord = New-ErrorRecord HPOneview.ResourceNotFoundException ChannelPartnerNotFound ObjectNotFound 'ID' -Message $_ExceptionMessage

                                } 
                                
                                else
                                {

                                    $ErrorRecord = New-ErrorRecord HPOneview.ResourceNotFoundException ResourceNotFound ObjectNotFound "URI" -Message ("The requested resource '$uri' could not be found. " + (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.recommendedActions)

                                }

                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }
                        
                            405 
                            {
                        
                                $ErrorRecord = New-ErrorRecord InvalidOperationException (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode InvalidOperation "$($Method):$($uri)" -Message ("[Send-HPOVRequest]: The requested HTTP method is not valid/supported. " + (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details + " URI: $uri")
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            { @(409, 412) -contains $_ } 
                            {
                        
                                $ErrorRecord = New-ErrorRecord InvalidOperationException $(${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode InvalidOperation 'Send-HPOVRequest' -Message ("[Send-HPOVRequest]: $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.message) $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions)")
                                Throw $ErrorRecord

                            }

                            500 
                            {

                                if ((${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details) 
                                { 
                                    
                                    $message = (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details 
                                
                                }

                                else 
                                { 
                                    
                                    $message = (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message 
                                
                                }
                                
                                if (-not($message.SubString($message.length - 1) -eq ".")) { $message += "." }
                                
                                $ErrorRecord = New-ErrorRecord InvalidOperationException $(${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode InvalidOperation 'Send-HPOVRequest' -Message ("[Send-HPOVRequest]: $message $((${Global:ResponseErrorObject} | ? Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions)") #-InnerException $global:ResponseErrorObject
                                Throw $ErrorRecord

                            }

                            # Wait for appliance startup here by calling Wait-HPOVApplianceStart
                            { @(503, 0) -contains $_ } 
                            {
                                
                                "[{0}] HTTP $([Int]$LastWebResponse.StatusCode) error caught." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                "[{0}] Calling Wait-HPOVApplianceStart" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                Try
                                {

                                    Wait-HPOVApplianceStart -Appliance $ApplianceHost.Name

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }
                                

                                # Appliance startup should have finished.
                                "[{0}] Returning caller back to: $($method.ToUpper()) $uri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                if ($addHeader) 
                                { 
                                    
                                    return (Send-HPOVRequest -uri $uri -method $method -body $body -addHeader $addHeader -Hostname $ApplianceHost.Name) 
                                
                                }

                                elseif ($body)
                                {

                                    return (Send-HPOVRequest -uri $uri -method $method -body $body -Hostname $ApplianceHost.Name) 

                                }

                                else 
                                { 
                                    
                                    return (Send-HPOVRequest -uri $uri -method $method -Hostname $ApplianceHost.Name) 

                                }

                            }

                            501 
                            {

                                $ErrorRecord = New-ErrorRecord InvalidOperationException (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.errorCode SyntaxError 'Send-HPOVRequest' -Message ("[Send-HPOVRequest]: " + (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.message + " " + (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.recommEndedActions) -InnerException (${Global:ResponseErrorObject} | Where-Object Name -eq $ApplianceHost.Name).ErrorResponse.details
                                Throw $ErrorRecord

                            }
                            
                        } 

                    }

                    else 
                    {

                        "[{0}] No Exception Response Object to return." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        return $null

                    }

                }

                finally
                {

                    "[{0}] Cleaning up HttpWebRequest" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($reader) { $reader.Close() }

                    if ($LastWebResponse)
                    {
                        
                        $LastWebResponse.Close()

                        if ($LastWebResponse -is [System.IDisposable])
                        {

                            $LastWebResponse.Dispose()

                        }

                    }

                    if ($req) 
                    { 

                        if ($req -is [System.IDisposable])
                        {

                            $req.Dispose()

                        }

                    }

                    $req = $null

                }

                "[{0}] Does nextPageUri member exist: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Bool]($resp | Get-Member -Name nextPageUri -ErrorAction SilentlyContinue) | Write-Verbose
                "[{0}] Is nextPageUri Null or Empty: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::IsNullOrEmpty($resp.nextPageUri) | Write-Verbose

                $_Stop = $False

                # Always stop if manual paging
                if ($ManualPaging)
                {

                    '[{0}] Stopping Do/Until loop because of manual paging' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Stop = $True

                }

                # If not manual paging and nextPageUri doesn't exist, stop
                elseif (-not($ManualPaging) -and -not([Bool]($resp | Get-Member -Name nextPageUri -ErrorAction SilentlyContinue)))
                {

                    "[{0}] Stopping Do/Until loop because nextPageUri doesn't exist and have received all objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Stop = $True

                }

                # If not manual paging, nextPageUri exists and it is null or empty
                elseif (-not($ManualPaging) -and ([Bool]($resp | Get-Member -Name nextPageUri -ErrorAction SilentlyContinue)) -and [String]::IsNullOrEmpty($resp.nextPageUri))
                {
                
                    "[{0}] Stopping Do/Until loop because nextPageUri is null/empty and have received all objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Stop = $True
                
                }

            } until ($_Stop)

            $c++

        } # Continue with next appliance

    }

    End 
    {

        "[{0}] End" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $AllResponses

    }

}

function Remove-ApplianceConnection
{
    
    [CmdletBinding ()]
    [Alias ('rac')]
    Param 
    (

        [Parameter (Mandatory = $false, ValueFromPipeline, Position = 0)]
        #[ValidateNotNullorEmpty()]
        [Object]$InputObject
    
    )

    Begin
    {

        # Write-Verbose "InputObject: $($InputObject | Out-String)"

    }

    Process
    {

        if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [String] -and $InputObject -isnot [Hashtable])
        {

            Write-Verbose 'InputObject is IEnumerable'

            $Collection = [System.Collections.ArrayList]::new()

            foreach ($object in $InputObject) 
            { 

                $_UpdatedObject = Remove-ApplianceConnection $object
                
                [void]$Collection.Add($_UpdatedObject)
                
            }

            Return ,$Collection

        }

        elseif ($InputObject.GetType().Name -eq 'PSCustomObject')
        {

            Write-Verbose 'InputObject is [PSCustomObject]. Copying...'

            $_ClonedObject = $InputObject.PSObject.Copy()

            foreach ($property in $InputObject.PSObject.Properties)
            {

                if ($InputObject.($property.Name) -is [System.Collections.IEnumerable] -and $InputObject.($property.Name) -isnot [String] -and $InputObject.($property.Name) -isnot [Hashtable])
                {

                    Write-Verbose 'Property is IEnumerable'

                    $_SubCollection = [System.Collections.ArrayList]::new()

                    foreach ($_subobject in $InputObject.($property.Name)) 
                    { 
                    
                        $_UpdatedObject = Remove-ApplianceConnection $_subobject
                        
                        [void]$_SubCollection.Add($_UpdatedObject)
                        
                    }

                    $_ClonedObject.($property.Name) = $_SubCollection

                }

                else
                {

                    if ($property.Name -eq 'ApplianceConnection')
                    {
                
                        Write-Verbose 'Found ApplianceConnection prop, removing'

                        $_ClonedObject.PSObject.Properties.Remove($property.Name)

                    }

                    elseif ($InputObject.($property.Name) -is [PSCustomObject] -and $InputObject.($property.Name) -isnot [String])
                    {

                        "Nested [PSCustomObject] {0}, Processing..." -f $property.Name | Write-Verbose

                        $_ClonedObject.($property.Name) = Remove-ApplianceConnection $InputObject.($property.Name)

                    }

                }

            }

            Return $_ClonedObject

        }

        else
        {

            Return $InputObject
        
        }
    
    }

}

function ConvertTo-Object
{
        
    [CmdletBinding ()]
    Param 
    (

         [Parameter (Mandatory)]
         [ValidateNotNullOrEmpty()]
         [System.Collections.ArrayList]$Objects

    )

    Begin
    {

        $NewObjects = [System.Collections.ArrayList]::new()

    }

    Process
    {
        
        # Write-Verbose "Objects is '$($Objects.GetType().Fullname)' type."
        
        ForEach($_obj in $Objects)
        {

            # Write-Verbose "_obj is '$($_obj.GetType().Fullname)' type."

            # Write-Verbose "Processing: $($_obj.name)"

            switch ($_obj.category)
            {

                "ethernet-networks"
                {
                
                    #[HPOneView.Networking.EthernetNetwork]$_newObj = $_obj

                    $_obj.PSObject.TypeNames.Insert(0,'HPOneView.Networking.EthernetNetwork')
                
                }

                "fc-networks"
                {
                
                    #[HPOneView.Networking.FibreChannelNetwork]$_newObj = $_obj
                    $_obj.PSObject.TypeNames.Insert(0,'HPOneView.Networking.FibreChannelNetwork')
                
                }

                "fcoe-networks"
                {
                
                    #[HPOneView.Networking.FCoENetwork]$_newObj = $_obj
                    $_obj.PSObject.TypeNames.Insert(0,'HPOneView.Networking.FCoENetwork')

                }

                default
                {
                
                    #$_newObj = $_obj

                }

            }


            # Write-Verbose "_newObj is '$($_newObj.GetType().Fullname)' type."

            #[void]$NewObjects.Add($_newObj)
            [void]$NewObjects.Add($_obj)

        }

    }

    End
    {

        Return $NewObjects

    }

}

# Helper function
function Get-AllIndexResources
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [String]$Uri,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Switch]$ReturnParent,

        [Parameter (Mandatory)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $_ResourcesFromIndexCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if (-not $Uri.StartsWith($IndexUri) -and -not $Uri.StartsWith($AssociationsUri))
        {

            Throw ("URI is incorrect. Does not begin with {0} or {1}." -f $IndexUri, $AssociationsUri)

        }

        "[{0}] Processing URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        Try
        {

            $_IndexResults = Send-HPOVRequest -Uri $Uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        ForEach ($_IndexEntry in $_IndexResults.members)
        {

            if ($Uri.StartsWith($AssociationsUri) -and -not $PSBoundParameters['ReturnParent'])
            {

                "[{0}] Get full child associated object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Uri = $_IndexEntry.childUri

            }

            elseif ($Uri.StartsWith($AssociationsUri) -and $PSBoundParameters['ReturnParent'])
            {

                "[{0}] Get full parent associated object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Uri = $_IndexEntry.parentUri

            }

            else
            {

                "[{0}] Get full object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_IndexEntry.name | Write-Verbose

                $_Uri = $_IndexEntry.uri

            }        

            Try
            {

                $_FullIndexEntry = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [void]$_ResourcesFromIndexCol.Add($_FullIndexEntry)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $_ResourcesFromIndexCol

    }

}
 
function Ping-HPOVAddress
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (

        # Allow via pipeline
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [String]$Address,

        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [Int]$Packets = 5,

        [Parameter (Mandatory = $False)]
        [Switch]$Async,

        [Parameter (Mandatory= $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Allow targets to be passed via pipeline
        if (-not($PSBoundParameters['Address'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_PingObject = NewObject -Ping

            $_PingObject.address = $Address

            if ($PSBoundParameters['Packets'])
            {

                $_PingObject.noOfPackets = $Packets

            }

            Try
            {

                $_resp = Send-HPOVRequest $appliancePingTestUri POST $_PingObject -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not($PSBoundParameters['Async']))
            {

                $_resp = Wait-HPOVTaskComplete $_resp

                Write-Host " "
                $_resp.progressUpdates.statusUpdate | Write-Host
                Write-Host " "

            }
                    
            [void]$_TaskCollection.Add($_resp)

        }

    }

    End
    {

        Return $_TaskCollection

    }

}

function Wait-HPOVApplianceStart 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [Alias ('Appliance')] 
        [ValidateNotNullOrEmpty()]
        [String]$Hostname = $null
    
    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose 

        if ($Hostname -is [String])
        {

            if (-not(${Global:ConnectedSessions}.Name -contains $Hostname) -and (-not(${Global:ConnectedSessions} | Where-Object Name -eq $Hostname).SessionID))
            {

                "[{0}] Appliance Session not found. Running FTS sequence?" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose 

                "[{0}] Creating temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose 

                $_ApplianceName = $Hostname

                [HPOneView.Appliance.Connection]$Hostname = New-TemporaryConnection $Hostname

                "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname.Name | Write-Verbose 
            
            }

            else # If (${Global:ConnectedSessions}.Name -contains $Appliance)
            {

                "[{0}] Appliance is a string value, lookup connection in global tracker." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [HPOneView.Appliance.Connection]$Hostname = ${Global:ConnectedSessions} | Where-Object Name -eq $Hostname

                "[{0}] Found connection in global tracker: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Hostname | Out-String) | Write-Verbose

            }
            
        }

        elseif ($Hostname -is [HPOneView.Appliance.Connection])
        {

            "[{0}] Appliance is a Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Hostname | Out-String) | Write-Verbose

        }
    
    }

    Process 
    {

        $_SW = New-Object System.Diagnostics.Stopwatch

        $_SW.Start()

        do 
        {
            
            "[{0}] Services not started. Monitoring startup progress" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $waitRequest  = $Null
            $waitResponse = $Null

            [System.Net.httpWebRequest]$waitRequest = RestClient -uri $ApplianceStartProgressUri -appliance $Hostname.Name
            $waitRequest.Timeout = 10000

            "[{0}] REQUEST: {1} {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $waitRequest.Method, $waitRequest.RequestUri | Write-Verbose

            $i = 0

            foreach ($h in $waitRequest.Headers) 
            { 
                
                "[{0}] Request Header {1}: {2} = {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($i+1), $h, $waitRequest.Headers[$i] | Write-Verbose
                
                $i++ 
            
            }

            try 
            {

                # Get response from appliance
                "[{0}] Getting response..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $waitResponse = $waitRequest.GetResponse()
                [Int]$HttpStatusCode = $waitResponse.StatusCode

                "[{0}] Received HTTP\{1} status." -f $MyInvocation.InvocationName.ToString().ToUpper(), [Int]$waitResponse.StatusCode | Write-Verbose

                # This will trigger when the GetResponse() does not generate an HTTP Error Code and get trapped by the Catch statement below
                If ($_displayflag) 
                {

                    write-host "]"

                    # Reset flag so we don't display the Ending brace
                    $_displayflag = $False

                }

                # Read the response
                $reader = New-Object System.IO.StreamReader($waitResponse.GetResponseStream())
                $responseJson = $reader.ReadToEnd()
                $reader.Close()

                $resp = ConvertFrom-json $responseJson

                $_ActualPercentComplete = ($resp.completeComponents / $resp.totalComponents) * 100

                $StatusMessage = 'Step2: Resource managers {0} of {1}, {2:##}%' -f $resp.completeComponents, $resp.totalComponents, $_ActualPercentComplete
                
                # Handle the call from -Verbose so Write-Progress does not get borked on display.
                if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                { 
                    
                    "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StatusMessage | Write-Verbose

                }
                
                else 
                {

                    # Display progress-bar
                    Write-Progress -activity "Appliance services starting" -Status $StatusMessage -percentComplete ('{0:##}' -f $resp.percentComplete)

                }

            }

            # Catch if we haven't received HTTP 200, as we should display a nice message stating services are still beginning to start
            catch [Net.WebException] 
            {

                if ($_.Exception.Message -match 'The remote name could not be resolved')
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($waitResponse) 
                {

                    $reader = New-Object System.IO.StreamReader($waitResponse.GetResponseStream())

                    $responseJson = $reader.ReadToEnd()

                    "[{0}] ERROR RESPONSE: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($responseJson | ConvertFrom-Json | out-string) | Write-Verbose

                    "[{0}] Response Status: HTTP\{1} {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Int]$waitResponse.StatusCode, $waitResponse.StatusDescription | Write-Verbose

                    foreach ($h in $waitResponse.Headers) 
                    { 
                        
                        "[{0}] Response Header: {1} = {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $h, $waitResponse.Headers[$i] | Write-Verbose
                        
                        $i++ 
                    
                    }

                }

                "[{0}] EXCEPTION CAUGHT! HTTP Status Code: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Int]$waitResponse.StatusCode | Write-Verbose

                # Handle WebException errors that are not HTTP Status Code 503 or 0, and throw error
                if ([Int]$waitResponse.StatusCode -ne 503 -and [Int]$waitResponse.StatusCode -ne 0)
                {

                    Throw $_.Exception.Message

                }

                Write-Verbose "$($waitResponse| Out-string)"

                # Only want to display this message once.
                if (-not($_displayflag)) 
                {

                    Write-host "Waiting for services to Begin starting [" -nonewline

                }

                if (-not ([Int]$waitResponse.StatusCode -eq 200)) 
                {

                    Write-host "*" -nonewline -ForegroundColor Green

                    $_displayflag = $true

                    start-sleep -s 5

                }

            }

            finally
            {

                if ($waitResponse -is [System.IDisposable])
                {
                    
                    $waitResponse.Dispose()

                }

            }
 
            # Timeout after 10 minutes
            if ($_SW.Elapsed.TotalSeconds -ge $ApplianceStartupTimeout)
            {

                $_SW.Stop()

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.NetworkConnectionException ConnectionWaitTimeoutExceeded OperationTimeout -TargetObject 'Hostname' -Message "Timeout waiting for appliance to respond after restart event. Verify the appliance is operational and reconnect to the appliance."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            '[{0}] Ending Do Loop: {1}; Percent Complete: {2}; HTTP Status Code: {3}' -f $MyInvocation.InvocationName.ToString().ToUpper(), [Bool]([Int]$_ActualPercentComplete -eq 100 -and $HttpStatusCode -eq 200), $resp.percentComplete, $HttpStatusCode | Write-Verbose

        } until ([Int]$_ActualPercentComplete -eq 100 -and $HttpStatusCode -eq 200)

        # Remove Temporary appliance connection
        if ((${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceConnection.Name).SessionID -eq 'TemporaryConnection')
        {

            "[{0}] Removing temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ConnectedSessions.RemoveConnection($ApplianceConnection)

        }

    }

    End 
    {

        "[{0}] Web Services have started successfully" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        "[{0}] Pausing 10 seconds to let web services finish their final startup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        start-sleep -s 10

    }

}

function Connect-HPOVMgmt 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'UsernamePassword')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = 'UsernamePassword')]
        [Parameter (Mandatory, ParameterSetName = 'PSCredential')]
        [Parameter (Mandatory, ParameterSetName = 'Certificate')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance', 'Computername')]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = 'UsernamePassword')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredential')]
        [ValidateNotNullOrEmpty()]
        [Alias ('authProvider')]
        [String]$AuthLoginDomain = 'LOCAL',

        [Parameter (Mandatory, ParameterSetName = 'UsernamePassword')]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [Alias ("u",'user')]
        [String]$UserName,

        [Parameter (Mandatory = $false, ParameterSetName = 'UsernamePassword')]
        [Obsolete()]
        [Alias ("p")]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory, ParameterSetName = 'PSCredential')]
        [ValidateNotNullOrEmpty()]
        [Alias ('PSCredential')]
        [PSCredential]$Credential,

        [Parameter (Mandatory, ParameterSetName = 'Certificate')]
        [Object]$Certificate,

        [Parameter (Mandatory = $false, ParameterSetName = 'UsernamePassword')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredential')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Certificate')]
        [Switch]$LoginAcknowledge 

    )

    Begin 
    {

        # Clone PSBoundParameters
        $_Params = @{}
        
        $PSBoundParameters.GetEnumerator() | ForEach-Object {

            if ($_.Key -eq 'Password')
            {

                $_Params['Password'] = '[*****REDACTED******]'

            }

            elseif ($_.Key -eq 'Certificate')
            {

                $_Params['Certificate'] = '[*****REDACTED******]'

            }

            else
            {

                $_Params.Add($_.Key,$_.Value)

            }            

        }

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Params | out-string) | Write-Verbose
        
        # Check to see if a connection to the appliance exists
        if ((${Global:ConnectedSessions}.Name -contains $Hostname) -and ((${Global:ConnectedSessions} | Where-Object name -eq $Hostname).SessionID)) 
        {

            Write-Warning "You are already connected to $Hostname"
            continue
                
        }

        # Create the connection object for tracking
        else 
        {

            # Look for Connection where Name exists but SessionID does not, and remove the object from $ConnectedSessions
            if ((${Global:ConnectedSessions}.Name -contains $Hostname) -and (-not(${Global:ConnectedSessions} | Where-Object name -eq $Hostname).SessionID)) 
            {

                "[{0}] Found incomplete session object in `$ConnectedSessions for '{1}'. Removing." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname | Write-Verbose

                # Found incomplete session connection. must remove it from the collection first.
                $_ndx = [array]::IndexOf(${Global:ConnectedSessions}, (${Global:ConnectedSessions}.Name -contains $Hostname))

                if ($_ndx -gt 0)
                {

                    [void]${Global:ConnectedSessions}.RemoveAt($_ndx)

                }

                else
                {

                    "[{0}] Index was {1}, connection doesn't exist in global tracker." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ndx | Write-Verbose

                }    
                    
            }

            "[{0}] Creating Session Container" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $tmpConnectionId = 1

            # Figure out ConnectionId
            if (${Global:ConnectedSessions})
            {

                While (${Global:ConnectedSessions}.ConnectionId -contains $tmpConnectionId) 
                {

                    $tmpConnectionId++

                }
            
            }

            # Store the entire auth request for later deletion when issuing Disconnect-HPOVmgmt
            [HPOneView.Appliance.Connection]$ApplianceConnection = New-Object HPOneView.Appliance.Connection($tmpConnectionId, 
                                                                                                            $Hostname, 
                                                                                                            $UserName)

            if (-not(${Global:ConnectedSessions} | Where-Object Default)) 
            { 
                
                $ApplianceConnection.SetDefault($True)
            
            }

            [void]${Global:ConnectedSessions}.Add($ApplianceConnection)
            
        }

        if (-not($PSBoundParameters['Password']) -and $PSCmdlet.ParameterSetName -eq 'UsernamePassword')
        {

            [SecureString]$password = read-host -AsSecureString "Password"
            $decryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            
        }

        elseif ($Password -is [SecureString] -and $PSCmdlet.ParameterSetName -eq 'UsernamePassword')
        {

            $decryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSCmdlet.ParameterSetName -eq 'UsernamePassword')
        {

            $decryptPassword = $Password

        }

        elseif ($PSCmdlet.ParameterSetName -eq 'PSCredential')
        {

            $Username = $Credential.UserName
            $decryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        elseif ($PSCmdlet.ParameterSetName -ne 'Certificate')
        {

            $Credential = Get-Credential
            $Username = $Credential.UserName
            $decryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        # Check to make sure the appliance X-API-Version is at least the supported minimum
        "[{0}] Checking X-API Version." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
        try 
        {
            
            $applianceVersion = (Send-HPOVRequest -Uri $ApplianceXApiVersionUri -Hostname $Hostname).currentVersion

            if ($applianceVersion -and $applianceVersion -lt $MinXAPIVersion ) 
            {

                [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

                # Display terminating error
                $ErrorRecord = New-ErrorRecord System.NotImplementedException LibraryTooNew OperationStopped $Hostname -Message "The appliance you are connecting to supports an older version of this library. Please visit https://github.com/HewlettPackard/POSH-HPOneView for a supported version of the library."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        catch 
        {

            "[{0}] Exception caught when checking X-API version." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)
            
            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    Process 
    {

        try 
        {

            "[{0}] Getting global login settings to check for login message acknowledgement." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_LoginDetails = Send-HPOVRequest -Uri $ApplianceLoginDomainDetailsUri -Hostname $Hostname

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Build the parameters object depending on what type of credential passed

        $_Params = @{
            
            Uri      = $null;
            Method   = 'POST';
            Body     = $null;
            Hostname = $Hostname

        }
        
        # Username/Password or PSCredential auth
        if ($PSCmdlet.ParameterSetName -ne 'Certificate')
        {

            $_authinfo = NewObject -AuthLoginCredential
            
            $_authinfo.userName = $UserName
            $_authinfo.password = $decryptPassword

            if (-not $PSBoundParameters['AuthLoginDomain'])
            {
                
                $_authinfo.authLoginDomain = $_LoginDetails.defaultLoginDomain
                # (${Global:ConnectedSessions} | ? Name -EQ $Hostname).AuthLoginDomain = $_LoginDetails.defaultLoginDomain

            }

            else
            {
                
                $_authinfo.authLoginDomain = $AuthLoginDomain

            }

            $_Params.Uri = $ApplianceLoginSessionsUri

            $_Params.Body = $_authinfo

            if ($PSBoundParameters['LoginAcknowledge'])
            {
    
                $_Params.Body | Add-Member -NotePropertyName loginMsgAck -NotePropertyValue $True
    
            }

        }

        # Cert/SmartCard auth
        else
        {

            $_CertificateBase64Object = $Certificate

            $_Params.Uri  = $ApplianceLoginSessionsSmartCardAuthUri
            $_Params.Body = $_CertificateBase64Object

            if ($PSBoundParameters['LoginAcknowledge'])
            {
    
                [void] $_Params.Add('AddHeader', @{'X-LoginMsgAck' = $True})
    
            }

        }

        Try
        {

            if ($_LoginDetails.loginMessage.message)
            {

                Write-Host ("{0}`n" -f $_LoginDetails.loginMessage.message)

            }            
            
            # Send the auth request
            $resp = Send-HPOVRequest @_Params

        }

        catch [HPOneview.ResourceNotFoundException]
        {

            [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)
            
            if ($PSCmdlet.ParameterSetName -eq 'Certificate')
            {

                $ExceptionMessage = "The appliance is not configured for 2-Factor authentication. Please provide a valid username and password in order to authenticate to the appliance."
                $ErrorRecord = New-ErrorRecord HPOneview.ResourceNotFoundException TwoFactorAuthenticationNotEnabled PermissionDenied 'Certificate' -Message $ExceptionMessage

            }

            else
            {

                $ExceptionMessage = "The provided '{0}' authentication directory is not configured on the appliance '{1}'." -f $AuthLoginDomain, $Hostname
                $ErrorRecord = New-ErrorRecord HPOneview.ResourceNotFoundException AuthenticationDirectoryNotFound ObjectNotFound 'AuthLoginDomain' -Message $ExceptionMessage

            }

            
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        catch [HPOneView.Appliance.AuthSessionException] 
        {

            "[{0}] Authentication Exception Caught." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_ErrorId = $_.FullyQualifiedErrorId.Split(',')[0]

            $_ErrorRecord = $_

            switch ($_ErrorId)
            {

                'LoginMessageAcknowledgementRequired'
                {

                    "[{0}] Login Message Acknowledgement Required" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get LoginMessage from appliance.
                    Try
                    {

                        $caption = "Please Confirm";
                        $message = "Do you acknowledge the login message?";
                        $yes     = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Yes, I accept the login message.";
                        $no      = New-Object System.Management.Automation.Host.ChoiceDescription "&No","No, I do not.";
                        $choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no);
                        $answer  = $host.ui.PromptForChoice($caption,$message,$choices,1) 

                        switch ($answer)
                        {

                            #YES
                            0 
                            {

                                "[{0}] Submitting auth request again, with login message acknowledgement." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                if ($PSCMdlet.ParameterSetName -eq 'Certificate')
                                {

                                    $_Params.AddHeader.Add('X-LoginMsgAck', $True)

                                }

                                else
                                {

                                    $_Params.Body | Add-Member -NotePropertyName loginMsgAck -NotePropertyValue $True

                                }

                                Try
                                {

                                    $resp = Send-HPOVRequest @_Params

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                            }

                            # NO
                            1
                            {

                                "[{0}] User selected 'No'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                'You are not authenticated to {0}, as you chose not to accept the Login Message acknowledgement.' -f $Hostname | Write-Warning 

                                # Remove Connection from global tracker
                                [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

                                Return

                            }

                        }   

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                'InvalidUsernameOrPassword'
                {

                    # Remove Connection from global tracker
                    [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

                    $PSCmdlet.ThrowTerminatingError($_ErrorRecord)

                }

                default
                {

                    # Remove Connection from global tracker
                    [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

                    #$ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException $_ErrorId InvalidResult 'Connect-HPOVMgmt' -Message $_.Exception.Message
                    $PSCmdlet.ThrowTerminatingError($_ErrorRecord)

                }

            }           

        }

        catch [HPOneview.Appliance.PasswordChangeRequired] 
        {

            "[{0}] Password needs to be changed. Use Set-HPOVInitialPassword if this is first time setup, or Set-HPOVUserPassword to update your own accounts password." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

            # Throw terminating error
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.PasswordChangeRequired PasswordExpired PermissionDenied 'Username' -Message "The password has expired and needs to be updated. Use Set-HPOVInitialPassword if this is first time setup, or Set-HPOVUserPassword to update your own accounts password."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   
        
        }
            
        catch [Net.WebException] 
        {

            "[{0}] Response: $($resp)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

            $ErrorRecord = New-ErrorRecord System.Net.WebException ApplianceNotResponding OperationStopped $Hostname -Message "The appliance at $Hostname is not responding on the network. Check for firewalls or ACL's prohibiting access to the appliance."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Something bad happened, should not leave connection in this state
        catch
        {

            [void] $ConnectedSessions.RemoveConnection($ApplianceConnection)

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }    

    End 
    {

        "[{0}] Authentication Response Received. Processing final connection object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # If a sessionID is returned, then the user has authenticated
        if ($resp.sessionId) 
        {

            $_RedactedResp = $resp.PSObject.Copy()

            $_RedactedResp.SessionId = '[*****REDACTED******]'

            $_Index = ${Global:ConnectedSessions}.IndexOf((${Global:ConnectedSessions} | Where-Object Name -EQ $Hostname))

            ${Global:ConnectedSessions}[$_Index].SetSessionID($resp.sessionId)
            
            "[{0}] Session received: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $($_RedactedResp | Out-String) | Write-Verbose

            if ($PSCmdlet.ParameterSetName -eq 'Certificate')
            {

                $_AuthType = 'Certificate'
                $_UserName = $resp.userName
                $_AuthLoginDomain = $resp.authLoginDomain

            }

            else
            {

                $_AuthType = 'Credentials'
                $_Username = $Username
                $_AuthLoginDomain = $AuthLoginDomain

            }

            # Get list of supported Roles from the appliance
            "[{0}] Getting list of supported roles from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_ApplianceSecurityRoles = $null

            try 
            { 
                
                $_ApplianceSecurityRoles = (Send-HPOVRequest $ApplianceRolesUri -Hostname $Hostname).members.roleName
            
            }

            catch [HPOneview.Appliance.AuthPrivilegeException] 
            { 
                
                "[{0}] User is not authorizaed to get list of security groups." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Get appliance platform type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Get Appliance Type to track what Cmdlet features are available
            # try
            # {
                
            # $ApplianceType = (Send-HPOVRequest $ApplianceVersionUri -Hostname $Hostname).platformType
            
            # }

            # catch
            # {
                
            # $PSCmdlet.ThrowTerminatingError($_)
            
            # }

            $_applianceversioninfo = NewObject -ApplianceVersion
            
            Try
            {

                $applVersionInfo = Send-HPOVRequest -Uri $ApplianceVersionUri -Hostname $Hostname

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            Try
            {

                $_applianceversioninfo = New-Object HPOneView.Appliance.NodeInfo ($applVersionInfo.softwareVersion, (Get-HPOVXApiVersion -ApplianceConnection $Hostname).currentVersion, $applVersionInfo.modelNumber)
                
                $PSLibraryVersion | Add-Member -NotePropertyName $Hostname -NotePropertyValue $_applianceversioninfo -Force

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Get users available Scopes and Permissions." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_UserDefaultSession = Send-HPOVRequest -Uri $UserLoginSessionUri -Hostname $Hostname -AddHeader @{'Session-ID' = $resp.sessionId}

                $_UserDefaultSessionPermissions = [System.Collections.ArrayList]::new()

                ForEach ($_Permission in $_UserDefaultSession.permissions)
                {

                    "[{0}] Adding {1} into permissions collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Permission.roleName | Write-Verbose

                    $_Scope = $null

                    if (-not [String]::IsNullOrWhiteSpace($_Permission.scopeUri))
                    {

                        $_Scope = Send-HPOVRequest -Uri $_Permission.scopeUri -Hostname $Hostname

                    }                

                    $_NewPermission = New-Object HPOneView.Appliance.ConnectionPermission ($_Permission.roleName, 
                                                                                           $_Scope.Name, 
                                                                                           $_Permission.scopeUri, 
                                                                                           $_Permission.active)

                    [void]$_UserDefaultSessionPermissions.Add($_NewPermission)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Recreate the full appliance connection
            $_NewConnection = New-Object HPOneView.Appliance.Connection($ConnectedSessions[$_Index].ConnectionID,
                                                                        $ConnectedSessions[$_Index].Name,
                                                                        $_Username,
                                                                        $resp.sessionId,
                                                                        $_AuthLoginDomain,
                                                                        $_AuthType,
                                                                        $AppliancePlatformType[$applVersionInfo.platformType],
                                                                        $ConnectedSessions[$_Index].Default,
                                                                        [Array]$_ApplianceSecurityRoles,
                                                                        [Array]$_UserDefaultSessionPermissions)
            
            ${Global:ConnectedSessions}[$_Index] = $_NewConnection

            # $Validator.AddTrustedHost($_NewConnection.Name)
            [HPOneView.PKI.SslValidation]::AddTrustedHost($_NewConnection.Name)

            Return $_NewConnection

        }

        else 
        { 
                              
            Return $resp 

        }

    }

}

function Push-HPOVAppliancePermission
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Array]$SetActivePermissions,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        # First, compare the objects to see if permissions will be different.
        "[{0}] Comparing permissions." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $_PermissionsDiff = Compare-Object -ReferenceObject $ApplianceConnection.ActivePermissions -DifferenceObject $SetActivePermissions -Property RoleName, ScopeName -IncludeEqual

        if ($_PermissionsDiff | Where-Object SideIndicator -ne '==')
        {

            "[{0}] Diff permissions: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_PermissionsDiff | Where-Object SideIndicator -ne '==' | Out-String) | Write-Verbose    

            $_UpdateToActivePermissions = NewObject -UpdateToActivePermissions

            $_UpdateToActivePermissions.sessionID = $ApplianceConnection.SessionID

            ForEach ($_Permission in $SetActivePermissions)
            {

                $_PermissionToActivate = NewObject -DirectoryGroupPermissions
                $_PermissionToActivate.roleName = $_Permission.RoleName

                if (-not [String]::IsNullOrWhiteSpace($_Permission.ScopeUri))
                {

                    $_PermissionToActivate.scopeUri = $_Permission.ScopeUri

                }
                
                [void]$_UpdateToActivePermissions.permissionsToActivate.Add($_PermissionToActivate)

            }

            # Take the URI of the scopeUris and do a POST $UpdateApplianceSessionAuthUri to get new SessionID
            Try
            {

                $_UpdatedSessionID = Send-HPOVRequest -Uri $UpdateApplianceSessionAuthUri -Method POST -Body $_UpdateToActivePermissions -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Update the appliance connection object
            "[{0}] Updating SessionID of the appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            ($ConnectedSessions | Where-Object Name -match $ApplianceConnection.Name).SetSessionID($_UpdatedSessionID.sessionID)

            # After the new sessionID has successfully been created, look at what existing permissions there are. Set the ones that do not
            # match the $SetActivePermissions to .UpdateState($false)

            "[{0}] Updating ActivePermission(s) that were changed to 'false'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($_PermissionToUpdate in ($_PermissionsDiff | Where-Object SideIndicator -eq '<='))
            {

                ($ApplianceConnection.ActivePermissions | Where-Object { $_.RoleName -eq $_PermissionToUpdate.RoleName -and $_.ScopeName -eq $_PermissionToUpdate.ScopeName}).UpdateState($false)

            }

            "[{0}] Updating ActivePermission(s) that should be active to 'true'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($_PermissionToUpdate in ($_PermissionsDiff | Where-Object SideIndicator -eq '=='))
            {

                ($ApplianceConnection.ActivePermissions | Where-Object { $_.RoleName -eq $_PermissionToUpdate.RoleName -and $_.ScopeName -eq $_PermissionToUpdate.ScopeName}).UpdateState($true)

            }

            "[{0}] Updated permissions: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($ApplianceConnection.ActivePermissions | Out-String) | Write-Verbose

            $ApplianceConnection.ActivePermissions

        }

        else
        {

            "[{0}] No permissions to update." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Pop-HPOVAppliancePermission
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        $_UpdateToActivePermissions = NewObject -UpdateToActivePermissions

        $_UpdateToActivePermissions.sessionID = $ApplianceConnection.SessionID

        ForEach ($_Permission in $ApplianceConnection.ActivePermissions)
        {

            $_PermissionToActivate = NewObject -DirectoryGroupPermissions
            $_PermissionToActivate.roleName = $_Permission.RoleName

            if (-not [String]::IsNullOrWhiteSpace($_Permission.ScopeUri))
            {

                $_PermissionToActivate.scopeUri = $_Permission.ScopeUri

            }

            [void]$_UpdateToActivePermissions.permissionsToActivate.Add($_PermissionToActivate)

        }

        # Take the URI of the scopeUris and do a POST $UpdateApplianceSessionAuthUri to get new SessionID
        Try
        {

            $_UpdatedSessionID = Send-HPOVRequest -Uri $UpdateApplianceSessionAuthUri -Method POST -Body $_UpdateToActivePermissions -ApplianceConnection $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Update the appliance connection object
        "[{0}] Updating SessionID of the appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        ($ConnectedSessions | Where-Object Name -match $ApplianceConnection.Name).SetSessionID($_UpdatedSessionID.sessionID)

        # After the new sessionID has successfully been created, look at what existing permissions there are. Set the ones that do not
        # match the $SetActivePermissions to .UpdateState($false)

        "[{0}] Updating ActivePermission(s) that were changed to 'false'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        ForEach ($_PermissionToUpdate in $ApplianceConnection.ActivePermissions)
        {

            $_PermissionToUpdate.UpdateState($true)

        }

        $ApplianceConnection.ActivePermissions

    }

}

function Disconnect-HPOVMgmt 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param
    (
    
        [Parameter (Mandatory = $false, ValueFromPipeline, Position = 0)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance', 'ApplianceSession', 'Hostname')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        if (-not ($ApplianceConnection))
        { 
        
            $ExceptionMessage = "No valid logon session available. Please use Connect-HPOVMgmt to connecto to an appliance, and then use Disconnect-HPOVmgmt to terminate your session."
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoAuthSession ResourceUnavailable 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)
            
        }

        $_ConnectionsToProcess = [System.Collections.ArrayList]::new()

    }

    Process 
    {    

        ForEach ($_ApplianceConnection in $ApplianceConnection)
        {

            # Check first if the Hostname value is a ConnectionID Integer
            [Int]$_tmpValue = 0

            if ([Int]::TryParse($_ApplianceConnection, [ref]$_tmpValue))
            {

                "[{0}] Hostname is ConnectionID {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_tmpValue | Write-Verbose

                [void]$_ConnectionsToProcess.Add((${Global:ConnectedSessions} | Where-Object ConnectionID -eq $_tmpValue))

                "[{0}] Found: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (${Global:ConnectedSessions} | Where-Object ConnectionID -eq $_tmpValue) | Write-Verbose

            }

            elseif ($_ApplianceConnection -is [String])
            {

                "[{0}] Hostname provide, looking in global connection tracker for connection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [void]$_ConnectionsToProcess.Add((${Global:ConnectedSessions} | Where-Object Name -eq $_ApplianceConnection))

                "[{0}] Found: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (${Global:ConnectedSessions} | Where-Object Name -eq $_ApplianceConnection) | Write-Verbose

            }

            elseif ($Null -eq $_ApplianceConnection.SessionID)
            {

                '[{0}] User Session not found in $Global:ConnectedSessions' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = "User session for '{0}' not found in library connection tracker (`$Global:ConnectedSessions). Did you accidentially remove it, or have you not created a session to an appliance?" -f $_ApplianceConnection.ToString()
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException UnableToLogoff ObjectNotFound 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }
        
            else
            {

                "[{0}] Adding Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ApplianceConnection | Write-Verbose

                [void]$_ConnectionsToProcess.Add($_ApplianceConnection)

            }

        }
        
    }

    End
    {

        For ($c = $_ConnectionsToProcess.Count - 1; $c -ge 0; $c--)
        {

            "[{0}] Processing Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ConnectionsToProcess[$c].Name | Write-Verbose

            "[{0}] Attempting to logoff user '{1}' from '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ConnectionsToProcess[$c].Username, $_ConnectionsToProcess[$c] | Write-Verbose

            "[{0}] Sending Delete Session ID request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            try 
            {
            
                $Resp = Send-HPOVRequest -Uri $ApplianceLoginSessionsUri -Method DELETE -Body $_ConnectionsToProcess[$c].SessionId -Hostname $_ConnectionsToProcess[$c]

                "[{0}] Removing connection from global connection tracker" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ConnectedSessions.RemoveConnection($_ConnectionsToProcess[$c])
                
            }
            
            catch
            {
            
                "[{0}] Unable to complete logoff. Displaying error" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $PSCmdlet.ThrowTerminatingError($_)
            
            }

        }


        if ($ConnectedSessions.Count -eq 1 -and (-not($ConnectedSessions | Where-Object Default)) -and $null -ne $ConnectedSessions[0])
        {

            $ConnectedSessions[0].SetDefault($true)

        }
        
        Return $ConnectedSessions
    
    }

}

function Set-HPOVApplianceDefaultConnection
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance', 'Connection')]
        [Object]$ApplianceConnection

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Check to see if there is only a single connection in the global tracker
        If (${Global:ConnectedSessions}.Count -eq 1)
        {

            Write-Warning 'There is only a single Appliance Connection. This Cmdlet only supports multiple Appliance Connections.'

            if (-not($Global:ConnectedSessions[0].Default))
            {

                'Appliance Connection "{0}" was not found to be the default connection. Setting as default.' -f ${Global:ConnectedSessions}[0].Name | Write-Warning 

                $Global:ConnectedSessions[0].SetDefault($True)

            }
            
            Break

        }

        if ($ApplianceConnection -is [System.String])
        {

            "[{0}] Connection Name provided. Looking in Global connection tracker variable." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $ApplianceConnection = ${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceConnection

            }

            Catch [System.Management.Automation.ValidationMetadataException]
            {

                "[{0}] Connection was not found. Looking for matching name in Global connection tracker variable." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $ApplianceConnection = ${Global:ConnectedSessions} | Where-Object Name -Match $ApplianceConnection

                }
                
                Catch
                {

                    $_Message = "Unable to find an appliance connection with the provided ApplianceConnection Name, {0}. Please provide the Connection Object or validate the Name and try again." -f $ApplianceConnection
                    $ErrorRecord = New-ErrorRecord InvalidOperationException ApplianceConnectionNotFound ObjectNotFound 'ApplianceConnection' -Message $_Message
                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

    }

    Process
    {

        if ($ApplianceConnection -isnot [HPOneView.Appliance.Connection])
        {

            $ExceptionMessage = "An invalid connection argument value type was provided, {0}. Please provide either a [String] or [HPOneView.Appliance.Connection] object." -f $ApplianceConnection
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidConnectionParameterValue InvalidArgument 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Check for existing Default Connection
        if (${Global:ConnectedSessions} | Where-Object Default)
        {

            # Unset it
            (${Global:ConnectedSessions} | Where-Object Default).SetDefault($false)

        }

        "[{0}] Setting {1} as the new default Appliance Connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceConnection.Name | Write-Verbose

        (${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceConnection.Name).SetDefault($true)

    }

    End
    {

        Return ${Global:ConnectedSessions}

    }

}

function Test-HPOVAuth
{

    [CmdletBinding ()]
    Param
    (
    
        [Parameter (Mandatory = $false, ValueFromPipeline)]
        [AllowEmptyString()]
        [Object]$Appliance
    
    )

    Begin 
    {

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Caller: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSBoundParameters['Appliance'])
        {

            "[{0}] Verify Auth for {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Appliance | Write-Verbose

        }

        else
        {

            "[{0}] -Appliance value via pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $PipelineInput = $True

        }

        $_ApplianceConnections = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ([String]::IsNullOrWhiteSpace($Appliance))
        {
        
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($_Appliance)" -Message 'No default active HPOV connection session found (check ${Global:ConnectedSessions} global variable.) Using this cmdlet requires either a default connection or the -ApplianceConnection parameter. Please use Connect-HPOVMgmt, if required, to establish a connection, or set a default connection and then try your command again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
        }

        if ($PipelineInput)
        {
    
            "[{0}] Verify Auth for {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Appliance.Name | Write-Verbose

        }
        
        if ($Appliance -is [System.Collections.IEnumerable])
        {

            ForEach ($_Appliance in $Appliance)
            {

                Switch ($_Appliance.GetType().FullName)
                {

                    'HPOneView.Appliance.Connection'
                    {

                        "[{0}] Received HPOneView.Appliance.Connection Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Appliance | Out-String) | Write-Verbose

                        If (-not(${Global:ConnectedSessions} | Where-Object name -eq $_Appliance.Name))
                        {

                            $ExceptionMessage = "No Appliance connection session found for '{0}' within `$Global:ConnectedSessions global variable. This CMDLET requires at least one active connection to an appliance. Please use Connect-HPOVMgmt to establish a connection, then try your command again." -f $_Appliance.Name
                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($_Appliance.Name)" -Message $ExceptionMessage

                        }

                        if ($_Appliance.SessionID -eq 'TemporaryConnection')
                        {

                            $ExceptionMessage = "The ApplianceConnection provided is a Temporary Connection, which is an invlaid state your PowerShell environment has become. Plesae restart your session and try your calls again."
                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionState InvalidOperation "$($Caller):$($_Appliance.Name)" -Message $ExceptionMessage

                        }

                        $_Appliance = $Appliance

                    }

                    'System.String'
                    {

                        if (-not(${Global:ConnectedSessions} | Where-Object name -eq $_Appliance))
                        {

                            $ExceptionMessage = "No connection session found for '{0}' within `$Global:ConnectedSessions global variable. This CMDLET requires at least one active connection to an appliance. Please use Connect-HPOVMgmt to establish a connection, then try your command again." -f $_Appliance
                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($_Appliance)" -Message $ExceptionMessage

                        }

                        elseif (${Global:ConnectedSessions} | Where-Object name -eq $_Appliance)
                        {
                    
                            $_Appliance = ${Global:ConnectedSessions} | Where-Object name -eq $_Appliance

                        }

                    }

                    {'System.Management.Automation.PSCustomObject', 'HPOneView.Library.ApplianceConnection' -contains $_}
                    {

                        "[{0}] Received PSCustomObject: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Appliance | Out-String) | Write-Verbose

                        If (-not(${Global:ConnectedSessions} | Where-Object name -eq $_Appliance.Name))
                        {

                            $ExceptionMessage = "No Appliance connection session found for '{0}' within `$Global:ConnectedSessions global variable. This CMDLET requires at least one active connection to an appliance. Please use Connect-HPOVMgmt to establish a connection, then try your command again." -f $_Appliance.Name
                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($_Appliance.Name)" -Message $ExceptionMessage

                        }

                        $_Appliance = ${Global:ConnectedSessions} | Where-Object name -eq $_Appliance.Name

                    }

                    default
                    {

                        "[{0}] Unsupported ApplianceConnection object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Appliance.GetType().FullName | Write-Verbose

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NotaValidApplianceConnection AuthenticationError "$($Caller)" -Message "The provided appliance object is not valid, as it is neither an [HPOneView.Appliance.Connection] object, [String] value representing a potentially valid Appliance Connection, or a [PSCustomObject] property of a resource object obtained from an appliance. Please correct the ApplianceConnection Parameter value, and then try your command again."

                    }

                }

                If ($ErrorRecord)
                { 

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Else
                {

                    [void]$_ApplianceConnections.Add($_Appliance)

                }

            }

        }

        else
        {

            "[{0}] `$Appliance is [{1}]"  -f $MyInvocation.InvocationName.ToString().ToUpper(), $Appliance.GetType().FullName | Write-Verbose

            Switch ($Appliance.GetType().FullName)
            {

                'HPOneView.Appliance.Connection'
                {

                    "[{0}] Received HPOneView.Appliance.Connection Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

                    If (-not(${Global:ConnectedSessions} | Where-Object name -eq $Appliance.Name))
                    {

                        $ExceptionMessage = "No Appliance connection session found for '{0}' within `$Global:ConnectedSessions global variable. This CMDLET requires at least one active connection to an appliance. Please use Connect-HPOVMgmt to establish a connection, then try your command again." -f $_Appliance.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($_Appliance.Name)" -Message $ExceptionMessage

                    }

                }

                'System.String'
                {

                    if (-not(${Global:ConnectedSessions} | Where-Object name -eq $_Appliance))
                    {

                        $ExceptionMessage = "No connection session found for '{0}' within `$Global:ConnectedSessions global variable. This CMDLET requires at least one active connection to an appliance. Please use Connect-HPOVMgmt to establish a connection, then try your command again." -f $_Appliance
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($_Appliance)" -Message $ExceptionMessage

                    }

                    elseif (${Global:ConnectedSessions} | Where-Object name -eq $_Appliance)
                    {
                    
                        $Appliance = ${Global:ConnectedSessions} | Where-Object name -eq $Appliance

                    }

                }

                {'System.Management.Automation.PSCustomObject', 'HPOneView.Library.ApplianceConnection' -contains $_}
                {

                    If (-not(${Global:ConnectedSessions} | Where-Object name -eq $Appliance.Name))
                    {

                        $ExceptionMessage = "No Appliance connection session found for '{0}' within `$Global:ConnectedSessions global variable. This CMDLET requires at least one active connection to an appliance. Please use Connect-HPOVMgmt to establish a connection, then try your command again." -f $Appliance.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "$($Caller):$($Appliance.Name)" -Message $ExceptionMessage

                    }

                    $Appliance = ${Global:ConnectedSessions} | Where-Object name -eq $Appliance.Name

                }

                default
                {

                    "[{0}] Unsupported ApplianceConnection object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NotaValidApplianceConnection AuthenticationError "$($Caller)" -Message "The provided appliance object is not valid, as it is neither an [HPOneView.Appliance.Connection] object, [String] value representing a potentially valid Appliance Connection, or a [PSCustomObject] property of a resource object obtained from an appliance. Please correct the ApplianceConnection Parameter value, and then try your command again."

                }

            }

            If ($ErrorRecord)
            { 

                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Else
            {

                [void]$_ApplianceConnections.Add($Appliance)

            }

        }        

    }

    End
    {
    
        Return $_ApplianceConnections

    }

}

function New-HPOVResource 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [String]$Uri,

        [Parameter (ValueFromPipeline, Mandatory)]
        [Alias('Resource')]
        [ValidateNotNullOrEmpty()]
        [object]$InputObject,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_NewResourceCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        Try
        {

            $_resp = Send-HPOVRequest -Uri $uri -Method POST -Body $InputObject -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        [void]$_NewResourceCollection.Add($_resp)

    }

    End
    {

        Return $_NewResourceCollection

    }

}

function Set-HPOVResource 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [Alias('Resource')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({$_.Uri})]
        [object]$InputObject,

        [Parameter (Mandatory = $false)]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        $InputObject = $InputObject.PSObject.Copy()

        if ($Force.IsPresent) 
        { 
            
            $InputObject.uri += "?force=true" 
        
        }

        Try
        {

            $_resp = Send-HPOVRequest -Uri $InputObject.uri -Method PUT -Body $InputObject -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_resp

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVResource 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml
     
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [Alias('Resource')]
        [ValidateNotNullorEmpty()]
        [Alias ("ro",'nameOruri','uri','name')]
        [object]$InputObject,

        [Parameter (Mandatory = $false)]
        [Switch]$force,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_RemoveResourceCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
         
        switch ($InputObject.GetType().Name) 
        { 

            "PSCustomObject"  
            { 
                
                "[{0}] Resource object passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Name: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] URI: $($InputObject.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Type: $($InputObject.type)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [void]$_RemoveResourceCollection.Add($InputObject)
                
            }
         
            "String"
            {
                
                # NameOrUri value is a URI
                if ($InputObject.StartsWith("/rest"))
                {

                    "[{0}] Resource URI passed '$($InputObject)', getting object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_resource = Send-HPOVRequest $InputObject -Hostname $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    [void]$_RemoveResourceCollection.Add($_resource)

                }

                # It's a string value
                else 
                {
                    
                    "[{0}] Resource name provided: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Querying appliance index for resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Use Index filtering to locate object
                    Try
                    {

                        $_resources = Send-HPOVRequest ($indexUri + "?filter=name='$InputObject'") -Hostname $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    "[{0}] Found $($_resources.count) resources." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if($_resources.members)
                    {

                        # Error should only be displayed if a Name was provided, and it wasn't globally unique on the appliance (i.e. Server Profile and Ethernet Network with the same name, which is completely valid.)
                        if($_resources.count -gt 1)
                        {
                            
                            "[{0}] Resources found: $($_resources.members | % { $_.name + " of type " + $_.category })" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $ErrorRecord = New-ErrorRecord InvalidOperationException ResourceNotUnique LimitsExceeded 'InputObject' -Message "'$InputObject' is not unique. Located $($_resources.count) resources with the same value."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        else 
                        { 
                        
                            [void]$_RemoveResourceCollection.Add($_resources.members)

                        }

                    }

                    else 
                    { 

                        $ErrorRecord = New-ErrorRecord InvalidOperationException ResourceNotFound ObjectNotFound 'InputObject' -Message "Resource '$InputObject' not found. Please check the resource value provided and try the call again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }   
              
        }

    }
    
    End
    {

        $n = 1

        ForEach ($_resource in $_RemoveResourceCollection)
        {

            "[{0}] Processing '$($_resource.name)', $n of $($_RemoveResourceCollection.Count)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ([Bool]$force) 
            { 
                
                $_resource.uri += "?force=true" 
            
            }

            $_Etag = "*"

            if ($null -ne $_resource.eTag)
            {

                $_Etag = $_resource.eTag

            }

            Try
            {
                                
                Send-HPOVRequest -Uri $_resource.uri -Method DELETE -AddHeader @{'If-Match' = $_Etag } -Hostname $_resource.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $n++

        }

    }

}

function ConvertFrom-HTML 
{

    [CmdletBinding ()]
    Param
    (

        [Parameter (ValueFromPipeline, Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.String] $html,

        [Switch]$NoClobber
        
    )

    Begin { }

    Process 
    {
        
        # remove line breaks, replace with spaces
        if (-not ($NoClobber.ispresent)) { $html = $html -replace "(`r|`n|`t)", " " }
        
        # remove invisible content
        @('head', 'style', 'script', 'object', 'embed', 'applet', 'noframes', 'noscript', 'noembed') | ForEach-Object {$html = $html -replace "<$_[^>]*?>.*?</$_>", "" }
        
        # Condense extra whitespace
        $html = $html -replace "( )+", " "
        
        # Add line breaks
        @('div','p','blockquote','h[1-9]') | ForEach-Object { $html = $html -replace "</?$_[^>]*?>.*?</$_>", ("`n" + '$0' )} 

        # Add line breaks for self-closing tags
        @('div','p','blockquote','h[1-9]','br') | ForEach-Object { $html = $html -replace "<$_[^>]*?/>", ('$0' + "`n")} 
        
        # Strip tags
        $html = $html -replace "<[^>]*?>", ""
         
        # replace common entities
        @(
            @("&amp;bull;", " * "),
            @("&amp;lsaquo;", "<"),
            @("&amp;rsaquo;", ">"),
            @("&amp;(rsquo|lsquo);", "'"),
            @("&amp;(quot|ldquo|rdquo);", '"'),
            @("&amp;trade;", "(tm)"),
            @("&amp;frasl;", "/"),
            @("&amp;(quot|#34|#034|#x22);", '"'),
            @('&amp;(amp|#38|#038|#x26);', "&amp;"),
            @("&amp;(lt|#60|#060|#x3c);", "<"),
            @("&amp;(gt|#62|#062|#x3e);", ">"),
            @('&amp;(copy|#169);', "(c)"),
            @("&amp;(reg|#174);", "(r)"),
            @("&amp;nbsp;", " "),
            @("&amp;(.{2,6});", ""),
            @("&nbsp;", " ")
        ) | ForEach-Object { $html = $html -replace $_[0], $_[1] }

    }

    End 
    {
    
        return $html

    }

}

function Start-HPOVLibraryTrace
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (
    
        [Parameter (Mandatory = $false)]
        [String]$Location = (Get-Location).path
    
    )

    Throw "This Cmdlet is now deprecated. Please use Get-HPOVCommandTrace instead."

}

function Stop-HPOVLibraryTrace
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    ()

    Throw "This Cmdlet is now deprecated. Please use Get-HPOVCommandTrace instead."

}

function Get-HPOVCommandTrace
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias('Command')]
        [ScriptBlock]$ScriptBlock = {},

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Location = (Get-Location).path

    )

    Begin 
    {

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Caller: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($Caller -eq 'Get-HPOVCommandTrace')
        {

            Throw "You cannot use the Cmdlet to trace itself. Please specify a different HPE OneView PowerShell Cmdlet."

        }

        $_TranscriptFile = $Location + '\' + (get-date -uformat %y%m%d%H%M) + '_HPOV_transcript.log'

        if ($host.name -match 'ISE' -and $PSVersionTable.PSVersion -lt '5.0')
        {

            Start-IseTranscript $_TranscriptFile | Out-Null

        }

        else
        {

            Try
            {
    
                '[{0}] Starting Transcript logging.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                '[{0}] Generating new trace file: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_TranscriptFile | Write-Verbose
                
                Start-Transcript $_TranscriptFile | Out-Null
    
            }
    
            catch
            {
    
                $PSCmdlet.ThrowTerminatingError($_)
    
            }

        }
        
        ($PSLibraryVersion | Out-String) | Write-Verbose -Verbose:$true

        # Enable .Net Class Library tracing
        [HPOneView.Config]::EnableVerbose = $true
        [HPOneView.Config]::EnableDebug = $true

    }

    Process
    {

        $sb = New-Object System.Text.StringBuilder
        [void]$sb.Append("`$VerbosePreference = 'Continue'`n")
        [void]$sb.Append($ScriptBlock.ToString())

        '[{0}] ScritpBlock to execute: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $sb.ToString() | Write-Verbose

        Invoke-Command -ScriptBlock ([Scriptblock]::Create($sb.ToString())) -ErrorVariable CapturedError | Out-Null

        if ($null -ne $CaptureError)
        {

            $CapturedError | Write-Host

        }

        ([String]::Join('',(1..80 | ForEach-Object { "-" }))) | Write-Verbose -Verbose:$true

    }

    End
    {

        [HPOneView.Config]::EnableVerbose = $false
        [HPOneView.Config]::EnableDebug = $false

        Stop-Transcript | Out-Null

        '[{0}] Stopped transcript logging.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        [System.IO.FileInfo]$_TranscriptFile

    }

}

Function Start-iseTranscript
{

    Param
    (

        [String]$logname = (Get-logNameFromDate -path "C:\fso" -postfix " $(hostname)" -Create)

    )

    $transcriptHeader = '**************************************
    Windows PowerShell ISE Transcript Start
    Start Time: {0}
    UserName: {1}
    UserDomain: {2}
    ComputerName: {3}
    Windows version: {4}
    **************************************
    Transcript started. Output file is {5}'
 -f [DateTime]::Now(), $env:username, $env:USERDNSDOMAIN, $env:COMPUTERNAME, (Get-CimObject win32_operatingsystem).version, $logname

    $transcriptHeader >> $logname

    $psISE.CurrentPowerShellTab.Output.Text >> $logname

    # Keep current Prompt
    if ($null -eq $__promptDef)
    {

        $__promptDef =  (Get-ChildItem Function:Prompt).Definition
        $promptDef = (Get-ChildItem Function:Prompt).Definition

    } 
    
    else
    {

        $promptDef = $__promptDef

    }

    $newPromptDef = '
    if ($global:_LastText -ne $psISE.CurrentPowerShellTab.Output.Text)
    {
 
        Compare-Object -ReferenceObject $global:_LastText.Split("`n") -DifferenceObject $psISE.CurrentPowerShellTab.Output.Text.Split("`n") | ? { $_.SideIndicator -eq "=>" } | % { $_.InputObject.TrimEnd() } | Out-File -FilePath ($Global:_DSTranscript) -Append
        $global:_LastText = $psISE.CurrentPowerShellTab.Output.Text
 
    }
    '
 + $promptDef

    New-Item -Path Function: -Name "Global:Prompt" -Value ([ScriptBlock]::Create($newPromptDef)) -Force | Out-Null
    
}

function Invoke-HPOVWebBrowser
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateSet ("Dashboard",
                      "Settings", 
                      "ServerProfiles", 
                      "ServerProfileTemplates", 
                      "ServerHardware", 
                      "Enclosures", 
                      "RackManagers", 
                      "LogicalEnclosures", 
                      "Networks", 
                      "LogicalInterconnects", 
                      "LogicaInterconnectGroups", 
                      "StorageSystems", 
                      "StoragePools", 
                      "StorageVolumes")]
        [String]$Resource = "Dashboard",

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceStatus = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_ResourceMap = @{
                Dashboard                = 'dashboard';
                Settings                 = 'settings/show/overview';
                ServerProfiles           = 'profiles';
                ServerProfileTemplates   = 'profile-templates';
                ServerHardware           = 'server-hardware';
                Enclosures               = 'enclosures';
                RackManagers             = 'rackmanagers';
                LogicalEnclosures        = 'logicalenclosures';
                Networks                 = 'network';
                LogicalInterconnects     = 'logicalswitch';
                LogicaInterconnectGroups = 'switchtemplate';
                StorageSystems           = 'storage-systems';
                StoragePools             = 'storage-pools';
                StorageVolumes           = 'storage-volumes'
            }

            Start-Process ("https://{0}/#/{1}?s_sid={2}" -f $_appliance.Name, $_ResourceMap.$Resource, $_appliance.SessionID)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Show-HPOVActiveUser
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose
            
            Try
            {

                $_ActiveUserSessions = Send-HPOVRequest -Uri $ActiveUserSessionsUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_usersession in $_ActiveUserSessions.members)
            {

                "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_usersession.username, $_ActiveUserSessions.count | Write-Verbose

                New-Object HPOneView.Appliance.ActiveUserSession ($_usersession.username, $_usersession.loginDomain, $_usersession.clientHost, $_usersession.timeCreated, [HPOneView.Library.ApplianceConnection]$_usersession.ApplianceConnection)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function ConvertTo-HPOVPowerShellScript
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [System.IO.FileInfo]$Export,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('NoClobber')]
        [ValidateNotNullorEmpty()]
        [Switch]$Append

    )
    
    Begin
    {

        $DoubleQuote    = '"'
        $CRLF           = "`r`n"
        $Delimiter      = "\"   # Delimiter for CSV profile file
        $SepHash        = ";"   # USe for multiple values fields
        $Sep            = ";"
        $hash           = '@'
        $SepChar        = '|'
        $CRLF           = "`r`n"
        $OpenDelim      = "{"
        $CloseDelim     = "}" 
        $OpenArray      = "("
        $CloseArray     = ")"
        $CR             = "`n"
        $Comma          = ','
        $Equal          = '='
        $Dot            = '.'
        $Underscore     = '_'
        $Space          = ' '

        $Syn12K         = 'SY12000' # Synergy enclosure type
        [Hashtable]$LogicalDiskCmdletTypeEnum = @{

            SasHdd  = 'SAS';
            SataHdd = 'SATA';
            Sas     = 'SASSSD';
            SasSsd  = 'SASSSD';
            SataSsd = 'SATASSD';
            NVMeSsd = 'NVMeSas';
            NVMeHdd = 'NVMeSata'

        }

    }

    Process
    {

        $ExportToFile = $PSBoundParameters['Export']

        $ApplianceConnection = $InputObject.ApplianceConnection

        function Insert-BlankLine
        {

            ""

        }

        Function Get-NamefromUri([String]$uri)
        {

            $name = $null

            if (-not [String]::IsNullOrEmpty($Uri)) 
            { 
                
                Try
                {
                
                    $resource = Send-HPOVRequest -Uri $Uri -ApplianceConnection $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }
            
            }

            switch ($resource.category)
            {

                $ResourceCategoryEnum.IPv4Subnet
                {

                    $name = $resource.networkId

                }

                'storage-systems'
                {

                    $name = $resource.members.displayName

                }

                default
                {

                    $name = $resource.name

                }

            }

            return $name

        }

        Function Generate-CustomVarCode ([String]$Prefix, [String]$Suffix, [String]$Value)
        {

            if (-not $Prefix.StartsWith("$") -and -not $Prefix.StartsWith("#"))
            {

                $Prefix = '${0}' -f $Prefix

            }

            $VarName = '{0}{1}' -f $Prefix, $Suffix

            Return '{0}{1}= {2}' -f $VarName, [String]::Join('', (1..(28 - $VarName.Length) | ForEach-Object { $Space })), $Value

        }

        Function rebuild-fwISO ($BaselineObj)
        {

            # ----------------------- Rescontruct FW ISO filename
            # When uploading the FW ISO file into OV, all the '.' chars are replaced with "_"
            # so if the ISO filename is: SPP_2018.06.20180709_for_HPE_Synergy_Z7550-96524.iso
            # OV will show $fw.ISOfilename ---> SPP_2018_06_20180709_for_HPE_Synergy_Z7550-96524.iso
            #
            # This helper function will try to re-build the original ISO filename

            $newstr = $null

            switch ($BaselineObj.GetType().Fullname)
            {

                'HPOneView.Appliance.Baseline'
                {

                    $arrList = [System.Collections.ArrayList]::new()

                    $StrArray = $BaselineObj.ResourceId.Split($Underscore)

                    ForEach ($string in $StrArray)
                    {

                        [void]$arrList.Add($string.Replace($dot, $Underscore))

                    }
                    
                    $newstr = "{0}.iso" -f [String]::Join($Underscore, $arrList.ToArray())                

                }

                'HPOneView.Appliance.BaselineHotfix'
                {

                    $newStr     = $BaselineObj.FwComponents.Filename

                }

                default
                {

                    $newstr = $null

                }

            }

            return $newStr
                
        }
        
        Function DisplayOutput ([System.Collections.ArrayList]$code)
        {

            if ($ExportToFile)
            {

                if (-not $Append)
                {

                    [System.IO.File]::WriteAllLines($Export, $code, [System.Text.Encoding]::UTF8)

                }

                else
                {

                    [System.IO.File]::AppendAllLines([String]$Export, [string[]]$code.ToArray(), [System.Text.Encoding]::UTF8)

                }

            }

            else
            {

                $code.ToArray()

                Insert-BlankLine

            }

        }

        Function Generate-fwBaseline-Script ($InputObject)
        {

            foreach ($fwBase in $InputObject)
            {

                $scriptCode =  [System.Collections.ArrayList]::new()

                # - OV strips the dot from the ISOfilename, so we have to re-construct it
                $filename   = rebuild-fwISO -BaselineObj $fwBase

                [void]$scriptCode.Add(('## ------ Upload baseline "{0}"' -f $filename))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'filename' -Value ('"{0}"' -f $filename)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'isofolder' -Value ('read-host "Provide the folder location for "{0}"' -f $filename)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'isofile' -Value 'Join-Path $isofolder $filename'))
                [void]$scriptCode.Add('Add-HPOVBaseline -file $isofile')
                
                DisplayOutput -Code $scriptCode

            }

        }

        Function Generate-proxy-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $proxy          = $InputObject
            $server         = $proxy.Server

            if ($server)
            {

                $protocol       = $proxy.protocol 
                $port           = $proxy.port 
                $username       = $proxy.username 
                $server         = $server 

                [void]$scriptCode.Add('## ------ Configure appliance proxy to "{0}"' -f $server)
                $serverParam    = ' -server $server'
                $portParam      = ' -port $port'
                $credParam      = $null
                $userParam      = $null
                $isHttps        = if ($protocol -eq 'Https') {$true} else {$false}
                $protocolParam  = ' -Https:$isHttps'


                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'server' -Value ('"{0}"' -f $server)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'port' -Value ('{0}' -f $port)))
            
                if (-not [String]::IsNullOrEmpty($username))
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'username' -Value ('"{0}"' -f $username)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'password' -Value ('Read-Host -prompt "Enter password for user {0} for proxy server" -AsSecureString' -f $username)))

                    $userParam = ' -Username {0} -Password $password' -f $username

                }

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'isHttps' -Value ('${0}' -f $isHttps.ToString())))
                [void]$scriptCode.Add(('Set-HPOVApplianceProxy -hostname $server{0}{1}{2}' -f $userParam, $portParam, $protocolParam))

                DisplayOutput -Code $scriptCode

            }   

        }
        
        Function Generate-scope-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $s = $InputObject

            $name       = $s.name
            $desc       = $s.description
            $members    = $s.members
        
            $descParam = $null
            $descCode  = $null

            [void]$scriptCode.Add('## ------ Create scope {0}' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))

            if ($desc)
            {

                $descParam  =  ' -description $description'
 
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'description' -Value ('"{0}"' -f $desc)))

            }

            if ($s.Members.Count -gt 0)
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'thisScope' -Value ('New-HPOVScope -Name $name {0}' -f $descParam)))

                [void]$scriptCode.Add(('{0}## ------ Create resources to be included in scope {1}' -f $CR, $name))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'resources' -Value '[System.Collections.ArrayList]::new()'))

                foreach ($m in $members)
                {

                    $scopeMemberCode = $scopeMemberType = $null

                    $m_type = $m.type

                    switch ($m_type) 
                    {

                        'EthernetNetwork'           
                        {

                            $scopeMemberCode = 'Get-HPOVNetwork -Name "{0}" -Type Ethernet' -f $m.name
                            
                        }

                        'FCoENetwork'               
                        {

                            $scopeMemberCode = 'Get-HPOVNetwork -Name "{0}" -Type FCoE' -f $m.name
                        
                        }

                        'FCNetwork'
                        {

                            $scopeMemberCode = 'Get-HPOVNetwork -Name "{0}" -Type FC' -f $m.name
                        
                        }

                        'LogicalInterconnectGroup'  
                        {

                            $scopeMemberCode = 'Get-HPOVLogicalInterconnectGroup -Name "{0}"' -f $m.name

                        }

                        'LogicalInterconnect'
                        {

                            $scopeMemberCode = 'Get-HPOVLogicalInterconnect -Name "{0}"' -f $m.name

                        }

                        'LogicalEnclosure'
                        {

                            $scopeMemberCode = 'Get-HPOVLogicalEnclosure -Name "{0}"' -f $m.name

                        }
                                                    
                        'ServerProfileTemplate'
                        {
                            
                            $scopeMemberCode = 'Get-HPOVServerProfileTemplate -Name "{0}"' -f $m.name
                        
                        }

                        'ServerHardware'
                        {

                            $scopeMemberCode = 'Get-HPOVServer -Name "{0}"' -f $m.name
                        
                        }

                        'StorageVolumeTemplate'
                        {

                            $scopeMemberCode = 'Get-HPOVStorageVolumeTemplate -Name "{0}"' -f $m.name
                                                    
                        }

                        'StorageVolume'
                        {

                            $scopeMemberCode = 'Get-HPOVStorageVolume -Name "{0}"' -f $m.name
                        
                        }

                        'StoragePool'
                        {

                            
                            $scopeMemberCode = 'Get-HPOVStoragePool -Name "{0}"' -f $m.name
                            
                        }

                        'FirmwareBundle'
                        {

                            $scopeMemberCode = 'Get-HPOVbaseline -Name "{0}"' -f $m.name
                                                    
                        }

                        default                     {}

                    }                     

                    [void]$scriptCode.Add('[void]$resources.Add({0})' -f $scopeMemberCode)

                }

                [void]$scriptCode.Add('Add-HPOVResourceToScope -Scope $thisScope -InputObject $resources')
            
            }

            else
            {
            
                [void]$scriptCode.Add('New-HPOVScope -Name $name {0}' -f $descParam)
            
            }

            DisplayOutput -Code $scriptCode

        }

        # Local OneView user accounts, with permissions and SBAC
        Function Generate-User-Script ($InputObject)
        {

            $scriptCode       = [System.Collections.ArrayList]::new()
            $scopePermissions = [System.Collections.ArrayList]::new()
            $permissionsCode  = [System.Collections.ArrayList]::new()

            $User = $InputObject

            $userName     = $User.userName
            $fullName     = $User.fullName
            $desc         = $User.description
            $permissions  = $User.permissions
            $emailAddress = $User.emailAddress
            $officePhone  = $User.officePhone
            $mobilePhone  = $User.mobilePhone
        
            $fullNameParam = $permissionsParam = $emailAddressParam = $officePhoneParam = $mobilePhoneParam = $descParam = $null
            $roleParam     = $scopeParam       = $null

            [void]$scriptCode.Add('# ------ Create user {0}' -f $userName)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'userName' -Value ('"{0}"' -f $userName)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'password' -Value ('Read-Host -Message "Provide the password for {0}"' -f $userName)))

            if ($userName -ne $fullName)
            {

                [void]$scriptCode.Add('$fullName = "{0}"' -f $fullName)
                $fullNameParam = ' -Fullname $fullname'

            }

            if (-not [String]::IsNullOrWhiteSpace($emailAddress))
            {

                [void]$scriptCode.Add('$emailAddress = "{0}"' -f $emailAddress)
                $emailAddressParam = ' -EmailAddress $emailAddress'

            }

            if (-not [String]::IsNullOrWhiteSpace($officePhone))
            {

                [void]$scriptCode.Add('$officePhone = "{0}"' -f $officePhone)
                $officePhoneParam = ' -OfficePhone $officePhone'

            }

            if (-not [String]::IsNullOrWhiteSpace($mobilePhone))
            {

                [void]$scriptCode.Add('$mobilePhone = "{0}"' -f $mobilePhone)
                $mobilePhoneParam = ' -MobilePhone $mobilePhone'

            }

            $n = 1

            ForEach ($permission in $permissions)
            {

                # Roles first, which have no scopeUri value
                $ScopePermission = [PSCustomObject]@{Role = $null; Scope = "All"}

                $ScopePermission.Role = $permission.roleName

                if (-not [String]::IsNullOrWhiteSpace($permission.scopeUri))
                {

                    $ScopeName = Get-NamefromUri $permission.scopeUri

                    $ScopePermission.Scope = '$Scope{0}' -f $n

                    $ScopeRoleVarCode = Generate-CustomVarCode -Prefix "Scope" -Suffix $n -Value ('Get-HPOVScope -Name "{0}"' -f $ScopeName)

                    [void]$scriptCode.Add('{0}' -f $ScopeRoleVarCode)

                    $n++
                
                }

                [void]$scopePermissions.Add($ScopePermission)

            }

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'permissions' -Value '@('))

            $c = 1

            ForEach ($perm in $scopePermissions)
            {

                $eol = ','

                if ($c -eq $n)
                {

                    $eol = $null

                }

               [void]$scriptCode.Add((' {0}Role = "{1}"; Scope = {2}{3}{4}' -f '@{', $perm.Role, $perm.Scope, '}', $eol))

               $c++

            }

            [void]$scriptCode.Add(')')

            $permissionsParam = ' -Roles $permissions'

            [void]$scriptCode.Add(('New-HPOVUser -Username $userName -Password $password{0}{1}{2}{3}' -f $fullNameParam, $descParam, $emailAddressParam, $officePhoneParam, $mobilePhoneParam, $permissionsParam))

            DisplayOutput -Code $scriptCode

        }

        # User and Directory Group permissions
        Function Generate-RBAC-Script ($InputObject)
        {

            $scriptCode       = [System.Collections.ArrayList]::new()
            $scopePermissions = [System.Collections.ArrayList]::new()

            $Group = $InputObject

            $groupName   = $Group.egroup
            $dirName     = $Group.loginDomain
            $permissions = $Group.permissions
        
            [void]$scriptCode.Add('# ------ Create authentication directory group {0}' -f $groupName)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'groupName' -Value ('"{0}"' -f $groupName)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dirName' -Value ('"{0}"' -f $dirName)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'credentials' -Value ('Get-Credential -Message "Provide {0} authentication directory username and password"' -f $dirName)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'directory' -Value ('Get-HPOVLdapDirectory -Name $dirName')))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'thisGroup' -Value ('Show-HPOVLdapGroups -Directory $directory -GroupName $groupName -Credential $credentials')))

            $n = 1

            ForEach ($permission in $permissions)
            {

                # Roles first, which have no scopeUri value
                $ScopePermission = [PSCustomObject]@{Role = $null; Scope = "All"}

                $ScopePermission.Role = $permission.roleName

                if (-not [String]::IsNullOrWhiteSpace($permission.scopeUri))
                {

                    $ScopeName = Get-NamefromUri $permission.scopeUri

                    $ScopePermission.Scope = '$Scope{0}' -f $n

                    $ScopeRoleVarCode = Generate-CustomVarCode -Prefix "Scope" -Suffix $n -Value ('Get-HPOVScope -Name "{0}"' -f $ScopeName)

                    [void]$scriptCode.Add(('{0}' -f $ScopeRoleVarCode))

                    $n++
                
                }

                [void]$scopePermissions.Add($ScopePermission)

            }

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'permissions' -Value '@('))

            $c = 1

            ForEach ($perm in $scopePermissions)
            {

                $eol = ','

                if ($c -eq $n)
                {

                    $eol = $null

                }

                [void]$scriptCode.Add((' {0}Role = "{1}"; Scope = {2}{3}{4}' -f '@{', $perm.Role, $perm.Scope, '}', $eol))

                $c++

            }

            [void]$scriptCode.Add(')')

            [void]$scriptCode.Add('New-HPOVLdapGroup -Directory $directory -Credential $credentials -Roles $permissions')

            DisplayOutput -Code $scriptCode

        }

        # Directory authentication, including default auth directory and local login policies
        Function Generate-DirectoryAuthentication-Script ($InputObject)
        {

            $scriptCode       = [System.Collections.ArrayList]::new()

            $Username           = $serviceAccountParam = $AuthProtocolParam = $null
            $UsrNameAttribParam = $LdapOUsParam        = $null

            $Directory     = $InputObject
            $Name          = $Directory.name
            $AuthProt      = $Directory.authProtocol
            $UsrNameAttrib = $Directory.userNamingAttribute
            $BaseDN        = $Directory.baseDN
            $OrgUnits      = $Directory.orgUnits
            $DirBindType   = $Directory.directoryBindingType
            $DirUsername   = $Directory.credential.userName
            $Servers       = $Directory.directoryServers

            [void]$scriptCode.Add(('# ------ Create authentication directory {0} ({1})' -f $Name, $BaseDN))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dirName' -Value ('"{0}"' -f $Name)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'baseDN' -Value ('"{0}"' -f $BaseDN)))

            if ($DirBindType -eq 'SERVICE_ACCOUNT')
            {

                $serviceAccountParam = ' -ServiceAccount'
                $Username = $DirUsername

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'credential' -Value ('Get-Credential -Message "Provide authentication credentials for {0} authentication directory." -Username "{0}"' -f $Username)))

            }

            else
            {
            
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'credential' -Value ('Get-Credential -Message "Provide authentication credentials for {0} authentication directory."' -f $Name)))
            
            }

            if ($AuthProt -ne 'AD')
            {

                $AuthProtocolParam  = ' -OpenLDAP'
                $LdapOUsParam       = ' -OrganizationalUnits $ldapOrgUnits'
                $UsrNameAttribParam = ' -UserNamingAttribute $usrNameAttrib'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ldapOrgUnits' -Value ('"{0}"' -f $OrgUnits)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'usrNameAttrib' -Value ('"{0}"' -f $UsrNameAttrib)))

            }

            else
            {
            
                $AuthProtocolParam = ' -AD'
            
            }

            $n = 1

            ForEach ($server in $Servers)
            {

                $ServerCode = $ServerNameCode = $ServerPortCode = $ServerCertCode = $null

                $ServerNameCode = ' -Hostname "{0}"' -f $server.directoryServerIpAddress
                $ServerPortCode = ' -SSLPort {0}' -f $server.directoryServerSSLPortNumber
                
                if ($server.directoryServerCertificateBase64Data)
                {

                    [void]$scriptCode.Add('# -------- If you wish to provide the certificate in Base64 format from a file, uncomment the following line')
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '#$certificate' -Value 'Get-ChildItem -Path "C:\Path\to\cert.cer"'))
                    [void]$scriptCode.Add('# -------- Comment out the following line to use the existing certificate value.')
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'certificate' -Value ('"{0}"' -f $BaseDN)))

                    $ServerCertCode = ' -Certificate $certificate -TrustLeafCertificate'

                }                

                $ServerCode = 'New-HPOVServer {0}{1}{2}' -f $ServerNameCode, $ServerPortCode, $ServerCertCode

                $ServerCode = Generate-CustomVarCode -Prefix "Server" -Suffix $n -Value $ServerCode

                [void]$scriptCode.Add(('{0}' -f $ServerCode))

                $n++

            }

            [void]$scriptCode.Add('$servers = @(')

            $c = 1

            ForEach ($server in $Servers)
            {

                $eol = ','

                if ($c -eq $n)
                {

                    $eol = $null

                }

                [void]$scriptCode.Add(' $Server{0}' -f $c)

                $c++

            }

            [void]$scriptCode.Add(')')

            [void]$scriptCode.Add(('New-HPOVLdapDirectory -Name $dirName{0}{1}{2} -BaseDN $baseDN -Servers $servers -Credential $credentials' -f $AuthProtocolParam, $LdapOUsParam, $UsrNameAttribParam))

            DisplayOutput -Code $scriptCode

        }

        # ///TODO: OVRS, data collection schedule, Contacts, Default data center, and additional data centers with contacts
        Function Generate-RemoteSupport-Script ($InputObject)
        {

            $scriptCode           = [System.Collections.ArrayList]::new()

            $RS                   = $InputObject 
            $companyName          = $RS.companyName
            $marketingOptIn       = $RS.marketingOptIn
            $autoEnableDevices    = $RS.autoEnableDevices
            $insightOnlineEnabled = $RS.InsightOnlineEnabled

        }

        Function Generate-snmp-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $snmp            = $InputObject
            $readCommunity   = $snmp.CommunityString 

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'readCommunity' -Value ('"{0}"' -f $readCommunity)))
            [void]$scriptCode.Add('Set-HPOVSnmpReadCommunity -Name $readCommunity')

            #Trap destinations
            Try
            {
            
                $trapDestinations = Get-HPOVApplianceTrapDestination -ApplianceConnection $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }            

            foreach ($t in $trapDestinations)
            {

                $communitystr       = $t.communitystring 
                $destinationAddress = $t.DestinationAddress
                $port               = $t.port
                $type               = $t.type
                                
                $destParam = $formatParam = $communityParam = $portParam = $snmpV3UserParam = $null
                $destCode = $formatCode = $communityCode = $portCode = $null
                
                if ($destinationAddress)
                {
                                        
                    $destParam      = ' -destination $destination'
                    $portParam      = ' -port $Port'
                    $formatParam    = ' -SnmpFormat $type'
                    
                    [void]$scriptCode.Add(("#-- `tGenerating {0} Trap destination object for {1}" -f $type, $destinationAddress))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'destination' -Value ('"{0}"' -f $destinationAddress)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'port' -Value ('{0}' -f $port)))

                    Switch ($t.GetType().Fullname)
                    {

                        'HPOneView.Appliance.SnmpV1TrapDestination'
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'communitystring' -Value ('"{0}"' -f $communitystr)))

                            $communityParam = ' -Community $communitystring'
                            $type           = "SNMPv1"

                        }

                        'HPOneView.Appliance.SnmpV3TrapDestination'
                        {

                            # This needs to be expanded upon to configure SNMPv3 user
                            Try
                            {
                            
                                $snmpv3User = Get-HPOVSnmpV3user -Name $t.SnmpV3User -ApplianceConnection $ApplianceConnection
                            
                            }
                            
                            Catch
                            {
                            
                                $PSCmdlet.ThrowTerminatingError($_)
                            
                            }

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpV3User' -Value ('Get-HPOVSnmpV3user -Name "{0}"' -f $t.SnmpV3User)))
                            $snmpV3UserParam = ' -SnmpV3User $snmpV3User'
                            $type            = "SNMPv3"

                        }                        

                    } 

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'type' -Value ('"{0}"' -f $type)))
                    [void]$scriptCode.Add(('New-HPOVSnmpTrapDestination {0}{1}{2}{3}{4}' -f $destParam, $portParam, $formatParam, $communityParam, $snmpV3UserParam))

                }

            }

            DisplayOutput -Code $scriptCode

        }

        Function Generate-snmpV3User-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $user     = $InputObject
            $userName = $user.userName

            $securityLevelParam = $snmpv3UserPrivProtocolParam = $snmpv3UserAuthProtocolParam = $null
            $authProtocolName = $privProtocolName = $null

            $securityLevelName = ($Snmpv3UserAuthLevelEnum.GetEnumerator() | Where-Object Value -eq $user.securityLevel).Name

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'userName' -Value ('"{0}"' -f $userName)))
            $userNameParam      = ' -Username $userName'

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'securityLevel' -Value ('"{0}"' -f $securityLevelName)))
            $securityLevelParam = ' -SecurityLevel $securityLevel'

            switch ($user.securityLevel)
            {

                $Snmpv3UserAuthLevelEnum["AuthOnly"]
                {

                    $authProtocolName = ($SnmpAuthProtocolEnum.GetEnumerator() | Where-Object Value -eq $user.authenticationProtocol).Name

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'authProtocol' -Value ('"{0}"' -f $authProtocolName)))

                    $snmpv3UserAuthProtocolParam = ' -AuthProtocol $authProtocol'

                    if ($authProtocolName -ne 'none')
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'AuthPassword' -Value ('Read-Host -prompt "Enter authentication password for SNMPv3 user {0}" -AsSecureString' -f $username)))
                        $snmpv3UserAuthProtocolParam += ' -AuthPassword $authPassword'

                    }

                }

                $Snmpv3UserAuthLevelEnum["AuthAndPriv"]
                {

                    $authProtocolName = ($SnmpAuthProtocolEnum.GetEnumerator() | Where-Object Value -eq $user.authenticationProtocol).Name

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'authProtocol' -Value ('"{0}"' -f $authProtocolName)))

                    $snmpv3UserAuthProtocolParam = ' -AuthProtocol $authProtocol'

                    if ($authProtocolName -ne 'none')
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'AuthPassword' -Value ('Read-Host -prompt "Enter authentication password for SNMPv3 user {0}" -AsSecureString' -f $username)))
                        $snmpv3UserAuthProtocolParam += ' -AuthPassword $authPassword'

                    }

                    $privProtocolName = ($ApplianceSnmpV3PrivProtocolEnum.GetEnumerator() | Where-Object Value -eq $user.privacyProtocol).Name

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'privProtocol' -Value ('"{0}"' -f $privProtocolName)))

                    $snmpv3UserPrivProtocolParam = ' -PrivProtocol $privProtocol'

                    if ($authProtoprivProtocolNamecolName -ne 'none')
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'PrivPassword' -Value ('Read-Host -prompt "Enter privacy password for SNMPv3 user {0}" -AsSecureString' -f $username)))
                        $snmpv3UserPrivProtocolParam += ' -PrivPassword $PrivPassword'

                    }

                }

            }

            [void]$scriptCode.Add(('New-HPOVSnmpV3User -ApplianceSnmpUser{0}{1}{2}{3}' -f $userNameParam, $securityLevelParam, $snmpv3UserAuthProtocolParam, $snmpv3UserPrivProtocolParam))
            
            DisplayOutput -Code $scriptCode

        }

        Function Generate-smtp-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()
        
            $smtp               = $InputObject

            $Email              = $Smtp.senderEmailAddress
            $Server             = $Smtp.smtpServer
            $Port               = $Smtp.smtpPort
            $ConnectionSecurity = ($SmtpConnectionSecurityEnum.GetEnumerator() | Where-Object Value -eq $Smtp.smtpProtocol).Name

            # Code and Parameters
            if (-not $smtp.alertEmailDisabled -and $smtp.smtpServer)
            {

                [void]$scriptCode.Add('# -------------- Attributes for SMTP alerting')       
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'AlertEmailDisabled' -Value '$False'))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'Email' -Value ('"{0}"' -f $Email)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'Server' -Value ('"{0}"' -f $Server)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'Port' -Value ('{0}' -f $Port)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ConnectionSecurity' -Value ('{0}' -f $ConnectionSecurity)))
                [void]$scriptCode.Add('# Omit the following line to if your SMTP server does not require a password.')
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'Password' -Value 'Read-Host "Please enter a password to connect to smtp Server " -AsSecureString'))
                [void]$scriptCode.Add('Set-HPOVSmtpConfig -SenderEmailAddress $Email -password $Password -Server $Server -Port $Port')
                [void]$scriptCode.Add("")

                if ($smtp.alertEmailFilters.Count -gt 0)
                {

                    ForEach ($filter in ($smtp.alertEmailFilters | Sort-Object filterName))
                    {

                        Insert-BlankLine

                        $ScopeMatchPreferenceParam = $smtpAlertNameParam = $smtpAlertEmailsParam = $null
                        
                        [void]$scriptCode.Add(('# -------------- Attributes for SMTP Filter "{0}"' -f $filter.filterName)) 
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $filter.filterName)) )
                        $smtpAlertNameParam = '-Name $name'

                        # Emails
                        $Emails = '"{0}"' -f [String]::Join('", "', $filter.emails)
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'emails' -Value ('{0}' -f $Emails)))
                        $smtpAlertEmailsParam = ' -Emails $emails'

                        # FilterQuery
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'filter' -Value ('"{0}"' -f $filter.filter)))
                        $filterParam = ' -Filter $filter'

                        # ScopeQuery
                        if ($null -ne $filter.scopeQuery)
                        {

                            if ($filter.scopeQuery -match ' AND ')
                            {

                                $ScopeMatchPreference = "AND"

                                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ScopeMatchPreference' -Value ('"{0}"' -f $ScopeMatchPreference)))
                                $ScopeMatchPreferenceParam = ' -ScopeMatchPreference $ScopeMatchPreference'

                            }

                            else
                            {
                            
                                $ScopeMatchPreference = "OR"
                            
                            }

                            $ScopeNames = [System.Collections.ArrayList]::new()

                            ForEach ($scope in $filter.scopeQuery.Split(" $ScopeMatchPreference ", [StringSplitOptions]::RemoveEmptyEntries))
                            {

                                $scopeName = $scope.Replace("scope:", $null)

                                [void]$ScopeNames.Add($scopeName)

                            }

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'scope' -Value ('{0}' -f [String]::Join(', ', $ScopeNames.ToArray()))))
                            $smtpAlertEmailsParam = ' -Scope $scope'

                        }

                        [void]$scriptCode.Add(('Add-HPOVSmtpAlertEmailFilter {0}{1}{2}' -f $smtpAlertNameParam, $smtpAlertEmailsParam, $filterParam, $smtpAlertEmailsParam))
                        [void]$scriptCode.Add("")

                    }

                }

            }
        
            DisplayOutput -Code $scriptCode

        }

        Function Generate-TimeLocale-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $timeLocale      = $InputObject
 
            $Locale          = $TimeLocale.Locale
            $ntpServers      = $TimeLocale.NtpServers
            $pollingInterval = $timeLocale.pollingInterval
            $syncWithHost    = $timeLocale.SyncWithHost

            $localeParm        = $ntpParam         = $ntpCode = $null
            $syncWithHostParam = $syncWithHostCode = $null
            $pollingParam      = $pollingCode      = $null

            [void]$scriptCode.Add('# -------------- Attributes for date and time')
            
            $locale            = $locale.Split($dot)[0]

            if ($locale -ne 'en_US')
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'locale' -Value ('"{0}"' -f $locale)))
                $localeParm = ' -Locale $locale'

            }

            # will need to return NTP configuration
            if (-not $syncWithHost)
            {

                if ($ntpServers)
                {

                    $ntpServers = [String]::Join('", "', $ntpServers)
                    $ntpParam = ' -NtpServers $ntpServers'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ntpServers' -Value ('"{0}"' -f $ntpServers)))

                }

                if ($pollingInterval)
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'pollingInterval' -Value ('{0}' -f $pollingInterval)))
                    $pollingParam = " -PollingInterval `$pollingInterval "

                }

            }

            else
            {
            
                $syncWithHostParam = ' -SyncWithHost'
            
            }

            [void]$scriptCode.Add(('Set-HPOVApplianceDateTime{0}{1}{2}{3}' -f $localeParm, $syncWithHostParam, $ntpParam, $pollingParam))

            DisplayOutput -Code $scriptCode

        }

        Function Generate-AddressPoolSubnet-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()
            
            $networkIdParam = $subnetMaskParam = $gatewayParam = $null

            $subnet = $InputObject

            $networkID      = $subnet.NetworkID
            
            if ($subnet.Category -eq $ResourceCategoryEnum.IPv4Subnet)
            {

                $subnetmask     = $subnet.subnetmask

                $subnetMaskParam = 'Subnetmask'

            }

            else
            {

                $subnetmask     = $subnet.prefixLength

                $subnetMaskParam = 'Prefixlength'

            }
            
            $gateway        = $subnet.gateway
            $domain         = $subnet.domain
            $dns            = $subnet.dnsservers
            $rangeUris      = $subnet.rangeUris

            [void]$scriptCode.Add('# -------------- Attributes for subnet "{0}"' -f $networkID)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'networkID' -Value ('"{0}"' -f $networkID)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $subnetMaskParam -Value ('"{0}"' -f $subnetmask)))

            $networkIdParam     = ' -NetworkID $networkID'
            $subnetMaskParam    = ' -{0} $subnetmask' -f $subnetMaskParam
            
            if (-not [String]::IsNullOrEmpty($gateway))
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'networkgatewayID' -Value ('"{0}"' -f $gateway)))

                $gatewayParam = ' -Gateway $gateway'

            }
            
            # Code and attribute parameters
            $dnsParam       = $dnsCode = $null

            if ($dns)
            {

                $dnsServers     = [String]::Join('", "', $dns)

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dnsServers' -Value ('"{0}"' -f $dnsServers)))
                $dnsParam       = ' -DnsServers $dnsServers'
            
            }

            $domainParam        = $domainCode = $null

            if ($domain)
            {

                $domainParam    =  ' -Domain $domain'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'domain' -Value ('"{0}"' -f $domain)))

            }
           
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'thisSubnet' -Value ('New-HPOVAddressPoolSubnet{0}{1}{2}{3}{4}' -f $networkIdParam, $subnetMaskParam, $gatewayParam, $dnsParam, $domainParam)))

            foreach ($rangeUri in $rangeUris)
            {

                $range          = Send-HPOVRequest -Uri $rangeUri
                $name           = $range.Name 
                $startAddress   = $range.startStopFragments.startAddress 
                $endAddress     = $range.startStopFragments.endAddress 

                [void]$scriptCode.Add('')
                [void]$scriptCode.Add('# --- Attributes for Address Pool range associated with subnet {0}' -f $networkID)
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'startAddress' -Value ('"{0}"' -f $startAddress)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'endAddress' -Value ('"{0}"' -f $endAddress)))
                [void]$scriptCode.Add('New-HPOVAddressPoolRange -InputObject $thisSubnet -Name $name -start $startAddress -end $endAddress')

            }

            DisplayOutput -Code $scriptCode

        }

        Function Generate-AddressPoolRange-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $range  = $InputObject

            $poolName       = $range.Name  
            $rangeType      = $range.rangeCategory 
            $startAddress   = $range.startAddress
            $endAddress     = $range.endAddress
            $cat            = $range.category

            $rangeTypeParam = $poolTypeParam = $startEndParam = $null

            $poolType       = $cat.Split('-')[-1] 

            [void]$scriptCode.Add('# -------------- Attributes for address pool range {0}' -f $poolType)

            # Custom, non-IPv4 range
            if ($poolType -notmatch 'IPv' -and $rangeType -eq 'Custom')
            {  

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'poolType' -Value ('"{0}"' -f $poolType)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'rangeType' -Value ('"{0}"' -f $rangeType)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'startAddress' -Value ('"{0}"' -f $startAddress)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'endAddress' -Value ('"{0}"' -f $endAddress)))
                
                $rangeTypeParam = ' -rangeType $rangeType'
                $poolTypeParam  = ' -poolType $poolType'
                $startEndParam  = ' -start $startAddress -end $endAddress'

            }

            # Auto generated, non-IPv4 range
            elseif ($poolType -notmatch 'IPv' -and $rangeType -eq 'Generated')
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'poolType' -Value ('"{0}"' -f $poolType)))
                $poolTypeParam  = ' -poolType $poolType'

            }

            # IPv4 address range
            else
            {
                
                Try
                {
                
                    $AddressPoolSubnetId = Get-NamefromUri $range.subnetUri
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'subnet' -Value ('Get-HPOVAddressPoolSubnet -NetworkID {0}' -f $AddressPoolSubnetId)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'startAddress' -Value ('"{0}"' -f $startAddress)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'endAddress' -Value ('"{0}"' -f $endAddress)))
                
                $startEndParam  = ' -InputObject $subnet -Start $startAddress -End $endAddress'
            
            }

            [void]$scriptCode.Add(('New-HPOVAddressPoolRange{0}{1}{2}' -f $poolTypeParam, $rangeTypeParam, $startEndParam))

            DisplayOutput -Code $scriptCode

        }

        Function Generate-EthernetNetwork-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $net = $InputObject

            # ----------------------- Construct Network information
            $name        = $net.name
            $type        = $net.type.Split("-")[0]   # Value is like ethernet-v30network

            $vLANType    = $net.ethernetNetworkType
            $vLANID      = $net.vLanId

            $pBandwidth  = [String]$net.DefaultTypicalBandwidth
            $mBandwidth  = [String]$net.DefaultMaximumBandwidth
            $smartlink   = if ($net.SmartLink) { $true } else { $false }
            $Private     = if ($net.PrivateNetwork) { $true } else { $false }
            $purpose     = $net.purpose

            [void]$scriptCode.Add('# -------------- Attributes for Ethernet network "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'type' -Value ('"{0}"' -f $type)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'vLANType' -Value ('"{0}"' -f $vLANType)))

            $vLANIDparam = $vLANIDcode = $null

            if ($vLANType -eq 'Tagged')
            { 

                if (($vLANID) -and ($vLANID -gt 0)) 
                {

                    $vLANIDparam = ' -VlanID $VLANID'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'vLANid' -Value ('{0}' -f $vLANID)))

                }

            }                

            $pBWparam = $pBWCode = $null
            $mBWparam = $mBWCode = $null

            if ($PBandwidth) 
            {

                $pBWparam = ' -TypicalBandwidth $pBandwidth'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'pBandwidth' -Value ('{0}' -f $pBandwidth)))

            }
    
            if ($MBandwidth) 
            {

                $mBWparam = ' -MaximumBandwidth $mBandwidth'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'mBandwidth' -Value ('{0}' -f $mBandwidth)))

            }

            $subnetURI     = $net.subnetURI
            $IPv6SubnetUri = $net.ipv6SubnetUri

            $subnetCode     = $null
            $subnetIDparam  = @()
            $IPv6subnetCode = $IPv6subnetIDparam = $null

            if ($subnetURI) 
            {

                Try
                {
                
                    $subnet = Send-HPOVRequest -Uri $subnetURI -Hostname $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

                $ThisSubnetID   = $subnet.NetworkID
                $subnetName     = $subnet.Name

                $subnetIDparam  += '$ThisIPv4Subnet'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'IPv4NetworkID' -Value ('"{0}"' -f $ThisSubnetID)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ThisIPv4Subnet' -Value ('Get-HPOVAddressPoolSubnet -NetworkID $IPv4NetworkID')))

            }
            
            if ($IPv6SubnetUri) 
            {

                Try
                {
                
                    $subnet = Send-HPOVRequest -Uri $IPv6SubnetUri -Hostname $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

                $ThisSubnetID   = $subnet.NetworkID
                $subnetName     = $subnet.Name

                $subnetIDparam  += '$ThisIPv6Subnet'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'IPv6NetworkID' -Value ('"{0}"' -f $ThisSubnetID)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ThisIPv6Subnet' -Value ('Get-HPOVAddressPoolSubnet -NetworkID $IPv6NetworkID')))

            }
            
            if ($subnetIDparam.Count -gt 0)
            {

                $subnetIDparam = ' -Subnet {0}' -f [String]::Join(', ', $subnetIDparam)

            }
            
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'PLAN' -Value ('${0}' -f $Private)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'smartLink' -Value ('${0}' -f $smartLink)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'purpose' -Value ('"{0}"' -f $purpose)))

            [void]$scriptCode.Add(('New-HPOVNetwork -Name $name -Type $Type -PrivateNetwork $PLAN -SmartLink $smartLink -VLANType $VLANType{0}{1}{2}{3} -purpose $purpose' -f $vLANIDparam, $pBWparam, $mBWparam, $subnetIDparam))

            DisplayOutput -Code $scriptCode
   
        }

        Function Generate-NetworkSet-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $ns = $InputObject

            $name               = $ns.name
            $description        = $ns.description
            $PBandwidth         = $ns.TypicalBandwidth 
            $Mbandwidth         = $ns.MaximumBandwidth 
            $untaggednetworkURI = $ns.nativeNetworkUri
            $networkURIs        = $ns.networkUris

            [void]$scriptCode.Add('# -------------- Attributes for Network Set "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
                
            $pBWparam = $pbWCode = $null
            $mBWparam = $mBWCode = $null

            if ($PBandwidth) 
            {

                $pBWparam = ' -TypicalBandwidth $pBandwidth'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'pBandwidth' -Value ('{0}' -f $pBandwidth)))

            }
            
            if ($MBandwidth) 
            {

                $mBWparam = ' -MaximumBandwidth $mBandwidth'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'mBandwidth' -Value ('{0}' -f $mBandwidth)))

            }
                
            $untaggedParam  = $untaggednetworkname  =  $untaggednetCode = $null

            if ($untaggednetworkURI) 
            {

                $untaggedParam          =  ' -UntaggedNetwork $untaggednetwork'
                $untaggednetworkname    = Get-NamefromUri -Uri $untaggednetworkURI
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'untaggednetworkname' -Value ('"{0}"' -f $untaggednetworkname)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'untaggednetwork' -Value 'Get-HPOVNetwork -Name $untaggednetworkname'))
                
            }
                
            $netParam = $netCode = $null

            if ($networkURIs) 
            {

                $netParam     = ' -Networks $networks'
                #Serialize Array
                $arr = @()

                foreach ($el in $networkURIs)
                { 

                    $name  = Get-NamefromUri -Uri $el
                    $arr += '"{0}"' -f $name
                        
                }   # Add quote to string

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'networks' -Value ('{0} | Get-HPOVNetwork' -f [String]::Join(', ', $arr))))

            }

            [void]$scriptCode.Add(('New-HPOVNetwork -Name $nsName{0}{1}{2}{3}' -f $pBWparam, $mBWparam, $netParam, $untaggedParam))

            DisplayOutput -Code $scriptCode

        }

        Function Generate-FCNetwork-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $net = $InputObject

            $name                    = $net.name
            $description             = $net.description
            $type                    = $net.type.Split("-")[0]   # Value is 'fcoe-networksV300
            $fabrictype              = $net.fabrictype
            $pBandwidth              = $net.defaultTypicalBandwidth
            $mBandwidth              = $net.defaultMaximumBandwidth
            $sanURI                  = $net.ManagedSANuri
            $linkStabilityTime       = if ($net.linkStabilityTime) { $net.linkStabilityTime} else {30}
            $autologinredistribution = if ($net.autologinredistribution) { $true } else { $false }

            [void]$scriptCode.Add('# -------------- Attributes for FibreChannel network "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'type' -Value ('"{0}"' -f $type)))

            # fcoe network
            $VLANID                  = $net.VLANID
            $fabricUri               = $net.fabricUri 

            $pBWparam = $pBWCode = $null
            $mBWparam = $mBWCode = $null

            if ($PBandwidth) 
            {

                $pBWparam = ' -typicalBandwidth $pBandwidth'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'pBandwidth' -Value ('{0}' -f $pBandwidth)))

            }
    
            if ($MBandwidth) 
            {

                $mBWparam = ' -maximumBandwidth $mBandwidth'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'mBandwidth' -Value ('{0}' -f $mBandwidth)))

            }

            $FCparam          = $FCcode = $null
            $vLANIDparam      = $vLANIDcode = $null
            $autologinParam   = $autologinCode = $null
            $linkParam        = $linkCode = $null

            if ($type -match 'fcoe') #FCOE network
            {                

                if (($vLANID) -and ($vLANID -gt 0)) 
                {

                    $vLANIDparam =   ' -vLanID $VLANID'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'vLANid' -Value ('{0}' -f $vLANID)))
                
                }
                        
            }

            else  # FC network
            {
                
                $FCparam          = ' -FabricType $fabricType'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'fabricType' -Value ('"{0}"' -f $fabricType)))
        
                if ($fabrictype -eq 'FabricAttach')
                {

                    if ($autologinredistribution)
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'autologinredistribution' -Value ('${0}' -f $autologinredistribution)))
                        $autologinParam     = ' -AutoLoginRedistribution $autologinredistribution'

                    }

                    if ($linkStabilityTime) 
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'LinkStabilityTime' -Value ('{0}' -f $LinkStabilityTime)))
                        $linkParam  = ' -LinkStabilityTime $LinkStabilityTime'

                    }

                    $FCparam              += $autologinParam + $linkParam
            
                }

            }
                

            $sanParam   = $sanCode = $null

            if ($sanURI)
            { 

                Try
                {
                
                    $ManagedSAN = Send-HPOVRequest -Uri $sanURI -Hostname $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }
                
                $SANname            = $ManagedSAN.Name 
                $SANmanagerName     = $ManagedSAN.devicemanagerName
        

                $SANparam   = ' -ManagedSAN $managedSAN'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'SANname' -Value ('"{0}"' -f $SANname)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'managedSAN' -Value ('Get-HPOVManagedSAN -Name $SANname')))

            }

            [void]$scriptCode.Add(('New-HPOVNetwork -Name $name -Type $Type{0}{1}{2}{3}{4}' -f $pBWparam, $mBWparam, $FCparam, $vLANIDparam, $SANparam))

            DisplayOutput -Code $scriptCode

        }

        Function Generate-SanManager-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $SM  = $InputObject

            if ($SM.isInternal)
            {

                # Need to change this to non-terminating error?
                Write-Host "Unable to generate PowerShell Cmdlet for Direct Attach SAN Managers."

            }

            else
            {
            
                $name = $SM.name

                $displayName = $sm.providerDisplayName
                    
                foreach ($CI in $SM.ConnectionInfo)
                {

                    Switch ($CI.Name)
                    {

                        # ------ For HPE and Cisco
                        'SnmpPort'
                        {

                            $Port = $CI.Value

                        }

                        'SnmpUsername'
                        {

                            $snmpUsername = $CI.Value

                        }

                        'SnmpAuthLevel'
                        { 

                            $v = $CI.Value

                            if ($v -notlike 'AUTH*')
                            {

                                $AuthLevel = 'None'

                            }

                            else 
                            {

                                if ($v -eq 'AUTHNOPRIV')
                                {
                                    
                                    $AuthLevel = 'AuthOnly'

                                }

                                else
                                {

                                    $AuthLevel = 'AuthAndPriv'

                                }

                            }

                        }  

                        'SnmpAuthProtocol'
                        {

                            $AuthProtocol = $CI.Value

                        }

                        'SnmpPrivProtocol'
                        {

                            $PrivProtocol = $CI.Value

                        }

                        #---- For Brocade
                        'Username'
                        {

                            $username = $CI.Value

                        }

                        'UseSSL'
                        {

                            $UseSSL = if ($CI.Value)
                            {

                                $true

                            }

                            else
                            {

                                $false

                            }   

                        }

                        'Port'
                        {

                            $Port = $CI.Value

                        }

                    }

                }

                $credParam = $credCode = $null
                $privProtocolParam = $privProtocolCode = $null

                [void]$scriptCode.Add('# -------------- Attributes for San Manager $name')
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'type' -Value ('"{0}"' -f $displayName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'port' -Value ('{0}' -f $port)))

                if ($displayName -eq 'Brocade Network Advisor')
                {

                    $credParam = ' -username $username -password password -useSSL:$useSSL'
                    
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'username' -Value ('"{0}"' -f $username)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'password' -Value ('Read-Host "Provide password for user "$username" to connect to SANManager" -asSecureString')))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'useSSL' -Value ('${0}' -f $useSSL)))

                }

                else    # Cisco or HPE
                {

                    $authProtocolParam = ' -SnmpAuthLevel $snmpAuthLevel -Snmpusername $snmpUsername -SnmpAuthPassword $snmpAuthPassword -SnmpAuthProtocol $snmpAuthProtocol'

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpUsername' -Value ('"{0}"' -f $snmpUsername)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpAuthLevel' -Value ('"{0}"' -f $authLevel)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpAuthProtocol' -Value ('"{0}"' -f $AuthProtocol)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpAuthPassword' -Value ('Read-Host "Provide authentication password for user $snmpUsername" -asSecureString')))

                    if ($authLevel -eq 'AuthAndPriv')
                    {

                        $privProtocolParam = ' -SnmpPrivPassword $snmpPrivPassword -snmpPrivProtocol $snmpPrivProtocol'

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpPrivProtocol' -Value ('"{0}"' -f $privProtocol)))
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpPrivPassword' -Value ('Read-hHst "Provide privacy password" -asSecureString')))

                    }

                    $credParam = $authProtocolParam + $privProtocolParam

                }

                [void]$scriptCode.Add('Add-HPOVSanManager -Hostname $name -Type $type -Port $port{0}' -f $credParam)

                DisplayOutput -Code $scriptCode
            
            }           

        }

        Function Generate-StorageSystem-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $StS = $InputObject

            $StoragePorts   = $PortGroupPorts     = @()
            $PortGroupParam = $StoragePortsParam  = $null

            $hostName            = $Sts.hostname
            $Username            = $Sts.Credentials.username
            $family              = $sts.family
            $DomainName          = if ($family -eq 'StoreServ' ) { $Sts.deviceSpecificAttributes.managedDomain } else {''}

            [void]$scriptCode.Add('# -------------- Attributes for StorageSystem "{0}"' -f $hostname)

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'hostname' -Value ('"{0}"' -f $hostname)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'family' -Value ('"{0}"' -f $family)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'cred' -Value ('Get-HPOVCredential -Message "Provide the password for {0}" -Username {0}' -f $Username)))

            $portList            = $Sts.Ports | Where-Object status -eq 'OK' | Sort-Object Name

            foreach ($MP in ($portList | Where-Object mode -eq 'Managed')) 
            {

                # 3PAR
                if ($family -eq 'StoreServ')
                { 
                    
                    $Thisname    = $MP.expectedSanName

                    if ($Thisname)
                    {

                        # Need to get the associated FC network to the expectedSanName value

                        Try
                        {
                        
                            $AssociatedFcNetwork = Send-HPOVRequest -Uri $MP.expectedSanUri

                            $AssociatedFcNetworkName = $AssociatedFcNetwork.associatedNetworks.name
                        
                        }
                        
                        Catch
                        {
                        
                            $PSCmdlet.ThrowTerminatingError($_)
                        
                        }

                        $StoragePorts += "'{0}' = '{1}'" -f $MP.Name, $AssociatedFcNetworkName # Build Port syntax '0:1:2'= 'VSAN10'

                    }

                    if ($null -ne $MP.groupName)
                    {

                        $PortGroupParam = ' -PortGroups $portGroups'

                        $PortGroupPorts += "'{0}' = '{1}'" -f $MP.Name, $MP.groupName # Build Port syntax '0:1:2'= 'Portgroup 1'

                    }
                
                }

                # VSA/StoreVirtual
                else 
                { 
                    
                    $Thisname    = $MP.ExpectedNetworkName  

                    if ($Thisname)
                    {

                        $StoragePorts = [PSCustomObject]@{PortName = $MP.Name; NetworkName = $Thisname} # Build Port syntax '192.168.1.1'= 'iSCSI Network'

                    }
                
                }

            }

            if ($DomainName)
            {

                $domainParam     = ' -Domain $domainName'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'domainName' -Value ('"{0}"' -f $domainName)))

            }

            if ($StoragePorts -and $family -eq 'StoreServ' -and $StoragePorts.Count -gt 0)
            {

                $storagePortsParam  = ' -Ports $storageSystemPorts'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'storageSystemPorts' -Value ('{0}{1}{2}' -f '@{', [String]::Join("; ", $StoragePorts), '}')))

                if ($PortGroupPorts.Count -gt 0)
                {

                    $PortGroupParam = ' -PortGroups $portGroupPorts'

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'portGroupPorts' -Value ('{0}{1}{2}' -f '@{', [String]::Join("; ", $PortGroupPorts), '}')))

                }
                
            }

            elseif ($StoragePorts -and $family -eq 'StoreVirtual')
            {

                $storagePortsParam  = ' -VIPS $vips'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ThisiSCSINetwork' -Value ('Get-HPOVNetwork -Type Ethernet -Name "{0}"' -f $StoragePorts.NetworkName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'vips' -Value ('{0}"{1}" = $ThisiSCSINetwork{2}' -f "@{", $StoragePorts.PortName, "}")))

            }

            [void]$scriptCode.Add(('Add-HPOVStorageSystem -Hostname $hostName -Credential $cred -Family $family{0}{1}{2}' -f $domainParam, $storagePortsParam, $PortGroupParam))
  
    
            DisplayOutput -Code $scriptCode

        }

        Function Generate-StoragePool-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $pool = $InputObject

            if ($pool.state -ne 'Managed')
            {

                Write-Host ("Unable to create a Cmdlet for an unmanaged storage pool, {0}" -f $pool.name)

            }

            else
            {
            
                $name           = $pool.name
                $description    = $pool.description

                # --- Storage System

                $stsName        = Get-NamefromUri -Uri $pool.StorageSystemUri 
        
                [void]$scriptCode.Add('# -------------- Attributes for Storage Pool "{0}"' -f $pool.name)
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$stsName' -Value ('"{0}"' -f $stsName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$storageSystem' -Value 'Get-HPOVStorageSystem -Name $stsName'))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$pool' -Value (' Get-HPOVStoragePool -Name "{0}" -StorageSystem $storageSystem' -f $pool.name)))
                [void]$scriptCode.Add('Set-HPOVStoragePool -Pool $pool -Managed $True')

                DisplayOutput -Code $scriptCode
            
            }

        }

        Function Generate-StorageVolumeTemplate-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $Template = $InputObject

            $descParam = $PoolParam = $CapacityParam = $StoragePoolParam = $SnapshotPoolParam = $ProvisionTypeParam = $CompressionParam = $ScopeParam = $null
            $DataProtectionLevelParam = $AdaptiveOptimizationParam = $null

            # Common SVT attributes
            $name                = $Template.Name
            $description         = $Template.Description
            $family              = $Template.family
            $stsUri              = $Template.compatibleStorageSystemsUri
 
            # Common SVT properties
            $p                   = $template.Properties
            $size                = $p.size.default / 1GB
            $sizeIsLocked        = $p.size.meta.locked
            $isShareable         = $p.isShareable.default
            $isShareableLocked   = $p.isShareable.meta.locked
            $PoolUri             = $p.storagePool.default
            $poolIsLocked        = $p.storagePool.meta.locked
            $ProvisioningType    = $p.provisioningType.default 
            $provisionTypeLocked = $p.provisioningType.meta.locked
            $stsName             = Get-NamefromUri -Uri $stsUri
            $poolName            = Get-NamefromUri -Uri $PoolUri

            # Common attributes to set
            [void]$scriptCode.Add(('#------ Attributes for storage volume template "{0}" (Family: {1})' -f $name, $family))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))

            if ($description)
            {

                $descParam      = ' -Description $description'
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'description' -Value ('"{0}"' -f $description)))

            }

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'poolName' -Value ('"{0}"' -f $poolName)))

            Switch ($family)
            {

                'StoreServ'
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'stsName' -Value ('"{0}"' -f $stsName)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'storagePool' -Value ('Get-HPOVStoragePool -Name $poolName -StorageSystem $stsName')))

                }

                'StoreVirtual'
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'storagePool' -Value ('Get-HPOVStoragePool -Name $poolName')))

                }                

            }           

            $PoolParam = ' -StoragePool $StoragePool'

            if ($poolIsLocked)
            {

                $PoolParam += ' -LockStoragePool' 

            }

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'capacity' -Value ('{0}' -f $size)))

            $CapacityParam = ' -Capacity $capacity'

            if ($sizeIsLocked)
            {
                
                $CapacityParam += ' -LockCapacity'

            }

            if ($isShareable)
            {

                $ProvisionTypeParam = ' -Shared'

                if ($isShareableLocked)
                {

                    $ProvisionTypeParam += ' -LockProvisionMode'

                }

            }            

            # family specific properties
            switch ($family)
            {

                'StoreServ'
                {

                    $SnapshotUri          = $p.snapshotPool.default 
                    $snpshotPoolIsLocked  = $p.snapshotPool.meta.locked
                    $isDeduplicated       = $p.isDeduplicated.default
                    $isDeduplicatedLocked = $p.isDeduplicated.meta.locked
                    $enableCompression    = $p.enableCompression.default
                    $isCompressionLocked  = $p.enableCompression.meta.locked

                    if ($SnapshotUri -ne $PoolUri)
                    {

                        $snapshotPoolName = Get-NamefromUri -Uri $snapshotUri

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snapShotPoolName' -Value ('"{0}"' -f $snapshotPoolName)))
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snapShotPool' -Value ('Get-HPOVStoragePool -Name $snapShotPoolName -StorageSystem $stsName')))

                        $SnapshotPoolParam = ' -SnapshotStoragePool $snapShotPool'

                        if ($snpshotPoolIsLocked)
                        {

                            $SnapshotPoolParam += ' -LockSnapshotStoragePool'

                        }

                    }

                    else
                    {
                    
                        $snapshotName        = $poolName
                    
                    }

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enableDeduplication' -Value ('${0}' -f $isDeduplicated)))

                    $DeduplicateParam = ' -EnableDeduplication $enableDeduplication'
                    
                    if ($isDeduplicatedLocked)
                    {

                        $DeduplicateParam += ' -LockEnableDeduplication'

                    }

                    if (-not [String]::IsNullOrWhiteSpace($enableCompression))
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enableCompression' -Value ('${0}' -f $enableCompression)))

                        $CompressionParam = ' -EnableCompression $enableCompression'

                        if ($isCompressionLocked)
                        {

                            $CompressionParam += ' -LockEnableCompression'

                        }

                    }

                }

                'StoreVirtual'
                {

                    $dataProtectionLevel           = $p.dataProtectionLevel.default
                    $dataProtectionLevelLocked     = $p.dataProtectionLevel.meta.locked
                    $isAdaptiveOptimizationEnabled = $p.isAdaptiveOptimizationEnabled.default
                    $isAdaptiveOptimizationLocked  = $p.isAdaptiveOptimizationEnabled.meta.locked

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dataProtectionLevel' -Value ('"{0}"' -f $dataProtectionLevel)))

                    $DataProtectionLevelParam = ' -DataProtectionLevel $dataProtectionLevel'

                    if ($dataProtectionLevelLocked)
                    {

                        $DataProtectionLevelParam += ' -LockProtectionLevel'

                    }

                    if ($isAdaptiveOptimizationEnabled)
                    {

                        $AdaptiveOptimizationParam = ' -EnableAdaptiveOptimization'
                        
                    }                    

                    if ($isAdaptiveOptimizationEnabled)
                    {

                        $AdaptiveOptimizationParam += ' -LockAdaptiveOptimization'

                    }

                }

            }

            # Scopes
            Try
            {
            
                $ResourceScope = Send-HPOVRequest -Uri $Template.scopesUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $n = 1

            if (-not [String]::IsNullOrEmpty($ResourceScope.scopeUris))
            {

                ForEach ($scopeUri in $ResourceScope.scopeUris)
                {

                    $scopeName = Get-NamefromUri -Uri $scopeUri

                    $ScopeVarName = 'Scope'
                    $Value        = 'Get-HPOVScope -Name "{0}"' -f $scopeName

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $ScopeVarName -Suffix $n -Value $Value))

                    $n++

                }

                $ScopeParam = ' -Scope {0}' -f ([String]::Join(', ', (1..($n - 1) | ForEach-Object { '$Scope{0}' -f $_}))) 

            }
            
            [void]$scriptCode.Add(('New-HPOVStorageVolumeTemplate -Name $name{0}{1}{2}{3}{4}{5}{6}{7}{8}' -f $descParam, $PoolParam, $CapacityParam, $ProvisionTypeParam, $SnapshotPoolParam, $CompressionParam, $DataProtectionLevelParam, $AdaptiveOptimizationParam, $ScopeParam))
                
            DisplayOutput -Code $scriptCode

        }

        Function Generate-StorageVolume-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $SV   = $InputObject

            $name               = $SV.name
            $description        = $SV.description
            $poolUri            = $SV.storagePoolUri
            $size               = $SV.provisionedCapacity / 1GB
            $volTemplateUri     = $SV.volumeTemplateUri
            $ProvisioningType   = $SV.provisioningType
            $isShareable        = $SV.isShareable
            $p                  = $SV.deviceSpecificAttributes
                $isCompressed   = $p.isCompressed
                $isDeduplicated = $p.isDeduplicated
                $snapshotUri    = $p.snapshotPoolUri

            $descParam = $PoolParam = $CapacityParam = $StoragePoolParam = $SnapshotPoolParam = $ProvisionTypeParam = $CompressionParam =$DeduplicateParam = $ScopeParam = $null
            $DataProtectionLevelParam = $AdaptiveOptimizationParam = $null

            [void]$scriptCode.Add('#------ Attributes for storage volume "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))

            if ($description)
            {

                $descParam      = " -Description `$description "
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'description' -Value ('"{0}"' -f $description)))

            }

            $volumeParam = $storagePoolCode = $null

            if ($volTemplateUri)
            {

                $volumeParam     = ' -VolumeTemplate $volumeTemplate'
                $volTemplateName = Get-NamefromUri -Uri $volTemplateUri  

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'volumeTemplateName' -Value ('"{0}"' -f $volTemplateName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'volumeTemplate' -Value ('Get-HPOVStorageVolumeTemplate -Name $volTemplateName')))

            }

            else # volume created without template
            {

                Try
                {
                
                    $pool = Send-HPOVRequest -Uri $PoolUri -Hostname $ApplianceConnection
                    $sts  = Send-HPOVRequest -Uri $pool.storageSystemUri -Hostname $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

                $poolName = $pool.name
                $family   = $sts.family

                $volumeParam        = '-StoragePool $storagePool -capacity $size -ProvisioningType $provisioningType'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'capacity' -Value ('{0}' -f $size)))

                $CapacityParam = ' -Capacity $capacity'

                if ($isShareable)
                {

                    $ProvisionTypeParam = ' -Shared'

                } 

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'provisioningType' -Value ('"{0}"' -f $ProvisioningType)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'poolName' -Value ('"{0}"' -f $poolName)))

                $storagePoolCode = Generate-CustomVarCode -Prefix 'storagePool' -Value 'Get-HPOVStoragePool -Name $poolName'

                Switch ($family)
                {

                    'StoreServ'
                    {

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'stsName' -Value ('"{0}"' -f $sts.name)))
                        $storagePoolCode += ' -StorageSystem $stsName'

                        [void]$scriptCode.Add($storagePoolCode)

                        if ($poolUri -ne $snapshotUri)
                        {

                            $snapshotPoolName = Get-NamefromUri -Uri $snapshotUri

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snapShotPoolName' -Value ('"{0}"' -f $snapshotPoolName)))
                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snapShotPool' -Value 'Get-HPOVStoragePool -Name $snapShotPoolName -StorageSystem $stsName'))

                            $SnapshotPoolParam = ' -SnapshotStoragePool $snapShotPool'

                        }

                        $isDeduplicated       = $p.isDeduplicated
                        $enableCompression    = $p.isCompressed
                        
                        if ($isDeduplicated)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enableDeduplication' -Value ('${0}' -f $isDeduplicated)))

                            $DeduplicateParam = ' -EnableDeduplication $enableDeduplication'

                        }                        
                    
                        if ($enableCompression)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enableCompression' -Value ('${0}' -f $enableCompression)))

                            $CompressionParam = ' -EnableCompression $enableCompression'

                        }

                    }

                    'StoreVirtual'
                    {

                        [void]$scriptCode.Add($storagePoolCode)

                        $dataProtectionLevel = $p.dataProtectionLevel
                        $isAdaptiveOptimizationEnabled = $p.isAdaptiveOptimizationEnabled

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dataProtectionLevel' -Value ('"{0}"' -f $dataProtectionLevel)))

                        $DataProtectionLevelParam = ' -DataProtectionLevel $dataProtectionLevel'

                        if ($isAdaptiveOptimizationEnabled)
                        {

                            $AdaptiveOptimizationParam = ' -EnableAdaptiveOptimization'
                        
                        }                        

                    }                

                }                

            }

            # Scopes
            Try
            {
            
                $ResourceScope = Send-HPOVRequest -Uri $SV.scopesUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $n = 1

            if (-not [String]::IsNullOrEmpty($ResourceScope.scopeUris))
            {

                ForEach ($scopeUri in $ResourceScope.scopeUris)
                {

                    $scopeName = Get-NamefromUri -Uri $scopeUri

                    $ScopeVarName = 'Scope'
                    $Value        = 'Get-HPOVScope -Name "{0}"' -f $scopeName

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $ScopeVarName -Suffix $n -Value $Value))

                    $n++

                }

                $ScopeParam = ' -Scope {0}' -f ([String]::Join(', ', (1..($n - 1) | ForEach-Object { '$Scope{0}' -f $_}))) 

            }

            [void]$scriptCode.Add(('New-HPOVStorageVolume -Name $name{0}{1}{2}{3}{4}{5}{6}{7}{8}' -f $volumeParam, $descParam, $CapacityParam, $ProvisionTypeParam, $DeduplicateParam, $CompressionParam, $DataProtectionLevelParam, $AdaptiveOptimizationParam, $ScopeParam))

            DisplayOutput -Code $scriptCode

        }

        Function Generate-LogicalInterConnectGroup-Script ($InputObject) 
        {
            
            $scriptCode =  [System.Collections.ArrayList]::new()

            $ICModuleTypes               = @{
                "VirtualConnectSE40GbF8ModuleforSynergy"   =  "SEVC40f8" ;
                "VirtualConnectSE100GbF32ModuleforSynergy" =  "SEVC100f32" ;
                "Synergy50GbInterconnectLinkModule"        =  "SE50ILM";
                "Synergy20GbInterconnectLinkModule"        =  "SE20ILM";
                "Synergy10GbInterconnectLinkModule"        =  "SE10ILM";
                "VirtualConnectSE16GbFCModuleforSynergy"   =  "SEVC16GbFC";
                "VirtualConnectSE32GbFCModuleforSynergy"   =  "SEVC32GbFC";
                "Synergy12GbSASConnectionModule"           =  "SE12SAS";
                "571956-B21"                               =  "FlexFabric";
                "455880-B21"                               =  "Flex10";
                "638526-B21"                               =  "Flex1010D";
                "691367-B21"                               =  "Flex2040f8";
                "572018-B21"                               =  "VCFC20";
                "466482-B21"                               =  "VCFC24";
                "641146-B21"                               =  "FEX"
            }

            $FabricModuleTypes           = @{
                "VirtualConnectSE40GbF8ModuleforSynergy"    =  "SEVC40f8" ;
                "VirtualConnectSE100GbF32ModuleforSynergy"  =  "SEVC100f32" ;
                "Synergy12GbSASConnectionModule"            =  "SAS";
                "VirtualConnectSE16GbFCModuleforSynergy"    =  "SEVCFC";
                "VirtualConnectSE32GbFCModuleforSynergy"    =  "SEVCFC";
            }

            $ICModuleToFabricModuleTypes = @{
                "SEVC40f8"                                  = "SEVC40f8" ;
                "SEVC100f32"                                = "SEV100f32" ;
                'SE50ILM'                                   = "SEV100f32" ;
                'SE20ILM'                                   = "SEVC40f8" ;
                'SE10ILM'                                   = "SEVC40f8" ;
                "SEVC16GbFC"                                = "SEVCFC" ;
                "SEVC32GbFC"                                = "SEVCFC" ;
                "SE12SAS"                                   = "SAS"
            }

            $UnsupportedLigTypes = 'FEX', 'SAS'

            $LigType = $ScopeParam = $QosParam = $null

            $lig     = $InputObject

            $name          = $lig.Name
            $enclosureType = $lig.enclosureType
            $description   = $lig.description
            $uplinkSets    = $lig.uplinksets | Sort-Object Name
            $qos           = $lig.qosConfiguration.activeQosConfig

            switch ($lig.category)
            {

                'sas-logical-interconnect-groups'
                {

                    $LigType = 'SAS'

                }

                'logical-interconnect-groups'
                {

                    $LigType = 'EthernetFC'

                    $snmp                   = $lig.snmpConfiguration
                    $Telemetry              = $lig.telemetryConfiguration
                        $sampleCount            = $Telemetry.sampleCount
                        $sampleInterval         = $Telemetry.sampleInterval

                    # The following is only applicable to Ethernet LIG, not FC or SAS
                    $internalNetworkUris    = $lig.internalNetworkUris
                    $fastMacCacheFailover   = $lig.ethernetSettings.enableFastMacCacheFailover
                    $macrefreshInterval     = $lig.ethernetSettings.macRefreshInterval
                    $igmpSnooping           = $lig.ethernetSettings.enableIGMPSnooping
                    $igmpIdleTimeout        = $lig.ethernetSettings.igmpIdleTimeoutInterval
                    $networkLoopProtection  = $lig.ethernetSettings.enablenetworkLoopProtection
                    $PauseFloodProtection   = $lig.ethernetSettings.enablePauseFloodProtection
                    $redundancyType         = $lig.redundancyType
                    $EnableRichTLV          = $lig.EthernetSettings.enableRichTLV
                    $LDPTagging             = $lig.EthernetSettings.enableTaggedLldp
                    
                }

            }

            [void]$scriptCode.Add('# -------------- Attributes for Logical Interconnect Group "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
            
            $FrameCount = $InterconnectBaySet = $frameCountParam = $null
            $intnetParam = $null

            # ----------------------------
            # Find Interconnect devices
            $Bays         = [System.Collections.ArrayList]::new()
            $UpLinkPorts  = [System.Collections.ArrayList]::new()
            $Frames       = [System.Collections.ArrayList]::new()

            $LigInterconnects = $lig.interconnectMapTemplate.interconnectMapEntryTemplates | Where-Object { -not [String]::IsNullOrWhiteSpace($_.permittedInterconnectTypeUri) }

            $BayHashtable = New-Object System.Collections.Specialized.OrderedDictionary

            foreach ($ligIC in $LigInterconnects)
            {

                # -----------------
                # Locate the Interconnect device and its position
                $ICTypeuri  = $ligIC.permittedInterconnectTypeUri

                if ($enclosureType -eq $Syn12K)
                {

                    $ICtypeName   = (Get-NamefromUri -Uri $ICTypeUri).Replace(' ',$null) # remove Spaces
                    $ICmoduleName = $ICModuleTypes[$ICtypeName]

                    $BayNumber   = ($ligIC.logicalLocation.locationEntries | Where-Object Type -eq "Bay").RelativeValue
                    $FrameNumber = [math]::abs(($ligIC.logicalLocation.locationEntries | Where-Object Type -eq "Enclosure").RelativeValue)

                    $fabricModuleType = $ICModuleToFabricModuleTypes[$ICmoduleName] 

                    if (-not ($BayHashtable.GetEnumerator() | Where-Object Name -eq "Frame$FrameNumber"))
                    {

                        $BayHashtable.Add("Frame$FrameNumber", (New-Object Hashtable))

                    }

                    # Use this hashtable to build the final string value for scriptCode
                    $BayHashtable."Frame$FrameNumber".Add("Bay$BayNumber", $ICmoduleName)

                }

                else # C7K
                {

                    Try
                    {
                    
                        $PartNumber   = (Send-HPOVRequest -Uri $ICTypeuri -Hostname $ApplianceConnection).partNumber
                    
                    }
                    
                    Catch
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }

                    if ("FEX" -eq $ICModuleTypes[$PartNumber])
                    {

                        $LigType = 'FEX'

                    }

                    $ICmoduleName = $ICModuleTypes[$PartNumber]
                    $BayNumber    = ($ligIC.logicalLocation.locationEntries | Where-Object Type -eq "Bay").RelativeValue

                    [void]$Bays.Add(('Bay{0} = "{1}"' -f $BayNumber, $ICmoduleName)) # Format is xx=Flex Fabric

                }
            
            }

            if ($enclosureType -eq $Syn12K -and $UnsupportedLigTypes -notcontains $LigType)
            {

                $FrameCount = $lig.EnclosureIndexes.Count

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'frameCount' -Value ('{0}' -f $FrameCount)))

                $frameCountParam = ' -FrameCount $frameCount'

            }

            # ----------------------------
            # Find Internal networks
            $intNetworks = [System.Collections.ArrayList]::new()
            $intNetworkNames = [System.Collections.ArrayList]::new()
            
            foreach ($uri in $internalNetworkUris)
            {

                Try
                {
                
                    $net = Send-HPOVRequest -Uri $uri -Hostname $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

                $netname = "'{0}'" -f $net.name

                [void]$intNetworkNames.Add($netname)
                [void]$intNetworks.Add($net)

            }

            #Code and parameters

            [Array]::Sort($Bays)

            $BayConfig    = [System.Collections.ArrayList]::new()

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'bayConfig' -Value '@{'))

            if ($enclosureType -eq $Syn12K)  # Synergy
            {

                # $BayConfigperFrame = [System.Collections.ArrayList]::new()
                $SynergyCode       = [System.Collections.ArrayList]::new()
                $CurrentFrame      = $null

                $InterconnectBaySet = $lig.interconnectBaySet

                $f = 1

                # Process Bays parameter
                foreach ($b in ($BayHashtable.GetEnumerator() | Sort-Object Name))
                {

                    [void]$scriptCode.Add(("`t{0} = @{1}" -f $b.Name, $OpenDelim))

                    $endDelimiter = $SepHash

                    if ($f -eq $BayHashtable.Count)
                    {

                        $endDelimiter = $null

                    }

                    $_b = 1

                    # Loop through ports
                    ForEach ($l in ($b.Value.GetEnumerator() | Sort-Object Name))
                    {

                        $subEndDelimiter = $SepHash

                        if ($_b -eq $b.Value.Count)
                        {

                            $subEndDelimiter = $null

                        }

                        [void]$scriptCode.Add(("`t`t{0} = '{1}'{2}" -f $l.Name, $l.Value, $subEndDelimiter))

                        $_b++

                    }

                    [void]$scriptCode.Add(("`t{0}{1}" -f $CloseDelim, $endDelimiter))

                    $f++

                }

                [void]$scriptCode.Add('}')

                if ($redundancyType)
                {

                    $redundancyParam = ' -fabricredundancy $redundancyType'

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'redundancyType' -Value ('"{0}"' -f $redundancyType)))

                }

                $FabricModuleTypeParam  = ' -FabricModuleType $fabricModuleType'
                $ICBaySetParam          = ' -InterConnectBaySet $InterconnectBaySet'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'fabricModuleType' -Value ('"{0}"' -f $fabricModuleType)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'InterconnectBaySet' -Value ('{0}' -f $InterconnectBaySet)))

                # Clear out parameters used for Synergy
                $PauseFloodProtectionParam = $macRefreshIntervalParam = $fastMacCacheParam = $null
            
            }

            else # C7K
            {

                $_b = 1

                ForEach ($b in $Bays)
                {

                    $endDelimiter = $SepHash

                    if ($_b -eq $Bays.Count)
                    {

                        $endDelimiter = $null

                    }

                    [void]$scriptCode.Add(("`t{0}{1}" -f $b, $endDelimiter))

                    $_b++

                }

                [void]$scriptCode.Add('}')
                           
                #Parameters valid only for C7000
                if ($UnsupportedLigTypes -notcontains $LigType)
                {

                    if ($fastMacCacheFailover)
                    {
                    
                        $macRefreshIntervalParam = $macRefreshIntervalCode = $null

                        if ($macRefreshInterval)
                        {

                            $macRefreshIntervalParam = " -macRefreshInterval `$macReFreshInterval "

                            $scriptCode.Add((Generate-CustomVarCode -Prefix 'macRefreshInterval' -Value ('$macRefreshInterval')))

                        }

                        $fastMacCacheParam = ' -enableFastMacCacheFailover:$fastMacCacheFailover {0}' # + $FastMacCacheIntervalParam

                    }    
    
                    $PauseFloodProtectionParam = " -enablePauseFloodProtection:`$pauseFloodProtection "

                }
                
                # -------Clear out parameters used for Synergy
                $RedundancyParam        = $null
                $FabricModuleTypeParam  = $null
                $FrameCountParam        = $ICBaySetParam = $null
        
            }            

            # Code and Parameters
            $igmpParam = $networkLoopProtectionParam = $EnhancedLLDPTLVParam = $LDPtaggingParam = $null

            # ---- Bay config
            $baysParam              = ' -Bays $bayConfig'

            if ($UnsupportedLigTypes -notcontains $LigType)
            {

                $igmpIdleTimeoutParam = $igmpIdleTimeoutCode = $intnetParam = $intnetCode = $snmpParam = $null

                if ($igmpSnooping)
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'igmpSnooping' -Value ('${0}' -f $igmpSnooping)))

                    if ($igmpIdletimeOut)
                    { 

                        $igmpIdleTimeoutParam = ' -IgmpIdleTimeOutInterval $igmpIdleTimeout'
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'igmpIdletimeOut' -Value ('{0}' -f $igmpIdletimeOut)))

                    }

                    $igmpParam                  = ' -enableIGMP:$igmpSnooping {0};' -f $igmpIdleTimeoutParam   

                }

                if ($networkLoopProtection)
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'networkLoopProtection' -Value ('${0}' -f $networkLoopProtection)))
                    $networkLoopProtectionParam = ' -enablenetworkLoopProtection:$networkLoopProtection'

                }

                if ($LDPTagging)
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'LDPtagging' -Value ('${0}' -f $LDPtagging)))
                    $LDPtaggingParam            = ' -EnableLLDPTagging:$LDPtagging'

                }

                if ($EnableRichTLV)
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'EnableRichTLV' -Value ('${0}' -f $EnableRichTLV)))
                    $EnhancedLLDPTLVParam       = ' -enableEnhancedLLDPTLV:$EnableRichTLV'

                }

                if ($intNetworkNames.Count -gt 0)
                {

                    $intNetParam            = ' -InternalNetworks $intNetnames'
                    
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'intNetnames' -Value ('{0} | Get-HPOVNetwork ' -f [String]::Join($Comma, $intNetworkNames.ToArray()))))

                }  

                if ($snmp)
                {

                    $isV1Snmp           = $snmp.enabled
                    $isV3Snmp           = $snmp.v3Enabled

                    if ($isV1Snmp -or $isV3Snmp)
                    {

                        $readCommunityParam = $snmpParam = $contactParam = $snmpV3UsersParam = $accessListParam = $informParam = $null

                        $trapdestParam = ' -TrapDestinations $trapDestinations'

                        $readCommunity    = $snmp.readCommunity 
                        $contact          = $snmp.systemContact
                        $snmpUsers        = $snmp.snmpUsers
                        $accessList       = $snmp.snmpAccess
                        $trapdestinations = $snmp.trapDestinations

                        [void]$scriptCode.Add('#-- Generating snmp object for LIG')
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'readCommunity' -Value ('"{0}"' -f $readCommunity)))
                        $readCommunityParam = ' -ReadCommunity $readCommunity'                        

                        if ($isV1Snmp)
                        {

                            $snmpParam += ' -SnmpV1'

                        }

                        if ($isV3Snmp)
                        {

                            $snmpParam += ' -SnmpV3'

                        }

                        if ($Contact)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'contact' -Value ('"{0}"' -f $contact)))
                            $contactParam = ' -Contact $contact'

                        }

                        $SnmpV3UsersProcessed = [System.Collections.ArrayList]::new()

                        $u = 1
                        # Process trap destinations
                        foreach ($t in $trapdestinations)
                        {

                            $destParam = $communityStrParam = $portParam = $trapFormatParam = $severityParam = $vcmCategoryParam = $enetCategoryParam = $fcCateoryParam = $snmpUserParam = $engineIdParam = $null

                            $destination        = $t.trapDestination
                            $communityString    = $t.communityString
                            $trapFormat         = $t.trapFormat
                            $severities         = $t.trapSeverities
                            $vcmTrapCategories  = $t.vcmTrapCategories
                            $enetTrapCategories = $t.enetTrapCategories
                            $fcTrapCategories   = $t.fcTrapCategories
                            $port               = $t.port
                            $snmpUserName       = $t.userName
                            $snmpUserEngineId   = $t.engineId
                            $inform             = $t.inform

                            [void]$scriptCode.Add('#-- Generating Trap destination object for "{0}" ' -f $destination)
                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'destination' -Value ('"{0}"' -f $destination)))
                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'trapFormat' -Value ('"{0}"' -f $trapFormat)))
                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'port' -Value ('{0}' -f $port)))

                            $destParam       = ' -destination $destination'
                            $trapFormatParam = ' -SnmpFormat $trapformat'
                            $portParam       = ' -Port $port'
                            
                            # Need to ccreate new SNMPv3 user param for each trap destination
                            if ($trapFormat -match 'SNMPv3')
                            {

                                if (-not ($SnmpV3UsersProcessed | Where-Object Name -eq $snmpUserName))
                                {

                                    $authProtParam = $privProtParam = $null

                                    $securitylevel = 'None'
                                    
                                    $snmpv3UserDetails = $snmpUsers | Where-Object snmpV3UserName -eq $snmpUserName

                                    $snmpV3AuthProtocol    = $snmpv3UserDetails.v3AuthProtocol
                                    $snmpv3PrivacyProtocol = $snmpv3UserDetails.v3PrivacyProtocol

                                    [void]$scriptCode.Add('#-- Generating SNMPv3 user "{0}"' -f $snmpUserName)
                                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'userName' -Value ('"{0}"' -f $snmpUserName)))

                                    $snmpUserNameParam = ' -Username $userName'

                                    if ($snmpV3AuthProtocol -ne 'NA')
                                    {

                                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'authProtocol' -Value ('"{0}"' -f $snmpV3AuthProtocol)))
                                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'authPassword' -Value ('Read-Host -AsSecureString -Message "Provide password for Authentication Protocol."' -f $destination)))

                                        $authProtParam = ' -AuthProtocol $authProtocol -AuthPassword $authPassword'

                                        $securitylevel = 'AuthOnly'

                                        if ($snmpv3PrivacyProtocol -ne 'NA')
                                        {

                                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'privProtocol' -Value ('"{0}"' -f $snmpv3PrivacyProtocol)))
                                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'privPassword' -Value ('Read-Host -AsSecureString -Message "Provide password for Privacy Protocol."' -f $destination)))

                                            $privProtParam = ' -PrivProtocol $privProtocol -PrivPassword $privPassword'
                                            
                                            $securitylevel = 'AuthAndPriv'

                                        }

                                    }

                                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'securityLevel' -Value ('"{0}"' -f $securitylevel)))
                                    $securityLevelParam = ' -SecurityLevel $securityLevel'

                                    $VarName = 'snmpv3User'
                                    $Value = 'New-HPOVSnmpV3User{1}{2}{3}{4}' -f $u, $snmpUserNameParam, $securityLevelParam, $authProtParam, $privProtParam

                                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $VarName -Suffix $u -Value $Value))

                                    $snmpV3UserParamVarName = '${0}{1}' -f $VarName, $u
                                    
                                    [void]$SnmpV3UsersProcessed.Add(@{name = $snmpUserName; varName = ('snmpv3User{0}' -f $u)})

                                    $u++

                                }
                                
                                else
                                {
                                
                                    $snmpV3UserParamVarName = '${0}' -f ($SnmpV3UsersProcessed | Where-Object name -eq $snmpUserName).varName
                                
                                }

                                $snmpUserParam = ' -SnmpV3User {0}' -f $snmpV3UserParamVarName

                            }

                            if ($inform)
                            {
                            
                                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'inform' -Value ('"{0}"' -f 'Inform')))

                                if ($trapFormat -match 'SNMPv3')
                                {

                                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'engineId' -Value ('"{0}"' -f $snmpUserEngineId)))
                                    $engineIdParam = ' -EngineID $engineId'

                                }
                            
                            }

                            else
                            {
                            
                                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'inform' -Value ('"{0}"' -f 'Trap')))
                            
                            }

                            $informParam    = ' -NotificationType $inform'
                            
                            [void]$scriptCode.Add(('$trapDestinations += New-HPOVSnmpTrapDestination{0}{1}{2}{3}{4}{5}' -f $destParam, $portParam, $communityParam, $FormatParam, $snmpUserParam, $informParam, $engineIdParam))

                        }

                        if ($SnmpV3UsersProcessed.Count -gt 0)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'snmpv3Users' -Value ('@(${0})' -f [String]::Join(', $', $SnmpV3UsersProcessed.varName))))

                             $snmpV3UsersParam = ' -Snmp3Users $snmpv3Users'

                        }

                        if ($accessList)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'accessList' -Value ('@("{0}")' -f [String]::Join('", "', $accessList))))

                            $accessListParam = ' -AccessList $accessList'

                        }

                        [void]$scriptCode.Add(('$snmpConfig += New-HPOVSnmpConfiguration{0}{1}{2}{3}{4}{5}' -f $readCommunityParam, $snmpParam, $contactParam, $trapdestParam, $snmpV3UsersParam, $accessListParam))

                    }

                }

                if ($qos.configType -ne 'Passthrough')
                {

                    $qosConfigType = $qos.configType
                    $uClassType    = $qos.uplinkClassificationType
                    $dClassType    = $qos.downlinkClassificationType

                    [void]$scriptCode.Add('#-- Generating QoS Configuration "{0}" ' -f $qosConfigType)
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'qosConfigType' -Value ('"{0}"' -f $qosConfigType)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'uClassType' -Value ('"{0}"' -f $uClassType)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dClassType' -Value ('"{0}"' -f $dClassType)))

                    $q = 1

                    ForEach ($trafficClass in $qos.qosTrafficClassifiers)
                    {

                        $ingressDot1pClassMappingParam = $ingressDscpClassMappingParam = $null

                        $className                = $trafficClass.qosTrafficClass.className
                        $realTime                 = $trafficClass.qosTrafficClass.realTime
                        $bandwidthShare           = $trafficClass.qosTrafficClass.bandwidthShare
                        $maxBandwidth             = $trafficClass.qosTrafficClass.maxBandwidth
                        $egressDot1pValue         = $trafficClass.qosTrafficClass.egressDot1pValue
                        $isEnabled                = $trafficClass.qosTrafficClass.enabled
                        $ingressDot1pClassMapping = $trafficClass.qosClassificationMapping.dot1pClassMapping
                        $ingressDscpClassMapping  = $trafficClass.qosClassificationMapping.dscpClassMapping

                        [void]$scriptCode.Add('#---- Generating QoS Traffic Class Mapping "{0}" ' -f $className)
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'dClanamessType' -Value ('"{0}"' -f $className)))
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'realTime' -Value ('${0}' -f $realTime)))
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'bandwidthShare' -Value ('{0}' -f $bandwidthShare)))
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'maxBandwidth' -Value ('{0}' -f $maxBandwidth)))
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'egressDot1pValue' -Value ('{0}' -f $egressDot1pValue)))

                        if ($null -ne $ingressDot1pClassMapping)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ingressDot1pClassMapping' -Value ('{0}' -f [String]::Join(', ', $ingressDot1pClassMapping))))

                            $ingressDot1pClassMappingParam = ' -IngressDot1pClassMapping $ingressDot1pClassMapping'

                        }
                        
                        if ($null -ne $ingressDscpClassMapping)
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ingressDscpClassMapping' -Value ('"{0}"' -f [String]::Join('", "', $ingressDscpClassMapping))))

                            $ingressDscpClassMappingParam = ' -IngressDscpClassMapping $ingressDscpClassMapping'

                        }
                        
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'isEnabled' -Value ('${0}' -f $isEnabled)))

                        $VarName = 'trafficClass'
                        $Value = 'New-HPOVQosTrafficClass -Name $name -MaxBandwidth $maxBandwidth -BandwidthShare -RealTime:$realTime -EgressDot1pValue $egressDot1pValue{0}{1} -Enabled:$isEnabled' -f $ingressDot1pClassMappingParam, $ingressDscpClassMappingParam

                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $VarName -Suffix $q -Value $Value))

                        $q++

                    }

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'QosConfig' -Value ('New-HPOVQosConfig -ConfigType {0} -UplinkClassificationType {1} -UplinkClassificationType {2} -TrafficClassifiers {3}' -f $qosConfigType, $uClassType, $dClassType, ([String]::Join(', ', (1..($q - 1) | ForEach-Object { '$trafficClass{0}' -f $_}))))))
                    $QosParam = ' -QosConfiguration $QosConfig'

                }

            }

            # Scopes
            Try
            {
            
                $ResourceScope = Send-HPOVRequest -Uri $lig.scopesUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $n = 1

            if (-not [String]::IsNullOrEmpty($ResourceScope.scopeUris))
            {

                ForEach ($scopeUri in $ResourceScope.scopeUris)
                {

                    $scopeName = Get-NamefromUri -Uri $scopeUri

                    $ScopeVarName = 'Scope'
                    $Value = 'Get-HPOVScope -Name "{0}"' -f $scopeName

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $ScopeVarName -Suffix $n -Value $Value))

                    $n++

                }

                $ScopeParam = ' -Scope {0}' -f ([String]::Join(', ', (1..($n - 1) | ForEach-Object { '$Scope{0}' -f $_}))) 

            }

            [void]$scriptCode.Add(('{0}New-HPOVLogicalInterconnectGroup -Name $name -Bays $bayConfig{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}' -f $LigVariable, $FabricModuleTypeParam, $FrameCountParam, $ICBaySetParam, $igmpParam, $intNetParam, $networkLoopProtectionParam, $EnhancedLLDPTLVParam, $LDPtaggingParam, $QosParam, $ScopeParam))

            DisplayOutput -Code $scriptCode
            
            # Process Uplink Sets
            Generate-uplinkSet-Script -InputObject $lig

            Insert-BlankLine

        }

        Function Generate-uplinkSet-Script ($InputObject)
        {

            $uplinkSets = $parentType = $RootLocationInfos = $subLocationInfo = $parentName = $enclosureType = $null
            $scriptCode = [System.Collections.ArrayList]::new()

            switch ($InputObject.type)
            {

                {$_ -match 'uplink-set'}
                {

                    $parentType        = 'LogicalInterconnect'
                    $RootLocationInfos = 'portConfigInfos'
                    $subLocationInfo   = 'location'

                    Try
                    {
                
                        $parent = Send-HPOVRequest -Uri $InputObject.logicalInterconnectUri -Hostname $ApplianceConnection

                        $parentName    = $parent.name
                        $enclosureType = $parent.enclosureType
                        $interconnects = $parent.interconnectMap.interconnectMapEntries
                
                    }
                
                    Catch
                    {
                
                        $PSCmdlet.ThrowTerminatingError($_)
                
                    }

                    $uplinkSets = $InputObject

                }

                # Not supported
                {$_ -match 'sas-logical-interconnect'}
                {

                    $parentType        = 'SasLogicalInterconnectGroup'

                }

                default
                {

                    $parentType        = 'LogicalInterconnectGroup'
                    $RootLocationInfos = 'logicalPortConfigInfos'
                    $subLocationInfo   = 'logicalLocation'

                    $parent = $InputObject                        
            
                    $parentName    = $parent.Name
                    $enclosureType = $parent.enclosureType
                    $uplinkSets    = $parent.uplinkSets | sort-object Name
                    $interconnects = $parent.interconnectMapTemplate.interconnectMapEntryTemplates

                }

            }

            foreach ($upl in $uplinkSets)
            {

                $uplName            = $Upl.name
                $upLinkType         = if ($Upl.networkType -eq "Ethernet") { $Upl.ethernetNetworkType } else { $Upl.networkType }
                $ethMode            = $Upl.mode
                $networkURIs        = $upl.networkUris

                [void]$scriptCode.Add(('# -------------- Attributes for Uplink Set "{0}" associated to {1} "{2}"' -f $uplName, $parentType, $parentName))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $uplName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'uplinkType' -Value ('"{0}"' -f $uplinkType)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'parentName' -Value ('"{0}"' -f $parentName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'parent' -Value ('Get-HPOV{0} -Name $parentName' -f $parentType)))

                switch ($parentType)
                {

                    'LogicalInterconnect'
                    {

                        $uplLogicalPorts  = $Upl.portConfigInfos
                        $LocationPropName = 'location'
                        $ValuePropName    = 'value'

                    }

                    'LogicalInterconnectGroup'
                    {

                        $uplLogicalPorts  = $Upl.logicalportconfigInfos
                        $LocationPropName = 'logicalLocation'
                        $ValuePropName    = 'relativeValue'
                        
                    }

                }

                # ----------------------------
                # Find networks
                $netNamesArray = [System.Collections.ArrayList]::new()
                $networkNames  = $fcTrunkingParam = $null

                switch ($upl.networkType)
                {

                    'Ethernet'
                    {

                        $nativeNetURI = $Upl.nativeNetworkUri
                        $netTagtype   = $Upl.ethernetNetworkType
                        $lacpTimer    = $Upl.lacpTimer

                        if ($Null -ne $nativeNetURI)
                        {
                
                            $nativeNetname = Get-NamefromUri -Uri $nativeuri

                        }

                        foreach ($neturi in $networkUris)
                        {

                            $netName = Get-NamefromUri -Uri $neturi
                            [void]$netNamesArray.Add($netName)

                        }

                        foreach ($fcoeNetUri in $fcoeNetworkUris)
                        {

                            $netName = Get-NamefromUri -Uri $fcoeNetUri
                            [void]$netNamesArray.Add($netName)

                        }

                    }

                    'FibreChannel'
                    {

                        $fcMode  = $upl.fcMode

                        # //TODO: Is this even correct??
                        $fcSpeed = if ($Upl.FCSpeed) { $Upl.FCSpeed } else { 'Auto' }
                        
                        if ($fcMode -eq 'Trunk')
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enableTrunking' -Value '$true'))

                            $fcTrunkingParam = ' -EnableTrunking $enableTrunking'

                        }

                        foreach ($fcNetUri in $fcNetworkUris)
                        {

                            $netName = Get-NamefromUri -Uri $fcNetUri
                            [void]$netNamesArray.Add($netName)

                        }

                    }

                }
                    
                # ----------------------------
                # Find uplink ports
                $UpLinkArray = [System.Collections.ArrayList]::new()

                foreach ($logicalPort in $uplLogicalPorts)
                {
                    
                    $Speed          = $UpLinkLocation = $Port = $icm = $null

                    $ThisBayNumber  = ($logicalPort.$LocationPropName.locationEntries | Where-Object Type -eq 'Bay').$ValuePropName
                    $ThisPortNumber = ($logicalPort.$LocationPropName.locationEntries | Where-Object Type -eq 'Port').$ValuePropName
                    $ThisEnclosure  = ($logicalPort.$LocationPropName.locationEntries | Where-Object Type -eq 'Enclosure').$ValuePropName

                    # Loop through Interconnect Map Entry Template items looking for the provided Interconnet Bay number
                    ForEach ($l in $interconnects) 
                    {

                        $ThisIcmEnclosureLocation = ($l.$LocationPropName.locationEntries | Where-Object { $_.type -eq "Enclosure" -and $_.$ValuePropName -eq $ThisEnclosure}).$ValuePropName
                        $ThisIcmBayLocation       = ($l.$LocationPropName.locationEntries | Where-Object { $_.type -eq "Bay" -and $_.$ValuePropName -eq $ThisBayNumber}).$ValuePropName

                        if ($enclosureType -eq $Syn12K) 
                        {

                            if ($ThisIcmBayLocation -and $l.enclosureIndex -eq $ThisEnclosure) 
                            {
                                        
                                $permittedInterconnectTypeUri = $l.permittedInterconnectTypeUri

                            }

                        }

                        else
                        {
                        
                            if ($l.$LocationPropName.locationEntries | Where-Object { $_.type -eq "Bay" -and $_.$ValuePropName -eq $ThisBayNumber }) 
                            {
                                        
                                $permittedInterconnectTypeUri = $l.permittedInterconnectTypeUri

                            }
                                                    
                        }
                        
                    } 

                    Try
                    {
                    
                        $PermittedInterConnectType = Send-HPOVRequest $permittedInterconnectTypeUri -Hostname $ApplianceConnection
                    
                    }
                    
                    Catch
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }
                    
                    # 1. Find port numbers and port names from permittedInterconnectType
                    $PortInfos     = $PermittedInterConnectType.PortInfos

                    # 2. Find Bay number and Port number on uplinksets
                    $ICLocation    = $icm.$RootLocationInfos.$subLocationInfo
                    $ICBay         = ($ICLocation | Where-Object Type -eq "Bay").$ValuePropName
                    $ICEnclosure   = ($IClocation | Where-Object Type -eq "Enclosure").$ValuePropName

                    # 3. Get faceplate port name
                    $ThisPortName   = ($PortInfos    | Where-Object PortNumber -eq $ThisPortNumber).PortName

                    if ($ThisEnclosure -eq -1)    # FC module
                    {

                        $UpLinkLocation = "Bay{0}:{1}" -f $ThisBayNumber, $ThisPortName   # Bay1:1
                    
                    }

                    else  # Synergy Frames or C7000
                    {

                        if ($enclosureType -eq $Syn12K) 
                        {

                            $UpLinkLocation = "Enclosure{0}:Bay{1}:{2}" -f $ThisEnclosure, $ThisBayNumber, $ThisPortName.Replace(":", ".")   # Enclosure#:Bay#:Q1.3; In $PortInfos, format is Q1:4, output expects Q1.4
                        
                        }

                        else # C7000
                        {

                            $UpLinkLocation = "Bay{0}:{1}" -f $ThisBayNumber, $ThisPortName.Replace(":", ".")   # Bay#:Q1.3; In $PortInfos, format is Q1:4, output expects Q1.4
                        
                        }

                    }

                    [void]$UpLinkArray.Add($UpLinkLocation)

                }

                $UpLinkArray.Sort()

                # Uplink Ports
                $uplinkPortParam    = $uplinkPortCode    = $null

                if ($UplinkArray) 
                {

                    $uplinkPortParam    = ' -UplinkPorts $uplinkPorts'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'uplinkPorts' -Value ('"{0}"' -f [String]::Join('", "', $UpLinkArray.ToArray()))))

                }
                    
                # Networks
                $uplNetworkParam    = $uplNetworkCode = $null
                if ($netNamesArray.Count -gt 0)
                { 

                    $uplNetworkParam    = ' -Networks $networks'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'networks' -Value ('"{0}" | Get-HPOVNetwork' -f [String]::Join('", "', $netNamesArray.ToArray()))))

                }
                
                $lacpTimerParam  =  $netAttributesParam = $uplNativeNetParam = $null

                # Uplink Type
                if ($uplinkType -eq 'FibreChannel')
                {

                    $netAttributesParam     = ' -fcUplinkSpeed $FCSpeed'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'fcSpeed' -Value ('"{0}"' -f $fcSpeed)))

                }

                else # Ethernet-type
                {

                    if ($null -ne $nativeNetname)
                    {

                        $uplNativeNetParam = " -nativeEthnetwork $nativenetwork"
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'nativeNetwork' -Value ('Get-HPOVNetwork -Name "{0}"' -f $nativeNetname)))

                    }

                    if ($ethMode -ne 'Audo')
                    {

                        $netAttributesParam += ' -EthMode $ethMode'
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ethMode' -Value ('"{0}"' -f $ethMode)))
                        
                    }

                    if ($lacpTimer) 
                    {

                        $netAttributesParam += ' -lacptimer $lacpTimer'                        
                        [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'lacpTimer' -Value ('"{0}"' -f $lacpTimer)))

                    }

                }

                [void]$scriptCode.Add(('New-HPOVUplinkSet -InputObject $parent -Name $name -Type $uplinkType{0}{1}{2}{3}{4}' -f $uplNetworkParam, $netAttributesParam, $uplinkPortParam, $uplNativeNetParam, $fcTrunkingParam))

            }

            DisplayOutput -Code $scriptCode

        }

        Function Generate-EnclosureGroup-Script ($InputObject)
        {
            
            $scriptCode = [System.Collections.ArrayList]::new()

            $EG     = $InputObject

            $name                   = $EG.name
            $description            = $EG.description
            $enclosureCount         = $EG.enclosureCount
            $powerMode              = $EG.powerMode
            $scopesUri              = $EG.scopesUri

            $manageOSDeploy         = $EG.osDeploymentSettings.manageOSDeployment
            $deploySettings         = $EG.osDeploymentSettings.deploymentModeSettings
            $deploymentMode         = $deploySettings.deploymentMode

            $ipV4AddressType        = $EG.ipAddressingMode
            $ipRangeUris            = $EG.ipRangeUris
            $ICbayMappings          = $EG.interConnectBayMappings | Where-Object { $null -ne $_.logicalInterconnectGroupUri } | Sort-Object enclosureIndex, interconnectBay
            $EnclosurCount          = $EG.enclosureCount
            $enclosuretype          = $EG.enclosureTypeUri.Split('/')[-1]

            [void]$scriptCode.Add('# -------------- Attributes for enclosure group "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))

            # --- Find Enclosure Bay Mapping
            ###

            $enclosureCountParam = $IPv4AddressTypeParam = $ligMappingParam  = $null

            if ($ICbayMappings)
            {
                
                $BayHashtable = New-Object System.Collections.Specialized.OrderedDictionary

                $l = 1

                ForEach ($LIG in $ICBayMappings)
                {

                    $FrameID = $null

                    $thisLIGName = Get-NamefromUri -Uri $LIG.logicalInterconnectGroupURI

                    $LigVarName = '$lig{0}' -f $l

                    # Multi or specific frame configuration
                    if (-not [String]::IsNullOrEmpty($LIG.enclosureIndex))
                    {
                        
                        $FrameID     = 'Frame{0}' -f $LIG.enclosureIndex

                        if (-not ($BayHashtable.GetEnumerator() | Where-Object Name -eq $FrameID))
                        {

                            $BayHashtable.Add($FrameID, ([System.Collections.ArrayList]::new()))

                        }

                        if (-not ($BayHashtable.GetEnumerator() | Where-Object Name -eq $FrameID).Value -eq $LigVarName)
                        {

                            # Use this hashtable to build the final string value for scriptCode
                            [Void]$BayHashtable.$FrameID.Add($LigVarName)
                    
                            $Value = 'Get-HPOVLogicalInterconnectGroup -Name "{0}"' -f $thisLIGName

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $LigVarName -Value $Value))

                            $l++

                        }                        

                    }

                    else
                    {
                    
                        if (-not ($BayHashtable.GetEnumerator() | Where-Object Name -eq $thisLIGName).Value -eq $LigVarName)
                        {

                            # Use this hashtable to build the final string value for scriptCode
                            [Void]$BayHashtable.Add($thisLIGName, $LigVarName)

                            $Value = 'Get-HPOVLogicalInterconnectGroup -Name "{0}"' -f $thisLIGName

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $LigVarName -Value $Value))

                            $l++

                        }   
                    
                    }

                }

                if ($BayHashtable)
                {

                    $ligMappingParam        =  ' -LogicalInterconnectGroupMapping $LigMapping'

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'LigMapping' -Value '@{'))

                    $c = 1

                    ForEach ($l in $BayHashtable.GetEnumerator())
                    {

                        $endDelimiter = $SepHash

                        if ($c -eq $BayHashtable.Count)
                        {

                            $endDelimiter = $null

                        }

                        if ($l.Name.StartsWith("Frame"))
                        {

                            [void]$scriptCode.Add(("`t{0} = '{1}'{2}" -f $l.Name, [String]::Join("', '", $l.Value.ToArray()), $endDelimiter))

                        }

                        else
                        {

                            [void]$scriptCode.Add(("`t{0}{1}" -f $l.Value, $endDelimiter))
                        
                        }

                        $c++

                    }

                    [void]$scriptCode.Add('}')

                }
            
            }

            $addressPoolParam       = $null

            if ($enclosuretype -eq $SYN12K)
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enclosureCount' -Value ('{0}' -f $enclosureCount)))
                $enclosureCountParam    = ' -EnclosureCount $enclosureCount'

                #---- IP Address Pool
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ipV4AddressType' -Value ('"{0}"' -f $ipV4AddressType)))
                $addressPoolParam = ' -IPv4AddressType $ipV4AddressType'

                if($ipV4AddressType -eq 'IpPool')
                {

                    $RangeNames = [System.Collections.ArrayList]::new()

                    foreach ($uri in $ipRangeUris)
                    {

                        $rangeName          = Get-NamefromUri -Uri $uri
                        [void]$RangeNames.Add('{0}' -f $rangeName)
                    
                    }

                    $addressPoolParam += ' -addressPool $addressPool'
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'addressPoolNames' -Value ('"{0}"' -f [String]::Join('", "', $RangeNames.ToArray()))))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'addressPool' -Value ('$addressPoolNames | % { Get-HPOVAddressPoolRange | ? name -eq $_ }')))
                    
                }

            }

            # --- OS Deployment with IS
            $OSdeploymentParam           = $null

            if ($manageOSDeploy)
            {

                $OSdeploymentParam      = ' -DeploymentNetworkType $deploymentMode'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'deploymentMode' -Value ('"{0}"' -f $deploymentMode)))

                if ($deploymentMode -eq 'External')
                {

                    $deploynetworkname      = Get-NamefromUri -Uri $deploySettings.deploymentNetworkUri
                    $OSdeploymentParam     += ' -deploymentnetwork $deploymentnetwork'

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'deploynetworkname' -Value ('"{0}"' -f $deploynetworkname )))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'deploymentnetwork' -Value ('Get-HPOVnetwork -Name $deploynetworkname')))

                }

            }

            $powerModeParam = $null

            if ($null -ne $powerMode)
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'powerMode' -Value ('"{0}"' -f $powerMode)))
                $powerModeParam         = ' -PowerRedundantMode $powerMode'

            }

            # Get the EG configuration script to add as a parameter
            Try
            {
            
                $uri = $EG.uri + '/script'
                $egScript = Send-HPOVRequest -Uri $uri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $ConfigScriptParam = $null

            if ($null -ne $egScript)
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'confScript' -Value ("'{0}'" -f $egScript)))
                $ConfigScriptParam = ' -ConfigurationScript $confScript'

            }

            # Scopes
            Try
            {
            
                $ResourceScope = Send-HPOVRequest -Uri $scopesUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $n = 1
            
            $ScopeParam = $null

            if (-not [String]::IsNullOrEmpty($ResourceScope.scopeUris))
            {

                ForEach ($scopeUri in $ResourceScope.scopeUris)
                {

                    $scopeName = Get-NamefromUri -Uri $scopeUri

                    $ScopeVarName = 'Scope'
                    $Value = 'Get-HPOVScope -Name "{0}"' -f $scopeName

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $ScopeVarName -Suffix $n -Value $Value))

                    $n++

                }

                $ScopeParam = ' -Scope {0}' -f ([String]::Join(', ', (1..($n - 1) | ForEach-Object { '$Scope{0}' -f $_}))) 

            }

            [void]$scriptCode.Add(('New-HPOVEnclosureGroup -Name $name{0}{1}{2}{3}{4}{5}{6}' -f $enclosureCountParam, $liGMappingParam, $addressPoolParam, $OSdeploymentParam, $powerModeParam, $ConfigScriptParam, $ScopeParam))

            DisplayOutput -Code $scriptCode

        }

        Function Generate-LogicalEnclosure-Script ($InputObject)
        {
        
            $scriptCode =  [System.Collections.ArrayList]::new()

            $LE     = $InputObject

            $name          = $LE.name
            $enclUris      = $LE.enclosureUris
            $EncGroupUri   = $LE.enclosuregroupUri
            $FWbaselineUri = $LE.firmware.firmwareBaselineUri
            $FWinstall     = $LE.firmware.forceInstallFirmware
            $scopesUri     = $LE.scopesUri

            $EGName        = Get-NamefromUri -Uri $EncGroupUri
            $enclNames     = ($enclUris | ForEach-Object { Get-NamefromUri -Uri $_ })

            $egParam       = ' -EnclosureGroup $eg'
            $enclParam     = ' -Enclosure ($enclosures | Select -First 1)'

            [void]$scriptCode.Add('# -------------- Attributes for logical enclosure "{0}"' -f $name)
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$name' -Value ('"{0}"' -f $name)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$egName' -Value ('"{0}"' -f $egName)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$eg' -Value ('Get-HPOVEnclosureGroup -Name $egName')))      
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$enclNames' -Value ('"{0}"' -f [String]::Join('", "', $enclNames))))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$enclosures' -Value '$enclNames | % { Get-HPOVenclosure -Name $_ }'))
                
            $fwparam = $null
            
            if ($FWbaselineUri)
            {

                $fwName  = Get-NamefromUri -Uri $FWbaselineUri
                $fwparam = ' -FirmwareBaseline $fwBaseline -ForceFirmwareBaseline $fwInstall'

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwName' -Value ('"{0}"' -f $fwName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwBaseline' -Value 'Get-HPOVBaseline -SPPname $fwName'))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwInstall' -Value ('${0}' -f $fwInstall)))

            }

            # Scopes
            $ScopeParam = $null

            Try
            {
            
                $ResourceScope = Send-HPOVRequest -Uri $scopesUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $n = 1

            if (-not [String]::IsNullOrEmpty($ResourceScope.scopeUris))
            {

                ForEach ($scopeUri in $ResourceScope.scopeUris)
                {

                    $scopeName = Get-NamefromUri -Uri $scopeUri

                    $ScopeVarName = 'Scope'
                    $Value = 'Get-HPOVScope -Name "{0}"' -f $scopeName

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $ScopeVarName -Suffix $n -Value $Value))

                    $n++

                }

                $ScopeParam = ' -Scope {0}' -f ([String]::Join(', ', (1..($n - 1) | ForEach-Object { '$Scope{0}' -f $_}))) 

            }

            [void]$scriptCode.Add(('New-HPOVLogicalEnclosure -Name $name{0}{1}{2}{3}' -f $enclParam, $egParam, $fwParam, $ScopeParam))
        
            DisplayOutput -Code $scriptCode

        }

        Function Generate-ProfileTemplate-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()

            $Type = ($ResourceCategoryEnum.GetEnumerator() | Where-Object value -eq $InputObject.category).Name

            $name               = $InputObject.Name   
            $description        = $InputObject.Description 
            $spDescription      = $InputObject.serverprofileDescription
            $shtUri             = $InputObject.serverHardwareTypeUri
            $egUri              = $InputObject.enclosureGroupUri
            $sptUri             = $InputObject.serverProfileTemplateUri
            $serverUri          = $InputObject.serverHardwareUri
            $enclosureUri       = $InputObject.enclosureUri
            $enclosureBay       = $InputObject.enclosureBay
            $affinity           = $InputObject.affinity 
            $hideFlexNics       = $InputObject.hideUnusedFlexNics
            $macType            = $InputObject.macType
            $wwnType            = $InputObject.wwnType
            $snType             = $InputObject.serialNumberType       
            $iscsiType          = $InputObject.iscsiInitiatorNameType 
            $osdeploysetting    = $InputObject.osDeploymentSettings
            $scopesUri          = $InputObject.scopesUri

            [void]$scriptCode.Add(('# -------------- Attributes for {0} "{1}"' -f $Type, $name))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$name' -Value ('"{0}"' -f $name)))

            # Param and code
            Try
            {
            
                $sht     = Send-HPOVRequest -Uri $shtUri -Hostname $ApplianceConnection
                $shtName = $sht.name
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }
            
            # ------- Descriptions
            $descriptionParam   = $spdescriptionParam = $null
            
            if ($description)
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$description' -Value ('"{0}"' -f $description)))
                $descriptionParam = ' -Description $description'

            }

            if ($spdescription)
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$spdescription' -Value ('"{0}"' -f $spdescription)))
                $spdescriptionParam = ' -ServerProfileDescription $spdescription '
                
            }

            # ------- Server hardware assigned
            $serverAssignParam = $null

            if (-not [String]::IsNullOrWhiteSpace($serverUri))
            {

                $serverName = Get-NamefromUri -uri $serverUri

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$server' -Value ('Get-HPOVServer -Name "{0}"' -f $serverName)))

                $serverAssignParam += ' -AssignmentType Server -Server $server'

            }
            
            if (-not [String]::IsNullOrWhiteSpace($sptUri))
            {

                Try
                {

                    $spt = Send-HPOVRequest -Uri $sptUri -HostName $ApplianceConnection
                    $sptName = $spt.name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'sptName' -Value ('"{0}"' -f $sptName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'spt' -Value ('Get-HPOVServerProfileTemplate -Name "{0}"' -f $sptName)))

                $serverAssignParam += ' -ServerProfileTemplate $spt'
                
            }

            # -------- SHT and EG
            $shtParam = $egParam = $null

            if ([String]::IsNullOrWhiteSpace($serverUri))
            {

                if ($Type -eq 'ServerProfile' -and [String]::IsNullOrWhiteSpace($enclosureUri))
                {

                    $serverAssignParam += ' -AssignmentType Unassigned'

                }

                elseif ($Type -eq 'ServerProfile' -and -not [String]::IsNullOrWhiteSpace($enclosureUri) -and -not [String]::IsNullOrWhiteSpace($egUri))
                {

                    $enclosureName = Get-NamefromUri -uri $enclosureUri

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'enclosure' -Value ('Get-HPOVEnclosure -Name "{0}"' -f $enclosureName)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'bay' -Value $enclosureBay))
                    $serverAssignParam += ' -AssignmentType Bay -Enclosure $enclosure -Bay $bay' 

                }

                if ([String]::IsNullOrWhiteSpace($sptUri))
                {
                # ------- SHT
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$shtName' -Value ('"{0}"' -f $shtName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$sht' -Value 'Get-HPOVServerHardwareType -Name $shtName'))

                $shtParam = ' -ServerHardwareType $sht'

                # ------- EG, if BL or SY, and only needed if SPT or unassigned server profile
                if (-not [String]::IsNullOrWhiteSpace($egUri))
                {
            
                    Try
                    {
                
                        $eg = Send-HPOVRequest -Uri $egUri -Hostname $ApplianceConnection
                        $egName = $eg.name
                
                    }
                
                    Catch
                    {
                
                        $PSCmdlet.ThrowTerminatingError($_)
                
                    }

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$egName' -Value ('"{0}"' -f $egName)))
                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$eg' -Value 'Get-HPOVEnclosureGroup -Name $egName'))

                    $egParam = ' -EnclosureGroup $eg'
                    }
            
                }

            }
            # Need to not display specific settings of profile if SHT is assigned
            if ([String]::IsNullOrWhiteSpace($sptUri))
            {

            # ------- Affinity
            $affinityParam = $null

            if (-not [String]::IsNullOrWhiteSpace($affinity))
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$affinity' -Value ('"{0}"' -f $affinity)))

                $affinityParam = ' -Affinity $affinity'

            }

            # ------- Firmware
            $fwParam = $fwCode = $null

            $fw          = $InputObject.firmware
            $isFwManaged = $fw.manageFirmware

            if ($isFWmanaged)
            {

                $FwCode, $fwParam = Generate-ManageFirmware-Script -Fw $fw

                ForEach ($line in $FwCode.ToArray())
                {

                    [void]$scriptCode.Add($line)
                    }

                }
                
            }

            # ------- Network Connections
            $ConnectionsParam   = $null
            $ConnectionSettings = $InputObject.connectionSettings
            $ListofConnections  = $ConnectionSettings.connections
            $ConnectionVarNames = [System.Collections.ArrayList]::new()

            if ($ConnectionSettings.manageConnections -or $ListofConnections.Count -gt 0)
            {

                ForEach ($c in $ListofConnections)
                {

                    $conCode, $varstr = Generate-NetConnection-Script -Conn $c -MacAssignType $InputObject.macType -WwnAssignType $InputObject.wwnType

                    ForEach ($line in $conCode.ToArray())
                    {

                        [void]$scriptCode.Add($line)

                    }

                    [void]$ConnectionVarNames.Add($varstr)

                }

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$connections' -Value ([String]::Join(', ', $ConnectionVarNames.ToArray()))))
                
                $ConnectionsParam = ' -Connections $connections'
            
            }

            elseif (-not $ConnectionSettings.manageConnections)
            {
            
                $ConnectionsParam = ' -ManageConnections $False'
            
            }

            # ---------- OS Deployment Settings
            $osDeploymentParam = $null

            if (-not [String]::IsNullOrWhiteSpace($osdeploysetting.osDeploymentPlanUri))
            {

                [void]$scriptCode.Add('# -------------- Attributes for OS deployment settings')

                $osDeploymentParam = ' -OSDeploymentPlan $osDeploymentPlan -OSDeploymentPlanAttributes $CustomAttribs'

                $osDeployPlanUri = $osdeploysetting.osDeploymentPlanUri
                $planAttributes = $osdeploysetting.osCustomAttributes | Sort-Object Name

                $deployPlanName = Get-NamefromUri -Uri $osDeployPlanUri

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'planName' -Value ('"{0}"' -f $deployPlanName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'osDeploymentPlan' -Value 'Get-HPOVOsDeploymentPlan -Name $planName'))   
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'planAttribs' -Value 'Get-HPOVOsDeploymentPlanAttribute -InputObject $osDeploymentPlan'))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'CustomAttribs' -Value '@()'))
                
                ForEach ($attrib in $planAttributes)
                {

                    # Set value
                    if ($attrib.Name -match 'Password')
                    {

                        $value = 'Read-Host -AsSecureString -Prompt "Provide required password"'

                    }

                    else
                    {

                        $value = '"{0}"' -f $attrib.Value

                    }

                    [void]$scriptCode.Add(('($planAttribs | Where-Object name -eq "{0}").value = {1}' -f $attrib.Name, $value))

                    # Save into new array
                    [void]$scriptCode.Add(('$CustomAttribs += $planAttribs | Where-Object name -eq "{0}"' -f $attrib.Name))

                }

            }

            # ------- Local Storage
            $LOCALStorageParam = $null
            $ListofControllers                  = $InputObject.localStorage

            if ($ListofControllers.controllers.Count -gt 0)
            {

                $LOCALStorageCode, $vars      = Generate-LocalStorageController-Script -LocalStorageConfig $ListofControllers

                ForEach ($line in $LOCALStorageCode.ToArray())
                {

                    [void]$scriptCode.Add($line)

                }

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'controllers' -Value ('{0}' -f [String]::Join(', ', $vars.ToArray()))))
                
                $LOCALStorageParam              = ' -LocalStorage -StorageController $controllers'
                
            }

            # ---------- SAN storage
            $SANStorageParam = $null

            $SANStorageCfg  = $InputObject.SanStorage
            $ManagedStorage = $InputObject.SanStorage.manageSanStorage

            if ($ManagedStorage)
            {

                $hostOSType       = $ServerProfileSanManageOSType[$SANStorageCfg.hostOSType]
                $IsManagedSAN     = $SANStorageCfg.manageSanStorage
                $volumeAttachment = $SANStorageCfg.volumeAttachments

                [void]$scriptCode.Add('# -------------- Attributes for SAN Storage')
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'osType' -Value ('"{0}"' -f $hostOSType)))

                $SANStorageCode, $vars      = Generate-SANStorage-Script -SANStorageConfig $SANStorageCfg

                ForEach ($line in $SANStorageCode.ToArray())
                {

                    [void]$scriptCode.Add($line)

                }

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'volumeAttachments' -Value ('{0}' -f [String]::Join(', ', $vars.ToArray()))))
                
                $SANStorageParam              = ' -SanStorage -HostOsType $osType -StorageVolume $volumeAttachments'

            }

            # ---------- Boot Settings
            $bootManageParam = $null

            $bo                 = $InputObject.boot
            $isManageBoot       = $bo.manageBoot

            $bm                 = $InputObject.bootMode
            $isbootOrderManaged = $bm.manageMode
            
            $bootManageParam = ''

            if ($isManageBoot)
            {

                [void]$scriptCode.Add('# -------------- Attributes for BIOS Boot Mode settings')

                $bootMode       = $bm.mode
                $pxeBootPolicy  = $bm.pxeBootPolicy
                $secureBoot     = $bm.secureBoot

                # Set BIOS Boot Mode, PXE boot policy and secure boot
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'manageboot' -Value ('${0}' -f $isManageBoot)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'biosBootMode' -Value ('"{0}"' -f $bootMode)))

                    $bootManageParam += ' -ManageBoot:$manageboot -BootMode $biosBootMode'

                if (-not [String]::IsNullOrWhiteSpace($bootPXE))
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'pxeBootPolicy' -Value ('"{0}"' -f $pxeBootPolicy)))

                    $bootManageParam += ' -PxeBootPolicy $pxeBootPolicy'

                }

                if ($secureBoot -ne 'Unmanaged')
                {

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'secureBoot' -Value ('"{0}"' -f $secureBoot)))

                    $bootManageParam += ' -SecureBoot $secureBoot'

                }

            }

            if ($isbootOrderManaged)
            {

                [void]$scriptCode.Add('# -------------- Attributes for BIOS order settings')

                $bootOrder = '"{0}"' -f [String]::Join('", "', $bo.order)

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'bootOrder' -Value ('{0}' -f $bootOrder)))

                $bootManageParam += ' -BootOrder $bootOrder'

            }

            # ---------- BIOS Settings
            $biosParam = $null

            $bios = $InputObject.bios

            $isBiosManaged      = $bios.manageBios

            if ($isBiosManaged)
            {

                $biosParam = ' -Bios'

                $biosSettings   = $bios.overriddenSettings

                if ($biosSettings.Count -gt 0)
                {
                    [void]$scriptCode.Add('# -------------- Attributes for BIOS settings')

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'biosSettings' -Value ('@{0}' -f $OpenArray)))

                    $_b = 1

                    ForEach ($b in $biosSettings)
                    {

                        $endDelimiter = $Comma

                        if ($_b -eq $biosSettings.Count)
                        {

                            $endDelimiter = $null

                        }

                        [void]$scriptCode.Add(("`t@{0}id = '{1}'; value = '{2}'{3}{4}" -f $OpenDelim, $b.id, $b.value, $CloseDelim, $endDelimiter))

                        $_b++

                    }

                    [void]$scriptCode.Add($CloseArray)
                
                        $biosParam += ' -BiosSettings $biosSettings'

                }

            }

            # ---------- Advanced Settings
            $AdvancedSettingsParam    = $null
            $hideUnusedFlexNics       = $InputObject.hideUnusedFlexNics
            $macType                  = $InputObject.macType
            $wwnType                  = $InputObject.wwnType
            $serialNumberType         = $InputObject.serialNumberType
            $iscsiInitiatorNameType   = $InputObject.iscsiInitiatorNameType

            $AdvancedSettings = [System.Collections.ArrayList]::new()

            if ($hideFlexNics -and $sht.capabilities -contains 'VCConnections')
            {

                [void]$AdvancedSettings.Add('hideFlexNics')
                
            }

            if ($macType -ne 'Virtual' -and $sht.capabilities -contains 'VirtualMAC')
            {

                [void]$AdvancedSettings.Add('macType')

            }

            if ($wwnType -ne 'Virtual' -and $sht.capabilities -contains 'VirtualWWN')
            {

                [void]$AdvancedSettings.Add('wwnType')

            }

            if ($serialNumberType -ne 'Virtual' -and $sht.capabilities -contains 'VirtualUUID')
            {

                [void]$AdvancedSettings.Add('serialNumberType')

            }

            if ($iscsiInitiatorNameType -ne 'AutoGenerated' -and $sht.capabilities -contains 'VCConnections')
            {

                [void]$AdvancedSettings.Add('iscsiInitiatorNameType')

            }

            if ($AdvancedSettings.Count -gt 0)
            {

                [void]$scriptCode.Add('# -------------- Attributes for advanced settings')

                ForEach ($advSetting in $AdvancedSettings)
                {

                    switch ($advSetting)
                    {

                        'hideFlexNics'
                        {

                            $AdvancedSettingsParam += ' -HideUnusedFlexNics $true'

                        }

                        'macType'
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'macType' -Value ('"{0}"' -f $macType)))                            
                            $AdvancedSettingsParam += ' -MacAssignment $macType'

                        }

                        'wwnType'
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'wwnType' -Value ('"{0}"' -f $wwnType)))   
                            $AdvancedSettingsParam += ' -WwnAssignment $wwnType'

                        }

                        'serialNumberType'
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'serialNumberType' -Value ('"{0}"' -f $serialNumberType)))  
                            $AdvancedSettingsParam += ' -SnAssignment $serialNumberType'
                            
                        }

                        'iscsiInitiatorNameType'
                        {

                            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'iscsiInitiatorType' -Value ('"{0}"' -f $iscsiInitiatorNameType)))  
                            $AdvancedSettingsParam += ' -IscsiInitiatorNameAssignmet $iscsiInitiatorType'

                        }

                    }

                }

            }

            # Scopes
            $ScopeParam = $null

            Try
            {
            
                $ResourceScope = Send-HPOVRequest -Uri $scopesUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            $n = 1

            if (-not [String]::IsNullOrEmpty($ResourceScope.scopeUris))
            {

                ForEach ($scopeUri in $ResourceScope.scopeUris)
                {

                    $scopeName = Get-NamefromUri -Uri $scopeUri

                    $ScopeVarName = 'Scope'
                    $Value = 'Get-HPOVScope -Name "{0}"' -f $scopeName

                    [void]$scriptCode.Add((Generate-CustomVarCode -Prefix $ScopeVarName -Suffix $n -Value $Value))

                    $n++

                }

                $ScopeParam = ' -Scope {0}' -f ([String]::Join(', ', (1..($n - 1) | ForEach-Object { '$Scope{0}' -f $_}))) 

            }

            [void]$scriptCode.Add(('New-HPOV{0} -Name $name{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}' -f $Type, $descriptionParam, $spdescriptionParam, $serverAssignParam, $shtParam, $egParam, $affinityParam, $osDeploymentParam, $fwParam, $ConnectionsParam, $LOCALStorageParam, $SANStorageParam, $bootManageParam, $biosParam, $AdvancedSettingsParam, $ScopeParam))
        
            DisplayOutput -Code $scriptCode

        }
        
        Function Generate-osDeploymentServer-Script ($InputObject)
        {

            $scriptCode =  [System.Collections.ArrayList]::new()   

            foreach ($osds in $InputObject)
            {

                $name                       = $osds.name
                $description                = $osds.description
                $mgmtNetworkUri             = $osds.mgmtNetworkUri
                $primaryActiveApplianceUri  = $osds.primaryActiveAppliance

                Try
                {

                    $i3sAppliance               = Send-HPOVRequest -uri $primaryActiveApplianceUri

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                $i3sApplianceName           = $i3sAppliance.cimEnclosureName

                $mgmtNetworkName            = Get-NameFromUri -uri $mgmtNetworkUri
                
                [void]$scriptCode.Add(('# -------------- Attributes for OS Deployment Server {0}' -f $name))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'name' -Value ('"{0}"' -f $name)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ManagementNetwork' -Value ('Get-HPOVNetwork -Name "{0}" -Type Ethernet' -f $mgmtNetworkName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ImageStreamerApplianceName' -Value ('"{0}"' -f $i3sApplianceName)))
                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix 'ImageStreamerAppliance' -Value ('Get-HPOVImageStreamerAppliance | where cimEnclosurename -eq $ImageStreamerApplianceName')))
                
                $descriptionParam = ""

                if (-not [String]::IsNullOrWhiteSpace($description))
                {

                    [void]$scriptCode.Add((enerate-CustomVarCode -Prefix 'description' -Value ('"{0}"' -f $description)))
                    $descriptionParam       = ' -description $description'

                }

                [void]$scriptCode.Add(('New-HPOVOSDeploymentServer -Name $name -ManagementNetwork $ManagementNetwork -InputObject $ImageStreamerAppliance{0} ' -f $descriptionParam))
                
                DisplayOutput -Code $scriptCode

            }
            
        }

        # Internal helper
        Function Generate-ManageFirmware-Script
        {

            Param
            (

                $fw

            )

            $FwManagedCode = [System.Collections.ArrayList]::new()
            $FwParam       = $null

            $fwInstallType  = $fw.firmwareInstallType
            $fwForceInstall = $fw.forceInstallFirmware
            $fwActivation   = $fw.firmwareActivationType
            $fwSchedule     = $fw.firmwareScheduleDateTime
            $fwBaseUri      = $fw.firmwareBaselineUri

            $sppName  = Get-NamefromUri -Uri $fwBaseUri

            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$sppName' -Value ('"{0}"' -f $sppName)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwBaseline' -Value 'Get-HPOVbaseline -SPPname $sppName'))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwInstallType' -Value ('"{0}"' -f $fwInstallType)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwForceInstall' -Value ('${0}' -f $fwforceInstall)))
            [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwActivation' -Value ('"{0}"' -f $fwActivation)))

            $fwParam = ' -firmware -Baseline $fwbaseline -FirmwareInstallMode $fwInstallType -ForceInstallFirmware:$fwForceInstall -FirmwareActivationMode $fwActivation'

            if (-not [String]::IsNullOrEmpty($fwSchedule))
            {

                [void]$scriptCode.Add((Generate-CustomVarCode -Prefix '$fwSchedule' -Value ('"{0}"' -f $fwSchedule)))
                $FwParam += ' -FirmwareActivateDateTime $fwSchedule'

            }

            Return $FwManagedCode, $FwParam

        }

        # Internal helper
        Function Generate-NetConnection-Script 
        {

            Param 
            (
            
                $Conn,

                $MacAssignType,

                $WwnAssignType
                
            )

            $NetworkTypeEnum = @{

                'ethernet-networks' = 'Get-HPOVNetwork -Type Ethernet';
                'fc-networks'       = 'Get-HPOVNetwork -Type FibreChannel';
                'network-sets'      = 'Get-HPOVNetworkSet'

            }
            
            $ScriptConnection   = [System.Collections.ArrayList]::new()

            $connID             = $Conn.id
            $connName           = $Conn.name
            $ConnType           = $Conn.functionType
            $netUri             = $Conn.networkUri
            $portID             = $Conn.portID
            $requestedVFs       = $Conn.requestedVFs
            $bootSettings       = $Conn.boot

            $ConnectionVarName = '$Conn{0}' -f $connID

            Try
            {
            
                $thisNetwork = Send-HPOVRequest -Uri $netUri -Hostname $ApplianceConnection
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }                

            $netName        = $thisNetwork.name 

            [void]$ScriptConnection.Add('# -------------- Attributes for connection "{0}"' -f $connID)
            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$connID' -Value $ConnID))

            $connNameParam = $null

            if (-not [String]::IsNullOrWhiteSpace($connName))
            {

                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$connName' -Value ('"{0}"' -f $ConnName)))
                $connNameParam = ' -Name $connName'

            }

            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$connType' -Value ('"{0}"' -f $ConnType)))
            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$netName' -Value ('"{0}"' -f $netName)))
            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$ThisNetwork' -Value ('{0} -Name $netName' -f $NetworkTypeEnum[$thisNetwork.category])))  # Will return the correct Get-HPOV Cmdlet name and syntax
            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$portID' -Value ('"{0}"' -f $PortID)))
            
            $mac = $macParam = $null

            if ($MacAssignType -eq "UserDefined")
            {   

                $macParam      = ' -MacAssignment UserDefined'

                # Not sure why these replace statements are here.
                $mac           = $Conn.mac #-replace '[0-9a-f][0-9a-f](?!$)', '$&:'

                # Specific to handle SPT versus SP. SPT will not have a MAC address value within the connection
                if (-not [String]::IsNullOrWhiteSpace($mac))
                {

                    $macParam += ' -mac $mac'
                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$mac' -Value ('"{0}"' -f $mac)))

                }

            }
        
            $wwpn         = $wwnn = $wwwnParam = $null

            if ($WwnAssignType -eq "UserDefined")
            {   

                # Not sure why these replace statements are here.
                $mac      = $Conn.mac  #-replace '[0-9a-f][0-9a-f](?!$)', '$&:' # Format 10:00:11
                $wwpn     = $Conn.wwpn #-replace '[0-9a-f][0-9a-f](?!$)', '$&:'
                $wwnn     = $Conn.wwnn #-replace '[0-9a-f][0-9a-f](?!$)', '$&:'
                $wwnParam = ' -WwnAssignment UserDefined'

                if (-not [String]::IsNullOrWhiteSpace($wwpn))
                {

                    $wwnParam += ' -Wwpn $wwpn -Wwnn $wwnn'

                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$wwpn' -Value ('"{0}"' -f $wwpn)))
                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$wwnn' -Value ('"{0}"' -f $wwnn)))

                }
                
            }

            $requestedMbps      = $Conn.requestedMbps

            if ($null -eq $requestedMbps)
            {

                $requestedMbps = '"Auto"'
            
            }
            
            $allocatededMbps    = $Conn.allocatedMbps
            $maximumMbps        = $Conn.maximumMbps

            $mbpsParam = $mbpsCode = $null

            $mbpsParam          = ' -RequestedBW $requestedMbps'
            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$requestedMbps' -Value ('{0}' -f $requestedMbps)))

            # ---- lag
            $lagName  = $Conn.lagName

            $lagParam = $null

            if ($lagName)
            {

                $lagParam            = ' -LagName $lagName'
                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$lagName' -Value ('"{0}"' -f $lagName)))
                
            }

            #--- Virtual Functions
            $requestedVfsParam = $null

            if (($requestedVFs -gt 0 -or $requestedVFs -eq 'Auto') -and $bootSettings.ethernetBootType -ne 'iSCSI' -and $ConnType -ne 'iSCSI')
            {

                if ($requestedVFs -ne 'Auto')
                {

                    $requestedVFs = '"{0}"' -f $requestedVFs

                    $requestedVfsParam   = ' -Virtualfunctions $requestedVFs'
                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$requestedVFs' -Value ('{0}' -f $requestedVFs)))
                
                }
                    
            }

            $bootSettingsParam  = $bootTargetParam = $null
            
            $bootPriority       = $bootSettings.priority   
            $bootVolumeSource   = $bootSettings.bootVolumeSource

            if ($bootPriority -ne 'NotBootable')
            {

                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$bootPriority' -Value ('"{0}"' -f $bootPriority)))
                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$volSource' -Value ('"{0}"' -f $bootVolumeSource)))

                $bootSettingsParam = ' -Bootable -Priority $bootPriority -BootVolumeSource $volSource'

                if ($bootVolumeSource -eq 'UserDefined')
                {

                    switch ($ConnType)
                    {

                        'FibreChannel'
                        {

                            ForEach ($target in $bootSettings.targets)
                            {

                                $bootTarget = [regex]::Replace($target.arrayWwpn, '[0-9a-f][0-9a-f](?!$)', '$&:')
                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$bootTarget' -Value ('"{0}"' -f $bootTarget)))

                                $targetLun = $target.lun
                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$targeLun' -Value ('{0}' -f $targetLun)))

                                $bootTargetParam = ' -TargetWwpn $bootTarget -LUN $targetLun'

                            }
                            
                        }

                        # Both HW and SW iSCSI connection support
                        default
                        {

                            # Where address policy for connection resides
                            $ipv4Settings = $Conn.ipv4
                            $addressSource = $ipv4Settings.ipAddressSource
                            $IPv4address   = $ipv4Settings.address
                            $IPv4Subnet    = $ipv4Settings.subnetMask
                            $IPv4gateway   = $ipv4Settings.gateway

                            [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$addressSource' -Value ('"{0}"' -f $addressSource)))

                            $bootTargetParam = ' -IscsiIPv4AddressSource $addressSource'

                            if ($addressSource -eq 'UserDefined')
                            {

                                if (-not [String]::IsNullOrWhiteSpace($IPv4address))
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$IPv4address' -Value ('"{0}"' -f $IPv4address)))
                                
                                    $bootTargetParam += ' -IscsiIPv4Address $IPv4address'

                                }

                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$IPv4Subnet' -Value ('"{0}"' -f $IPv4Subnet)))
                                
                                $bootTargetParam += ' -IscsiIPv4SubnetMask $IPv4Subnet'

                                if (-not [String]::IsNullOrWhiteSpace($IPv4gateway))
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$IPv4gateway' -Value ('"{0}"' -f $IPv4gateway)))
                                
                                    $bootTargetParam += ' -IscsiIPv4Gateway $IPv4gateway'

                                }

                            }

                            # Where boot target and CHAP settings reside
                            $iSCSISettings        = $bootSettings.iscsi
                            $initiatorSource      = $iSCSISettings.initiatorNameSource
                            $initiatorName        = $iSCSISettings.initiatorName
                            $bootTargetIqn        = $iSCSISettings.bootTargetName
                            $bootTargetLun        = $iSCSISettings.bootTargetLun
                            $firstBootTargetIP    = $iSCSISettings.firstBootTargetIp
                            $firstBootTargetPort  = $iSCSISettings.firstBootTargetPort
                            $secondBootTargetIP   = $iSCSISettings.secondBootTargetIP
                            $secondBootTargetPort = $iSCSISettings.secondBootTargetPort
                            $chapLevel            = $iSCSISettings.chapLevel
                            $chapName             = $iSCSISettings.chapName
                            $mutualChapName       = $iSCSISettings.mutualChapName

                            # Initiator Name
                            if (-not [String]::IsNullOrWhiteSpace($initiatorName) -and $initiatorSource -eq 'UserDefined')
                            {

                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$profileInitiatorName' -Value ('"{0}"' -f $initiatorName)))
                                
                                $bootTargetParam += ' -ISCSIInitatorName $profileInitiatorName'

                            }

                            # Target IQN and LUN
                            if (-not [String]::IsNullOrWhiteSpace($bootTargetIqn))
                            {

                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$bootTargetIqn' -Value ('"{0}"' -f $bootTargetIqn)))
                                
                                $bootTargetParam += ' -IscsiBootTargetIqn $bootTargetIqn'

                                if (-not [String]::IsNullOrWhiteSpace($bootTargetLun))
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$bootTargetLun' -Value ('"{0}"' -f $bootTargetLun)))
                                
                                    $bootTargetParam += ' -LUN $bootTargetLun'

                                }

                            }

                            # First boot target IP
                            if (-not [String]::IsNullOrWhiteSpace($firstBootTargetIP))
                            {

                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$firstBootTargetIP' -Value ('"{0}"' -f $firstBootTargetIP)))
                                
                                $bootTargetParam += ' -IscsiPrimaryBootTargetAddress $firstBootTargetIP'

                                if ($firstBootTargetPort -ne 3260)
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$firstBootTargetPort' -Value ('{0}' -f $firstBootTargetPort)))
                                
                                    $bootTargetParam += ' -IscsiPrimaryBootTargetPort $firstBootTargetPort'

                                }

                            }

                            # Second boot target IP
                            if (-not [String]::IsNullOrWhiteSpace($secondBootTargetIP))
                            {

                                [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$secondBootTargetIP' -Value ('"{0}"' -f $secondBootTargetIP)))
                                
                                $bootTargetParam += ' -IscsiSecondaryBootTargetAddress $secondBootTargetIP'

                                if ($firstBootTargetPort -ne 3260)
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$secondBootTargetPort' -Value ('{0}' -f $secondBootTargetPort)))
                                
                                    $bootTargetParam += ' -IscsiSecondaryBootTargetPort $secondBootTargetPort'

                                }

                            }

                            # CHAP settings
                            if ($chapLevel -ne 'None')
                            {

                                # Only needed for SPT
                                if (-not [String]::IsNullOrWhiteSpace($chapName))
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$chapName' -Value ('"{0}"' -f $chapName)))

                                    $bootTargetParam += ' -ChapName $chapName'

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$chapSecret' -Value 'Read-Host -AsSecureString -Prompt "Provide CHAP password"'))

                                    $bootTargetParam += ' -ChapSecret $chapSecret'

                                }

                                # Needed for SPT or if not MutualChap policy
                                if (-not [String]::IsNullOrWhiteSpace($mutualChapName))
                                {

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$mutualChapName' -Value ('"{0}"' -f $mutualChapName)))

                                    $bootTargetParam += ' -MutualChapName $mutualChapName'

                                    [void]$ScriptConnection.Add((Generate-CustomVarCode -Prefix '$mutualChapSecret' -Value 'Read-Host -AsSecureString -Prompt "Provide mutual CHAP password"'))

                                    $bootTargetParam += ' -MutualChapSecret $mutualChapSecret'

                                }

                            }

                        }

                    }
                    
                }

            }

            $Value = 'New-HPOVServerProfileConnection -ConnectionID $connID{0} -ConnectionType $connType -Network $ThisNetwork -PortId $portID{1}{2}{3}{4}{5}{6}{7}' -f $connNameParam, $macParm, $wwnParam, $requestedVFsParam, $mbpsParam, $lagParam, $bootSettingsParam, $bootTargetParam
            $Cmd = Generate-CustomVarCode -Prefix $ConnectionVarName -Value $Value
        
            [void]$ScriptConnection.Add($Cmd)

            Return $ScriptConnection, $ConnectionVarName

        }

        # Internal helper
        Function Generate-LocalStorageController-Script 
        {

            Param 
            ( 
                
                $LocalStorageConfig
            
            )

            $LDAcceleratorEnum = @{

                ControllerCache = 'Enabled';
                IOBypass        = 'SsdSmartPath';
                None            = 'Disabled';
                Unmanaged       = 'Unmanaged'

            }

            $ScriptController        = [System.Collections.ArrayList]::new()
            $ControllerVarNames      = [System.Collections.ArrayList]::new()

            $SasLogicalJBODs = $LocalStorageConfig.sasLogicalJBODs

            $c = 1
            $l = 1  # Needed here so that LogicalDiskVarName num doesn't overlap with other controllers present with their own logical disks

            ForEach ($controller in $LocalStorageConfig.controllers)
            {

                $LogicalDiskVarNames = [System.Collections.ArrayList]::new()

                $deviceSlot    = $controller.deviceSlot
                $mode          = $controller.mode
                $initialize    = $controller.initialize
                $writeCache    = $controller.driveWriteCache
                $importCfg     = $controller.importConfiguration
                $logicalDrives = $controller.logicalDrives

                $ControllerVarName = '$controller{0}' -f $c

                [void]$ControllerVarNames.Add($ControllerVarName)

                if ($importCfg)
                {

                    $importCfgParam = ' -ImportExistingConfiguration'

                }

                else
                {
                
                    ForEach ($ld in $logicalDrives)
                    {

                        $writeCacheParam = $initializeParam = $importCfgParam = $LogicalDisksParam = $null

                        $LogicalDiskVarName = '$LogicalDisk{0}' -f $l

                        [void]$LogicalDiskVarNames.Add($LogicalDiskVarName)

                        $name             = $ld.name
                        $RaidLevel        = $ld.raidLevel
                        $bootable         = $ld.bootable
                        $numPhysDrives    = $ld.numPhysicalDrives
                        $driveTech        = if ([String]::IsNullOrWhiteSpace($ld.driveTechnology)) { 'Auto' } else { $LogicalDiskCmdletTypeEnum[$ld.driveTechnology] }
                        $accelerator      = $ld.accelerator
                        $sasLogicalJbodId = $ld.sasLogicalJBODId
                        $sasLogicalJbod   = $SasLogicalJBODs | Where-Object { $_.deviceSlot -eq $deviceSlot -and $_.id -eq $sasLogicalJbodId }

                        # Look for immediate attached disks, not D3940
                        if (-not [String]::IsNullOrEmpty($name) -and [String]::IsNullOrEmpty($sasLogicalJbodId))
                        {

                            if ($null -eq $driveTech)
                            {

                                $driveTech = 'Auto'

                            }

                            [void]$ScriptController.Add(('# -------------- Attributes for logical disk "{0}({1})"' -f $name, $RaidLevel))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "ldName" -Value ('"{0}"' -f $name)))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "raidLevel" -Value ('"{0}"' -f $RaidLevel)))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "numPhysDrives" -Value ('{0}' -f $numPhysDrives)))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "driveTech" -Value ('"{0}"' -f $driveTech)))

                            $LogicalDiskParams = ' -Raid $raidLevel -NumberofDrives $numPhysDrives -DriveType $driveTech'

                            if ($bootable)
                            {

                                $LogicalDiskParams += ' -Bootable $True'

                            }

                            if ($accelerator -ne 'Unmanaged')
                            {

                                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "accelerator" -Value ('"{0}"' -f $LDAcceleratorEnum[$accelerator])))

                                $LogicalDiskParams += ' -Accelerator $accelerator'

                            }

                            # Internal drive configuration, so use -StorageLocation Internal
                            if ($deviceSlot -match 'Mezz')
                            {

                                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "location" -Value 'Internal'))

                                $LogicalDiskParams += ' -StorageLocation $location'

                            }

                        }

                        # Synergy D3940 RAID disks
                        else
                        {

                            $sasLJBODName          = $sasLogicalJbod.name
                            $sasLJBODNumPhysDrives = $sasLogicalJbod.numPhysicalDrives
                            $sasLJBODMinDriveSize  = $sasLogicalJbod.driveMinSizeGB
                            $sasLJBODMaxDriveSize  = $sasLogicalJbod.driveMaxSizeGB
                            $sasLJBODdriveTech     = if ([String]::IsNullOrWhiteSpace($sasLogicalJbod.driveTechnology)) { 'Auto' } else { $LogicalDiskCmdletTypeEnum[$sasLogicalJbod.driveTechnology] }
                            $sasLJBODeraseData     = $sasLogicalJbod.eraseData
                    
                            [void]$ScriptController.Add(('# -------------- Attributes for RAID logical JBOD "{0}" ({1})' -f $sasLJBODName, $deviceSlot))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "ldname" -Value ('"{0}"' -f $sasLJBODName)))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "numPhysDrives" -Value ('{0}' -f $sasLJBODNumPhysDrives)))

                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "minDriveSize" -Value ('{0}' -f $sasLJBODMinDriveSize)))
                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "maxDriveSize" -Value ('{0}' -f $sasLJBODMaxDriveSize)))
                             [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "driveTech" -Value ('"{0}"' -f $sasLJBODdriveTech)))
                        
                             $LogicalDiskParams += ' -MinDriveSize $minDriveSize -MaxDriveSize $maxDriveSize -DriveType $driveTech'

                            if ($sasLJBODeraseData)
                            {

                                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "eraseDataOnDelete" -Value ('${0}' -f $sasLJBODeraseData)))

                                $LogicalDiskParams += ' -EraseDataOnDelete $eraseDataOnDelete' 

                            }
                        
                        }

                        $Value = 'New-HPOVServerProfileLogicalDisk -Name $ldName{0}' -f $LogicalDiskParams
                        $Cmd = Generate-CustomVarCode -Prefix $LogicalDiskVarName -Value $Value
    
                        [void]$ScriptController.Add($Cmd)

                        $l++

                    }
                    
                    # Exclusively for D3940 Logical JBOD within the controller
                    ForEach ($sasJBOD in ($SasLogicalJBODs | Where-Object deviceSlot -eq $deviceSlot))
                    {

                        $LogicalDiskParams = $null

                        $LogicalDiskVarName = '$LogicalDisk{0}' -f $l

                                    [void]$LogicalDiskVarNames.Add($LogicalDiskVarName)

                        $sasLJBODName          = $sasJBOD.name
                        $sasLJBODNumPhysDrives = $sasJBOD.numPhysicalDrives
                        $sasLJBODMinDriveSize  = $sasJBOD.driveMinSizeGB
                        $sasLJBODMaxDriveSize  = $sasJBOD.driveMaxSizeGB
                        $sasLJBODdriveTech     = $LogicalDiskCmdletTypeEnum[$sasJBOD.driveTechnology]
                        $sasLJBODeraseData     = $sasJBOD.eraseData

                        [void]$ScriptController.Add(('# -------------- Attributes for logical JBOD "{0}" ({1})' -f $sasLJBODName, $deviceSlot))
                        [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "ldname" -Value ('"{0}"' -f $sasLJBODName)))
                        [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "numPhysDrives" -Value ('{0}' -f $sasLJBODNumPhysDrives)))

                        [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "minDriveSize" -Value ('{0}' -f $sasLJBODMinDriveSize)))
                        [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "maxDriveSize" -Value ('{0}' -f $sasLJBODMaxDriveSize)))
                        [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "driveTech" -Value ('"{0}"' -f $sasLJBODdriveTech)))
                                    
                        $LogicalDiskParams += ' -MinDriveSize $minDriveSize -MaxDriveSize $maxDriveSize -DriveType $driveTech'

                        if ($sasLJBODeraseData)
                        {

                            [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "eraseDataOnDelete" -Value ('${0}' -f $sasLJBODeraseData)))

                            $LogicalDiskParams += ' -EraseDataOnDelete $eraseDataOnDelete' 

                        }

                        $Value = 'New-HPOVServerProfileLogicalDisk -Name $ldName{0}' -f $LogicalDiskParams
                        $Cmd = Generate-CustomVarCode -Prefix $LogicalDiskVarName -Value $Value
    
                        [void]$ScriptController.Add($Cmd)

                        $l++

                    }
                                
                }
                
                [void]$ScriptController.Add(('# -------------- Attributes for controller "{0}" ({1})' -f $deviceSlot, $mode))
                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "deviceSlot" -Value ('"{0}"' -f $deviceSlot)))
                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "controllerMode" -Value ('"{0}"' -f $mode)))
                            
                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "LogicalDisks" -Value ('{0}' -f [String]::Join(', ', $LogicalDiskVarNames.ToArray()))))

                $LogicalDisksParam = ' -LogicalDisk $LogicalDisks'

                if ($writeCache -ne 'Unmanaged' -and -not [String]::IsNullOrEmpty($writeCache))
                {

                [void]$ScriptController.Add((Generate-CustomVarCode -Prefix "writeCache" -Value ('"{0}"' -f $writeCache)))
                $writeCacheParam = ' -WriteCache $writeCache'

            }

            if ($initialize)
            {

                $initializeParam = ' -Initialize'

            }


            $Value = 'New-HPOVServerProfileLogicalDiskController -ControllerID $deviceSlot -Mode $controllerMode{0}{1}{2}{3}' -f $writeCacheParam, $initializeParam, $importCfgParam, $LogicalDisksParam
            $Cmd = Generate-CustomVarCode -Prefix $ControllerVarName -Value $Value
            
            [void]$ScriptController.Add($Cmd)

            $c++                

            }
            
            Return $ScriptController, $ControllerVarNames

        }

        # Internal helper
        Function Generate-SANStorage-Script  
        {

            Param 
            ( 
                
                $SANStorageConfig

            )

            $SanStorageCode    = [System.Collections.ArrayList]::new()
            $VolAttachVarNames = [System.Collections.ArrayList]::new()

            $IsManagedSAN       = $SANStorageConfig.manageSanStorage
            $volumeAttachment   = $SANStorageConfig.volumeAttachments

            $_v = 1

            $volIdParam = $lunParam = $lunTypeParam = $null

            foreach ($vol in $volumeAttachment)
            {

                $lunParam = $volumeParam = $null

                $VarName = '$volume{0}' -f $_v

                [void]$VolAttachVarNames.Add($VarName)

                $volID              = $vol.id
                $isBootVolume       = if ($vol.bootVolumePriority -eq 'Bootable') { $True } else { $False }
                $lunType            = $vol.lunType

                # Lets see if volume name can be added here. If existing vol, volume name is not present in attachment, need to get volume from volumeUri
                [void]$SanStorageCode.Add('# ----------- SAN volume attributes for volume ID "{0}"' -f $volID)
                [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'volId' -Value ('{0}' -f $volID)))
                [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'lunIdType' -Value ('"{0}"' -f $lunType)))
                $lunParam       = ' -VolumeID $volId -LunIDType $lunIdType'

                if ($lunType -ne 'Auto')
                {

                    $lunID          = $vol.lun

                    [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'lunID' -Value ('{0}' -f $lunID)))
                    $lunParam       += ' -lunID $lunID'

                }

                # Perminent storage vol
                if (-not [String]::IsNullOrWhiteSpace($vol.volumeUri))
                {

                    Try
                    {
                    
                        $volAttachment = Send-HPOVRequest -Uri $vol.volumeUri -Hostname $ApplianceConnection
                    
                    }
                    
                    Catch
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }

                    $volName           = $volProperty.name

                    [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'volName' -Value ('"{0}"' -f $volName)))
                    [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix $VarName -Value 'Get-HPOVStorageVolume -Name $volName'))

                    $volumeParam = ' -Volume {0}' -f $VarName

                }

                # Dynamic private volume
                else
                {
                
                    # Common ephemeral volume settings
                    $volProperty      = $vol.volume.properties
                    $isPermanent      = $vol.volume.isPermanent
                    $name             = $volProperty.name
                    $size             = $volProperty.size / 1GB
                    $isDeduplicated   = $volProperty.isDeduplicated
                    $ProvisioningType = $volProperty.provisioningType
                    $storagePoolUri   = $volProperty.storagePool
                    
                    $templateUri      = $vol.volume.templateUri 

                    [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'volName' -Value ('"{0}"' -f $name)))
                    $volumeParam = ' -Name $volName'

                    Try
                    {
                    
                        $template = Send-HPOVRequest -Uri $templateUri -Hostname $ApplianceConnection
                    
                    }
                    
                    Catch
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }

                    $isRoot = $template.isRoot

                    # Administrator SVT, not storage system SVT
                    if (-not $isRoot)
                    {

                        $volTemplateName = $template.name

                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'volTemplateName' -Value ('"{0}"' -f $volTemplateName)))
                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'volumeTemplate' -Value 'Get-HPOVStorageVolumeTemplate -Name $volTemplateName'))

                        $volumeParam += ' -VolumeTemplate $volumeTemplate'
                        
                    }

                    # Ephemeral volume with parameters
                    else 
                    {

                        # Get storage pool object
                        Try
                        {
                        
                            $storagePool   = Send-HPOVRequest -Uri $storagePoolUri -Hostname $ApplianceConnection
                            $storageSystem = Send-HPOVRequest -Uri $storagePool.storageSystemUri -Hostname $ApplianceConnection
                        
                        }
                        
                        Catch
                        {
                        
                            $PSCmdlet.ThrowTerminatingError($_)
                        
                        }

                        $storagePoolName = $storagePool.name

                        # Get storage system name from pool
                        $storageSystemName = $storageSystem.name

                        $volTemplateParam = $volTemplateCode = $null

                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'capacity' -Value ('{0}' -f $size)))
                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'ProvisioningType' -Value ('"{0}"' -f $ProvisioningType)))
                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'storagePoolName' -Value ('"{0}"' -f $storagePoolName)))
                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'storageSystemName' -Value ('"{0}"' -f $storageSystemName)))
                        [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'storagePool' -Value 'Get-HPOVStoragePool -Name $storagePoolName -StorageSystem $storageSystemName'))

                        $volumeParam += ' -Capacity $capacity -ProvisioningType $ProvisioningType -StoragePool $storagePool'

                        switch ($storageSystem.family)
                        {

                            'StoreServ'
                            {

                                $snapshotStoragePoolUri = $volProperty.snapshotPool

                                if ($snapshotStoragePoolUri -ne $storagePoolUri)
                                {

                                    # Get snapshot storage pool object
                                    Try
                                    {
                        
                                        $snapshotStoragePool = Send-HPOVRequest -Uri $snapshotStoragePoolUri -Hostname $ApplianceConnection
                        
                                    }
                        
                                    Catch
                                    {
                        
                                        $PSCmdlet.ThrowTerminatingError($_)
                        
                                    }

                                    [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'snapshotPoolName' -Value ('"{0}"' -f $snapshotStoragePool.name)))
                                    [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'snapshotStoragePool' -Value 'Get-HPOVStoragePool -Name $snapshotPoolName -StorageSystem $storageSystemName'))

                                    $volumeParam += ' -SnapshotStoragePool $snapshotStoragePool'

                                }

                            }

                            'StoreVirtual'
                            {

                                $dataProtectionLevel = $volProperty.dataProtectionLevel
                                $isAOEnabled         = $volProperty.isAdaptiveOptimizationEnabled

                                [void]$SanStorageCode.Add((Generate-CustomVarCode -Prefix 'dataProtectionLevel' -Value ('"{0}"' -f $dataProtectionLevel)))

                                $volumeParam += ' -DataProtectionLevel $dataProtectionLevel'

                                if ($isAOEnabled)
                                {

                                    $volumeParam += ' -EnableAdaptiveOptimization'
                    
                                }    

                            }

                        }

                    }

                    Write-Host "isPermanent: " $isPermanent
                    if ($isPermanent)
                    {

                        $volumeParam += ' -Permanent'

                    }

                    $_v++
                
                }
                
                $Value = 'New-HPOVServerProfileAttachVolume{0}{1}{2}' -f $lunParam, $volumeParam, $null
                
                $Cmd = Generate-CustomVarCode -Prefix $VarName -Value $Value
        
                [void]$SanStorageCode.Add($Cmd)

            }

            return $SanStorageCode, $VolAttachVarNames

        }

        switch ($InputObject.GetType().FullName)
        {

            {$_ -match 'HPOneView.Appliance.Baseline'}
            {

                Generate-fwBaseline-Script              -InputObject $InputObject

            }

            'HPOneView.Appliance.ProxyServer'
            {

                Generate-proxy-Script                   -InputObject $InputObject 

            }

            'HPOneView.Appliance.ScopeCollection'
            {

                Generate-Scope-Script                   -InputObject $InputObject

            }

            'HPOneView.Appliance.SnmpReadCommunity'
            {
                
                Generate-Snmp-Script                    -InputObject $InputObject

            }

            'HPOneView.Appliance.SnmpV3User'
            {

                Generate-snmpV3User-Script              -InputObject $InputObject

            }

            'HPOneView.Appliance.ApplianceLocaleDateTime'
            {

                Generate-TimeLocale-Script              -InputObject $InputObject

            }

            'HPOneView.Storage.StoragePool'
            {

                Generate-StoragePool-Script             -InputObject $InputObject

            }

            default
            {

                switch ($InputObject.type)
                {

                    'EmailNotificationV3'
                    {

                        Generate-smtp-Script              -InputObject $InputObject

                    }

                    'Subnet'
                    {

                        Generate-AddressPoolSubnet-Script -InputObject $InputObject

                    }

                    'Range'
                    {

                        Generate-AddressPoolRange-Script  -InputObject $InputObject

                    }

                    {$_ -match 'ethernet-network'}
                    {

                        Generate-EthernetNetwork-Script   -InputObject $InputObject

                    }

                    {$_ -match 'network-set'}
                    {

                        Generate-NetworkSet-Script   -InputObject $InputObject

                    }

                    {$_ -match 'fcoe-network' -or $_ -match 'fc-network'}
                    {

                        Generate-FCNetwork-Script         -InputObject $InputObject

                    }

                    {$_ -match 'FCDeviceManager'}
                    {

                        Generate-SanManager-Script        -InputObject $InputObject

                    }

                    {$_ -match 'StorageSystem'}
                    {

                        Generate-StorageSystem-Script         -InputObject $InputObject

                    }

                    {$_ -match 'StorageVolumeTemplate'}
                    {

                        Generate-StorageVolumeTemplate-Script -InputObject $InputObject; Break

                    }

                    {$_ -match 'StorageVolume'}
                    {

                        Generate-StorageVolume-Script -InputObject $InputObject; Break

                    }

                    {$_ -match 'UserAndPermissions'}
                    {

                        Generate-User-Script -InputObject $InputObject

                    }

                    {$_ -match 'LoginDomainGroupPermission'}
                    {

                        Generate-RBAC-Script -InputObject $InputObject

                    }

                    {$_ -match 'LoginDomainConfig'}
                    {

                        Generate-DirectoryAuthentication-Script  -InputObject $InputObject

                    }

                    # {$_ -match 'Configuration'}
                    # {

                    # Generate-RemoteSupport-Script -InputObject $InputObject

                    # }

                    {$_ -match 'logical-interconnect-group'}
                    {

                        Generate-LogicalInterConnectGroup-Script -InputObject $InputObject

                    }

                    {$_ -match 'enclosure'}
                    {
                        
                        switch ($InputObject.category)
                        {

                            'enclosure-groups'
                            {

                                Generate-EnclosureGroup-Script           -InputObject $InputObject

                            }

                            'logical-enclosures'
                            {

                                if (($ConnectedSessions | Where-Object Name -eq $InputObject.ApplianceConnection.Name).ApplianceType -ne 'Composer')
                                {
                                    
                                    $ErrorRecord = New-Object Management.Automation.ErrorRecord (New-Object HPOneview.Appliance.ComposerNodeException ('The ApplianceConnection {0} is not a Synergy Composer. The logical enclosure resource and this Cmdlet is only supported with Synergy Composers.' -f $ApplianceConnection)), 'InvalidOperation', 'InvalidOperation', 'ApplianceConnection'

                                    $PSCmdlet.WriteError($ErrorRecord)

                                }

                                else
                                {
                                
                                    Generate-LogicalEnclosure-Script         -InputObject $InputObject
                                
                                }

                            }

                            default
                            {

                                if ($InputObject.enclosureType -eq 'C7000')
                                {

                                    Try
                                    {
                        
                                        $EnclosureGroup = Send-HPOVRequest -Uri $InputObject.enclosureGroupUri -Hostname $ApplianceConnection
                        
                                    }
                        
                                    Catch
                                    {
                        
                                        $PSCmdlet.ThrowTerminatingError($_)
                        
                                    }

                                    Generate-EnclosureGroup-Script           -InputObject $EnclosureGroup

                                }

                                else
                                {
                        
                                    Try
                                    {
                        
                                        $LogicalEnclosure = Send-HPOVRequest -Uri $InputObject.logicalEnclosureUri -Hostname $ApplianceConnection
                        
                                    }
                        
                                    Catch
                                    {
                        
                                        $PSCmdlet.ThrowTerminatingError($_)
                        
                                    }

                                    Generate-LogicalEnclosure-Script         -InputObject $LogicalEnclosure
                        
                                }

                            }

                        }

                        break

                    }

                    {$_ -match 'server'}
                    {

                        switch ($InputObject.category)
                        {

                            'server-profiles'
                            {

                                Generate-ProfileTemplate-Script -InputObject $InputObject
                                
                            }

                            'server-profile-templates'
                            {

                                Generate-ProfileTemplate-Script -InputObject $InputObject

                            }

                            # Generate Profile script code
                            'server-hardware'
                            {

                                Try
                                {
                                
                                    $ServerProfile = Send-HPOVRequest -Uri $InputObject.serverProfileUri -Hostname $ApplianceConnection
                                
                                }
                                
                                Catch
                                {
                                
                                    $PSCmdlet.ThrowTerminatingError($_)
                                
                                }

                                # If a template is associated, get template code first
                                if ($null -ne $ServerProfile.serverProfileTemplateUri)
                                {

                                    Try
                                    {
                                    
                                        $ServerProfileTemplate = Send-HPOVRequest -Uri $ServerProfile.serverProfileTemplateUri -Hostname $ApplianceConnection
                                    
                                    }
                                    
                                    Catch
                                    {
                                    
                                        $PSCmdlet.ThrowTerminatingError($_)
                                    
                                    }

                                    Generate-ProfileTemplate-Script -InputObject $ServerProfileTemplate

                                }

                                Generate-Profile-Script -InputObject $ServerProfile

                            }

                        }
                        
                    }
                    
                    'DeploymentManager'
                    {

                        Generate-osDeploymentServer-Script -InputObject $InputObject

                    }

                    default
                    {

                        $ExceptionMessage = 'The "{0}" resource category for "{1}" is currently not supported. ' -f $InputObject.type, $InputObject.name
                        $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage

                        $PSCmdlet.WriteError($ErrorRecord)

                    }

                }

            }

        }   

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Appliance Configuration:
#

function Get-HPOVApplianceAuditLogForwarding
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.AuditLogForwardingConfig[]])]
    Param 
    (
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $_Uri = $ApplianceAuditLogForwardingUri

        ForEach ($_appliance in $ApplianceConnection)
        {

            Try
            {

                $_CurrentConfig = Send-HPOVRequest -Uri $_Uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_Destinations = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.Destination]'

            ForEach ($_Dest in $_CurrentConfig.remoteDestinations)
            {

                $_NewDestination = New-Object HPOneView.Appliance.Destination($_Dest.remoteDestination, $_Dest.remotePort)

                [void]$_Destinations.Add($_NewDestination)

            }

            New-Object HPOneView.Appliance.AuditLogForwardingConfig($_CurrentConfig.forwardingEnabled,
                                                                    $_Destinations,
                                                                    $_CurrentConfig.ApplianceConnection)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }
    
}

function Set-HPOVApplianceAuditLogForwarding
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.AuditLogForwardingConfig[]])]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Enable,
        
        [Parameter (Mandatory, ParameterSetName = 'Disable')]
        [Switch]$Disable,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String[]]$ComputerName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Int]$Port = 514,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String[]]$RemoveComputerName,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $_Uri = $ApplianceAuditLogForwardingUri

        ForEach ($_appliance in $ApplianceConnection)
        {

            # Get the current configuration
            Try
            {

                $_CurrentConfig = Send-HPOVRequest -Uri $_Uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Disable'])
            {

                "[{0}] Will disable forwarding." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_CurrentConfig.forwardingEnabled = $false

            }

            else
            {

                if ($PSBoundParameters['Enable'])
                {

                    "[{0}] Will enable forwarding." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_CurrentConfig.forwardingEnabled = $True

                }

                # Rebuild remoteDestinations as an ArrayList
                $_OriginalDestinations = $_CurrentConfig.remoteDestinations.Clone()
                $_CurrentConfig.remoteDestinations = [System.Collections.ArrayList]::new()

                ForEach ($_Dest in $_OriginalDestinations)
                {

                    [void]$_CurrentConfig.remoteDestinations.Add($_Dest)

                }

                # Add the $ComputerName to the destinations
                # Use Port if $Computername does not follow "ServerName:PORT" format
                ForEach ($_NewDest in $ComputerName)
                {

                    if ($ComputerName.Contains(':'))
                    {

                        $_Target = $_NewDest.Split(':')[0]
                        $_Port = $_NewDest.Split(':')[1]

                    }

                    else
                    {

                        $_Target = $_NewDest
                        $_Port = $Port

                    }

                    if ($_CurrentConfig.remoteDestinations.remoteDestination -NotContains $_Target)
                    {

                        "[{0}] Adding '{1}:{2}' to the remoteDestinations collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Target, $_Port | Write-Verbose

                        [void]$_CurrentConfig.remoteDestinations.Add(@{remoteDestination = $_Target; remotePort = $_Port})

                    }

                    elseif ($_CurrentConfig.remoteDestinations.remoteDestination -Contains $_Target -and ($_CurrentConfig.remoteDestinations | ? remoteDestination -eq $_Target).remotePort -ne $_Port)
                    {

                        "[{0}] Updating '{1}' to new port '{2}' ." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Target, $_Port | Write-Verbose

                    }

                }

                # Process RemoveComputerName value
                ForEach ($_RemoveDest in $RemoveComputerName)
                {

                    if ($_DestToRemove = $_CurrentConfig.remoteDestinations | ? remoteDestination -eq $_RemoveDest)
                    {

                        "[{0}] Removing '{1}:{2}' from the remoteDestinations collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DestToRemove.remoteDestination, $_DestToRemove.remotePort | Write-Verbose

                        [void]$_CurrentConfig.remoteDestinations.Remove($_DestToRemove)

                    }

                    else
                    {

                        "[{0}] Host '{1}' not found in collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_RemoveDest | Write-Verbose

                    }

                }

            }

            

            # Save config
            Try
            {

                Send-HPOVRequest -Uri $_Uri -Method PUT -Body $_CurrentConfig -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }
    
}
    
function Test-HPOVApplianceAuditLogForwarding
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            Try
            {

                Send-HPOVRequest -Uri $ApplianceTestAuditLogForwardingUri -Method POST -ApplianceConnection $_appliance
            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceCertificateStatus 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose
            
            Try
            {

                $_status = Send-HPOVRequest $applianceSslCert -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_status.PSObject.TypeNames.insert(0,'HPOneView.Appliance.ApplianceSslCertificateStatus')

            $_status

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVApplianceSelfSignedCertificate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]

    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('C')]
        [ValidateNotNullOrEmpty()]
        [String]$Country,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('ST','Province')]
        [ValidateNotNullOrEmpty()]    
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('L','Locality')]    
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('O')]
        [ValidateNotNullOrEmpty()]
        [String]$Organization,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('CN')]
        [ValidateNotNullOrEmpty()]
        [String]$CommonName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('OU')]    
        [ValidateNotNullOrEmpty()]
        [String]$OrganizationalUnit,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('SAN')]    
        [ValidateNotNullOrEmpty()]
        [String]$AlternativeName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('Contact')]    
        [ValidateNotNullOrEmpty()]
        [String]$ContactName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Email,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('Sur')]    
        [ValidateNotNullOrEmpty()]
        [String]$Surname,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('Giv')]    
        [ValidateNotNullOrEmpty()]
        [String]$GivenName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Initials,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$DNQualifier,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskStatus = [System.Collections.ArrayList]::new()

        if ($Country.length -gt 2)
        {

            $TempCountry = $Country.Clone()

            $Country = GetTwoLetterCountry -Name $Country

            if (-not($Country))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException CountryNameNotFound ObjectNotFound 'Country' -Message ('{0} is not a valid Country Name, or unable to find mapping to RegionInfo ISO3166-2 compliant 2-Character name.' -f $Country )
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }

    Process 
    {    
            
        $_SelfSignedCertObject = NewObject -SelfSignedCert

        $_SelfSignedCertObject.country            =  $Country.ToUpper()
        $_SelfSignedCertObject.state              =  $State
        $_SelfSignedCertObject.locality           =  $City
        $_SelfSignedCertObject.organization       =  $Organization
        $_SelfSignedCertObject.commonName         =  $CommonName
        $_SelfSignedCertObject.organizationalUnit =  $OrganizationalUnit
        $_SelfSignedCertObject.alternativeName    =  $AlternativeName
        $_SelfSignedCertObject.contactPerson      =  $ContactName
        $_SelfSignedCertObject.email              =  $Email
        $_SelfSignedCertObject.surname            =  $Surname
        $_SelfSignedCertObject.givenName          =  $GivenName
        $_SelfSignedCertObject.initials           =  $Initials
        $_SelfSignedCertObject.dnQualifier        =  $DNQualifier

        Try
        {

            Write-Warning 'Updates to the certificate will require the appliance internal web server to be restarted. There will be a temporary service interruption estimated to last 30 seconds.'

            if ($PSCmdlet.ShouldProcess($ApplianceConnection.Name,"generate new self-signed certificate"))
            {    

                "[{0}] Generating new self-signed certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_resp = Send-HPOVRequest -Uri $applianceSslCert -Method POST -Body $_SelfSignedCertObject -HostName $ApplianceConnection
        
            }

            else 
            {

                if ($PSBoundParameters['whatif'].ispresent) 
                { 

                    write-warning "-WhatIf was passed, would have proceeded 'New Self-Signed Certificate for Appliance $($ApplianceConnection.Name)'."

                    $_resp = $null

                }

                else 
                {

                    # If here, user chose "No", End Processing
                    $_resp = $Null

                }

            }

            [void]$_TaskStatus.Add($_resp)

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End 
    {

        Return $_TaskStatus

    }

}

function New-HPOVApplianceCsr 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('C')]
        [ValidateNotNullOrEmpty()]
        [String]$Country,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('ST','Province')]
        [ValidateNotNullOrEmpty()]    
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('L','Locality')]    
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('O')]
        [ValidateNotNullOrEmpty()]
        [String]$Organization,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias ('CN')]
        [ValidateNotNullOrEmpty()]
        [String]$CommonName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('OU')]    
        [ValidateNotNullOrEmpty()]
        [String]$OrganizationalUnit,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('SAN')]    
        [ValidateNotNullOrEmpty()]
        [String]$AlternativeName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('Contact')]    
        [ValidateNotNullOrEmpty()]
        [String]$ContactName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Email,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('Sur')]    
        [ValidateNotNullOrEmpty()]
        [String]$Surname,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('Giv')]    
        [ValidateNotNullOrEmpty()]
        [String]$GivenName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Initials,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$DNQualifier,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$ChallengePassword,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('UN')]    
        [ValidateNotNullOrEmpty()]
        [String]$UnstructuredName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Bool]$CnsaCompliantRequest = $false,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskStatus = [System.Collections.ArrayList]::new()

        # Handle runtime, none-script use
        if ($PSBoundParameters['ChallengePassword'] -and $ChallengePassword -eq '*'  ) 
        {

            Do 
            {

                [SecureString]$ChallengePassword        = Read-Host "Challenge Password:" -AsSecureString

                [SecureString]$ChallengePasswordConfirm = Read-Host "Confirm Challenge Password:" -AsSecureString

                $pwd1_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ChallengePassword))

                $pwd2_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ChallengePasswordConfirm))

                if (-not($pwd1_text -ceq $pwd2_text)) 
                {

                    Write-Error "Passwords to not match. Please try again." -ea Continue

                    $PasswordsMatch = $False

                }

                else { $PasswordsMatch = $True }

            } Until ($PasswordsMatch)

        }

        if ($Country.length -gt 2)
        {

            $TempCountry = $Country.Clone()

            $Country = GetTwoLetterCountry -Name $Country

            if (-not($Country))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException CountryNameNotFound ObjectNotFound 'Country' -Message ('{0} is not a valid Country Name, or unable to find mapping to RegionInfo ISO3166-2 compliant 2-Character name.' -f $Country )
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }

    Process 
    {

        $_CsrObject = NewObject -ApplianceCSR

        $_CsrObject.country            =  $Country.ToUpper()
        $_CsrObject.state              =  $State
        $_CsrObject.locality           =  $City
        $_CsrObject.organization       =  $Organization
        $_CsrObject.commonName         =  $CommonName
        $_CsrObject.organizationalUnit =  $OrganizationalUnit
        $_CsrObject.alternativeName    =  $AlternativeName.Replace(" ", $null) # Remove spaces?
        $_CsrObject.contactPerson      =  $ContactName
        $_CsrObject.email              =  $Email
        $_CsrObject.surname            =  $Surname
        $_CsrObject.givenName          =  $GivenName
        $_CsrObject.initials           =  $Initials
        $_CsrObject.dnQualifier        =  $DNQualifier
        $_CsrObject.unstructuredName   =  $UnstructuredName
        $_CsrObject.challengePassword  =  $ChallengePassword

        Try
        {

            "[{0}] Sending CSR request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_resp = Send-HPOVRequest -Uri $applianceCsr -Method POST -Body $_CsrObject -HostName $ApplianceConnection
                
            [void]$_TaskStatus.Add($_resp)

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }


    }

    End 
    {

        Return $_TaskStatus

    }

}

function GetTwoLetterCountry
{

    <#
        .DESCRIPTION
        Helper function to get ISO3166-2 Compliant Country Name
                     
        .Parameter Country
        Helper function to get ISO3166-2 Compliant Country Name
 
        .INPUTS
        None. You cannot pipe objects to this cmdlet.
                     
        .OUTPUTS
        System.String
        ISO3166-2 Compliant two character country name
         
        .EXAMPLE
        PS C:\> GetTwoLetterCountry 'United States'
        US
 
        Returns the ISO3166-2 Compliant 2-character Country name.
                 
    #>


    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {

        Write-Verbose 'Building Country collection.'

        $CountriesCollection = New-Object Hashtable

        $Countries = [System.Globalization.CultureInfo]::GetCultures([System.Globalization.CultureTypes]'AllCultures')

        foreach ($ObjCultureInfo in [System.Globalization.CultureInfo]::GetCultures([System.Globalization.CultureTypes]'AllCultures'))
        {

            Try
            {

                [System.Globalization.RegionInfo]$_Country = $ObjCultureInfo.LCID

                if ($_Country.EnglishName -match ' AND ')
                {

                    $_CountriesSplit = $_Country.EnglishName.Split(' AND ')

                    ForEach ($_split in $_CountriesSplit)
                    {

                        if (-not($CountriesCollection.ContainsKey($_split)))
                        {
                
                            $CountriesCollection.Add($_split, $_Country.TwoLetterISORegionName.ToUpper());

                        }

                    }

                }

                else
                {

                    if (-not($CountriesCollection.ContainsKey($_Country.EnglishName)))
                    {


                        $CountriesCollection.Add($_Country.EnglishName, $_Country.TwoLetterISORegionName.ToUpper());

                    }

                }

            }

            Catch
            {

                Write-Verbose ("{0} Doesn't have RegionInfo" -f $ObjCultureInfo)

            }

        }

    }

    End
    {

        Write-Verbose 'Returning value'

        Write-Verbose ('Country Collection: {0}' -f ($CountriesCollection | Out-String))

        Write-Verbose ('ISO3166-2 Country Name: {0}' -f $CountriesCollection[$Name])

        $_Return = $CountriesCollection[$Name]

        if (-not($_Return))
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException CountryNameNotFound ObjectNotFound 'Name' -Message ('{0} is not a valid Country Name, or unable to find mapping to RegionInfo ISO3166-2 compliant 2-Character name.' -f $Name )
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)`

        }

        Return $_Return

    }

}

function Install-HPOVApplianceCertificate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default', ValueFromPipeline)]
        [Alias ('PrivateKey', 'Certificate')]
        [ValidateNotNullOrEmpty()]
        [Object]$Path,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $_CertificateObject = NewObject -ApplianceSslCertificate

        'Path is valid: {0}' -f (Test-Path $Path) | Write-Verbose
        if ($Path -Is [System.IO.FileInfo])
        {

            if (-not (Test-Path $Path))
            {

                $Exceptionmessage = 'The supplied Path value is not a valid X.509 certificate, System.IO.FileInfo object, or path to a valid X.509 certificate.'
                $ErrorRecord = New-ErrorRecord InvalidOperationException PathValueInvalid InvalidArgument 'Path' -Message $Exceptionmessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Opening {1} file for reading.)" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Path | Write-Verbose

            Try
            {

                $_ReadFile = [System.IO.File]::OpenText($Path)
                $_Certificate = $_ReadFile.ReadToEnd()
                $_ReadFile.Close()
                $_CertificateObject.base64Data = ($_Certificate | Out-String) -join "`n"

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }            

        }

        elseif ($Path.Contains('-----BEGIN CERTIFICATE-----'))
        {

            "[{0}] Received certificate contents." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_CertificateObject.base64Data = ($Path | Out-String) -join "`n"
            
        }
        
        else 
        {

            $Exceptionmessage = 'The supplied Path value is not a valid X.509 certificate, System.IO.FileInfo object, or path to a valid X.509 certificate.'
            $ErrorRecord = New-ErrorRecord InvalidOperationException PathValueInvalid InvalidArgument 'Path' -Message $Exceptionmessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        Try
        {

            "[{0}] Installing appliance CA signed certificate" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_resp = Send-HPOVRequest -Uri $applianceCsr -Method PUT -BOdy $_CertificateObject -HostName $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['Async'])
        {

            $_resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVPendingUpdate 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Check to see if ane existing update is present. Report to user if it is, and tell them to use -InstallNow
            Try
            {
                
                "[{0}] - Checking if Pending update exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_PendingUpdate = Send-HPOVRequest -Uri $ApplianceUpdatePendingUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_PendingUpdate)
            {

                "[{0}] - Update found $($_PendingUpdate.fileName), $($_PendingUpdate.version)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_PendingUpdate.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.Update.Pending')

            }

            $_PendingUpdate

        }

    }

    End
    {

        "[{0}] - Finished" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Install-HPOVUpdate 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Update', SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Update')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Stage')]
        [Alias ('f')]
        [ValidateScript({Test-Path $_})]
        [String]$File,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Update')]
        [Parameter (Mandatory = $false, ParameterSetName = 'StageInstall')]
        [String]$Eula,

        [Parameter (Mandatory = $false, ParameterSetName = 'Update')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Stage')]
        [Parameter (Mandatory = $false, ParameterSetName = 'List')]
        [Switch]$DisplayReleaseNotes,

        [Parameter (Mandatory, ParameterSetName = 'Stage')]
        [Switch]$Stage,

        [Parameter (Mandatory, ParameterSetName = 'StageInstall')]
        [Switch]$InstallNow,
        
        [Parameter (Mandatory, ParameterSetName = 'List')]
        [Alias ('list')]
        [Switch]$ListPending,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Update")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Stage")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "List")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "StageInstall")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $File)
        {

            $Pipeline = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_StatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Check to see if ane existing update is present. Report to user if it is, and tell them to use -InstallNow
            Try
            {
                
                "[{0}] - Checking if Pending update exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_PendingUpdate = Send-HPOVRequest -Uri $ApplianceUpdatePendingUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            if ($_PendingUpdate)
            {

                "[{0}] - Update found '{1}', '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PendingUpdate.fileName, $_PendingUpdate.version | Write-Verbose

                $_PendingUpdate.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.Update.Pending')

            }

            Switch ($PSCmdlet.ParameterSetName) 
            {
                
                # List staged update
                "List" 
                {

                    # If the request is to install a staged update, we need to handle no response. If request is Update, then no Pending update will exist yet.
                    If (-not($_PendingUpdate)) 
                    {

                        "[{0}] - No Pending update found. Return is Null" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ErrorRecord = New-ErrorRecord InvalidOperationException PendingUpdateNotFound ObjectNotFound 'Install-HPOVUpdate' -Message "No Pending update found. Please first upload update and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_PendingUpdate
                    
                    If ($PSBoundParameters['DisplayReleaseNotes'])
                    {
                        
                        "[{0}] - Displaying Release Notes" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        # Display Release Notes
                        Try
                        {

                            $uri = "/rest/appliance/firmware/document-content/{0}/release" -f $Upload.fileName
                            Send-HPOVRequest -Uri $uri -Hostname $_appliance | ConvertFrom-HTML

                        }
                            
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        "[{0}] - Done. Displayed update release notes." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }
                    
                    Return
                }

                # Stage Update
                "Stage" 
                {              

                    if (-not($_PendingUpdate)) 
                    {

                        "[{0}] - Stage Only" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] - UPLOAD FILE: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $File | Write-Verbose

                        Try 
                        {
                    
                            # Upload update
                            $FileName = Get-Item $File

                            $_upload = Upload-File -Uri $ApplianceUpdateImageUri -File $File -ApplianceConnection $_appliance.Name
                    
                        }

                        Catch 
                        {
                        
                            $ErrorRecord = New-ErrorRecord InvalidOperationException StageUpdateFailed InvalidResult 'Install-HPOVUpdate' -Message $_.Exception.Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        If ($PSBoundParameters['DisplayReleaseNotes'])
                        {
                        
                            "[{0}] - Displaying Release Notes" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            # Display Release Notes
                            Try
                            {

                                $uri = "/rest/appliance/firmware/document-content/{0}/release" -f $Upload.fileName
                                Send-HPOVRequest -Uri $uri -Hostname $_appliance | ConvertFrom-HTML

                            }
                            
                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            "[{0}] - Done. Displayed update release notes." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        Return $_upload

                    }

                    else 
                    {
                    
                        $ExceptionMessage = "An existing appliance update has been staged. Version: '{0}' Filename: '{1}' Please use the -InstallUpdate Parameter to proceed with the update, or use Remove-HPOVPendingUpdate cmdlet to remove the staged update." -f $_PendingUpdate.version, $_PendingUpdate.fileName
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.FirmwareUpdateException PendingUpdateConflict ResourceExists 'File' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                # Upload update then install update below.
                "Update" 
                {

                    if ($_PendingUpdate) 
                    {

                        $ExceptionMessage = "A Pending update was found. File name: '{0}'; Update Version: '{1}'. Please remove the update before continuing and try again." -f $_PendingUpdate.version, $_PendingUpdate.fileName
                        $ErrorRecord = New-ErrorRecord InvalidOperationException PendingUpdateFound ResourceExists 'File' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }
                                    
                    "[{0}] - UPLOAD FILE: '{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $File | Write-Verbose

                    Try 
                    {
                    
                        # Upload update
                        $FileName = Get-Item $File

                        $_PendingUpdate = Upload-File -Uri $ApplianceUpdateImageUri -File $File -ApplianceConnection $_appliance.Name

                        # Pause for 30 seconds? need to make sure appliance has finished Processing update file before invoking update
                        "[{0}] - Sleeping for 5 seconds." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Start-Sleep -Seconds 5
                
                    }

                    Catch 
                    {

                        $ErrorRecord = New-ErrorRecord InvalidOperationException UploadUpdateFailed InvalidResult 'File' -Message $_.Exception.Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            # Process Pending update
            if (($PSCmdlet.ParameterSetName -eq "StageInstall") -or ($PSCmdlet.ParameterSetName -eq "Update" )) 
            {

                # If the request is to install a staged update, we need to handle no response. If request is Update, then no Pending update will exist yet.
                If ((-not($_PendingUpdate)) -and ($PSCmdlet.ParameterSetName -eq "StageInstall")) 
                {

                    "[{0}] - No Pending update found. Return is Null" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $ErrorRecord = New-ErrorRecord InvalidOperationException StorageSystemResourceNotFound ObjectNotFound 'Install-HPOVUpdate' -Message "No Pending update found. Please first upload update and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }


                "[{0}] - Install Now" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_PendingUpdate

                If ($Eula -ne "accept") 
                {

                    "[{0}] - EULA NOT Accepted" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $Url = "https://{0}/ui-js/pages/upgrade/eula_content.html" -f $_appliance.Name

                    try
                    {

                        # Display eula of update

                        $_WebClient = (New-Object HPOneView.Utilities.Net).RestClient($Url, 'GET', 600)

                        [System.Net.WebResponse]$_response = $_WebClient.GetResponse()
                        $_reader = New-Object IO.StreamReader($_response.GetResponseStream())
                        $_reader.ReadToEnd() | ConvertFrom-HTML -NoClobber
                        $_reader.close()

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    Do { $acceptEula = Read-Host "Accept EULA (Must type ACCEPT)" } Until ($acceptEula -eq "Accept")

                }
                    
                "[{0}] - EULA Accepted" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] - Beginning update $($_PendingUpdate.fileName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] - Estimated Upgrade Time $($_PendingUpdate.estimatedUpgradeTime) minutes" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_resp = $Null

                # Check to see if the update requires an appliance reboot.
                if ($_PendingUpdate.rebootRequired) 
                {

                    "[{0}] - Appliance reboot required $($_PendingUpdate.rebootRequired)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] - Prompting for confirmation" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] - Is confirmation overridden $([Bool]$confirm)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Write-Warning "Reboot required for the update."

                    # If it does require a reboot, then we need to prompt for confirmation. Overriden by -confirm:$false
                    if ($PSCmdlet.ShouldProcess($_appliance.Name,"upgrade appliance using $($_PendingUpdate.fileName)")) 
                    {

                        "[{0}] - Appliance reboot required and user selected YES or passed -Confirm:`$false, executing Invoke-Upgrade" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_resp = Invoke-Upgrade $_PendingUpdate -ApplianceConnection $_appliance

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                        
                    }

                    else 
                    {

                        if ($PSBoundParameters['whatif']) 
                        { 

                            write-warning "-WhatIf was passed, would have initiated appliance update."

                        }

                        else 
                        {

                            # If here, user chose "No", End Processing
                            "[{0}] - User selected NO." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose                        

                        }

                    }

                }

                else
                {
                     
                    "[{0}] - Appliance reboot NOT required, executing Invoke-Upgrade" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    Try
                    {

                        $_resp = Invoke-Upgrade $_PendingUpdate -ApplianceConnection $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

                if ($null -ne $_resp)
                {

                    # Update PSLibraryVersion variable with new appliance version
                    Try
                    {

                        $applVersionInfo = Send-HPOVRequest -Uri $ApplianceVersionUri -Hostname $_appliance
                        $PSLibraryVersion."$($_appliance.Name)" = New-Object HPOneView.Appliance.NodeInfo ($applVersionInfo.softwareVersion, (Get-HPOVXApiVersion -ApplianceConnection $_appliance).currentVersion, $applVersionInfo.modelNumber)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }                

                $_resp

            }

        }

    }

    End
    {

        "[{0}] - Finished" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Invoke-Upgrade  
{

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullorEmpty()]
        [Object]$PendingUpdate,

        [Parameter (Mandatory)]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.Connection]$ApplianceConnection

    )

    Begin 
    {
    
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $_FinalStatus = $null

    }

    Process 
    {

        Try
        {

            $uri = "{0}?file={1}" -f $ApplianceUpdatePendingUri, $PendingUpdate.fileName
            $_updateTask = Send-HPOVRequest -Uri $uri -Method PUT -Hostname $ApplianceConnection

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $sw = [System.Diagnostics.Stopwatch]::StartNew()

        $_PreviousTaskStep = $null

        # Loop to display progress-bar
        Do 
        {

            # Connect to update monitor web Process
            Try
            {

                $_MonitorUpdate = Send-HPOVRequest -Uri $ApplianceUpdateMonitorUri -Hostname $ApplianceConnection

                if ($_MonitorUpdate.taskStep)
                {

                    $_PreviousTaskStep = $_MonitorUpdate.taskStep.Replace(" ", $null)

                }

                else
                {

                    $_PreviousTaskStep = $_MonitorUpdate.status.Replace(" ", $null)

                }                

            }
        
            Catch
            {

                # Sleep 30 seconds to see make sure it wasn't a brief Apache issue
                "[{0}] Pausing 30 seconds after '{1}' exception was caught." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.Message | Write-Verbose
                Start-Sleep -Seconds 30

                # Attempt a second connection, as appliance may have restarted Apache
                Try
                {

                    "[{0}] Trying 2nd time to get update monitor status." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_MonitorUpdate = Send-HPOVRequest -Uri $ApplianceUpdateMonitorUri -Hostname $ApplianceConnection

                    if ($_MonitorUpdate.taskStep)
                    {

                        $_PreviousTaskStep = $_MonitorUpdate.taskStep.Replace(" ", $null)

                    }

                    else
                    {

                        $_PreviousTaskStep = $_MonitorUpdate.status.Replace(" ", $null)

                    }

                }
            
                Catch
                {
                    $PSCmdlet.ThrowTerminatingError($_)

                }                        

            }
                        
            # Remove % from value in order to get INT
            if ($_MonitorUpdate.percentageCompletion) 
            { 
                
                $PercentComplete = $_MonitorUpdate.percentageCompletion.Replace("%",$null).Replace(" ",$null)
            
            }
            
            else 
            { 
                
                $PercentComplete = 0 
            
            }
                        
            # Remove " State = " to get proper status
            if ($_MonitorUpdate.status) 
            { 
                
                $UpdateStatus = $_MonitorUpdate.status.Replace(" ", $null).Replace("State=", $null)

                if ($_MonitorUpdate.phase)
                {
                    
                    $UpdateStatus = '{0} - {1}' -f $UpdateStatus, $_MonitorUpdate.phase

                }
            
            }

            else 
            { 
                
                $UpdateStatus = "Starting" 
            
            }

            $Status = "{0} {1}% [{2}min {3}sec]" -f $UpdateStatus, $PercentComplete, $sw.elapsed.minutes, $sw.elapsed.seconds            
            
            # Handle the call from -Verbose so Write-Progress does not get borked on display.
            if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
            { 
                
                "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Update Status: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Status | Write-Verbose
            
            }
                          
            else 
            { 
                
                Write-Progress -id 1 -Activity ("Installing appliance update {0}" -f $PendingUpdate.fileName) -Status $Status -PercentComplete $PercentComplete 
            
            }

            if ($UpdateStatus -match "UpdateReboot") 
            {

                # Handle the call from -Verbose so Write-Progress does not get borked on display.
                if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                { 

                    "[{0}] pausing for 5 minutes while appliance reboots. Invoking Start-Sleep" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    Start-Sleep -Seconds 300

                }

                else 
                { 
                    
                    $time = 300

                    foreach ($i in (1..$time)) 
                    {

                        $percentage = $i / $time
                        
                        Write-Progress -id 1 -activity ("Installing appliance update {0}" -f $PendingUpdate.fileName) -Status $Status -PercentComplete $PercentComplete

                        Write-Progress -id 2 -parent 1 -activity "Appliance Rebooting" -status "Pausing for 5 minutes" -percentComplete ($percentage * 100) -SecondsRemaining ($time - $i)

                        Start-Sleep 1

                    }
                        
                    Write-Progress -id 2 -parent 1 -activity "Appliance Rebooting" -status "Pausing for 5 minutes" -Completed            
                    
                }

            }

        } Until ([Int]$percentComplete -eq 100 -or $_PreviousTaskStep -match 'FAILED')
                
        $sw.Stop()

        "[{0}] Upgrade operation took {1}min, {2}sec." -f $MyInvocation.InvocationName.ToString().ToUpper(), $sw.elapsed.minutes, $sw.elapsed.seconds | Write-Verbose

        # Retrieve final update status
        Try
        {

            $_FinalStatus = Send-HPOVRequest -Uri $ApplianceUpdateNotificationUri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Write-Progress -Activity ("Installing appliance update {0}" -f $PendingUpdate.fileName) -status $updateStatus -percentComplete $percentComplete

        Write-Progress -Activity ("Installing appliance update {0}" -f $PendingUpdate.fileName) -status $updateStatus -Completed

    }

    End 
    {

        Return $_FinalStatus

    }

}

function Remove-HPOVPendingUpdate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {
    
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()
    
    }

    Process 
    { 

        ForEach ($_appliance in $ApplianceConnection)
        {
            
            $_resp = $null

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Check to see if ane existing update is present. Report to user if it is, and tell them to use -InstallNow
            Try
            {
                
                "[{0}] - Checking if Pending update exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_PendingUpdate = Send-HPOVRequest -Uri $ApplianceUpdatePendingUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            if ($_PendingUpdate)
            {

                "[{0}] - Update found $($_PendingUpdate.fileName), $($_PendingUpdate.version)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_PendingUpdate.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.Update.Pending')

                $_PendingUpdate

                $RemoveMessage = "remove Pending update, {0}" -f $_PendingUpdate.fileName

                if ($PSCmdlet.ShouldProcess($_appliance.Name, $RemoveMessage)) 
                {

                    "[{0}] Removing Pending update from applinace." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {
                        
                        "[{0}] - Checking if Pending update exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_resp = Send-HPOVRequest -Uri $ApplianceUpdatePendingUri -Method DELETE -AddHeader @{'If-Match' = '*' } -Hostname $_appliance

                        [void]$_ColStatus.Add($_resp)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                else 
                {

                    "[{0}] No Pending update found" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }

        }

    }

    End 
    { 
    
        Return $_ColStatus

    }

}

function Get-HPOVVersion 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$ApplianceVer,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'CheckOnlineOnly')]
        [Switch]$CheckOnline,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {    
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if  ($ApplianceConnection.Count -eq 0 -and (-not($PSBoundParameters['CheckOnline'])) -and $PSBoundParameters['ApplianceVer'])
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoAuthSessionFound InvalidArgument 'ApplianceConnection' -Message 'No ApplianceConnections were found. Please use Connect-HPOVMgmt to establish an appliance connection.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($PSBoundParameters['ApplianceVer'])
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ApplianceVersionCollection = [System.Collections.ArrayList]::new()
    
    }
    
    Process 
    {

        if ($PSboundParameters['CheckOnline']) 
        {

            try 
            { 

                "[{0}] Testing for Proxy settings" -f  $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Uri]$_ProxyUri = $null

                $_Options = @{Uri = $Repository}

                $_Proxy = [System.Net.WebRequest]::GetSystemWebProxy()

                $_Proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
                $_ProxyUri = $_Proxy.GetProxy($_Options.Uri)

                if ($_ProxyUri.OriginalString -ne $_Options.Uri)
                {

                    $_Options.Add('Proxy',$_proxyUri)
                    $_Options.Add('ProxyUseDefaultCredentials', $true)
                    
                }

                $_OriginalProgressPreference = $ProgressPreference
                
                # Hide the display of Write-Progress Invoke-RestMethod displays
                $ProgressPreference = 'silentlyContinue'

                "[{0}] Invoke-RestMethod Options: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Options | Out-String) | Write-Verbose
                
                $resp = Invoke-RestMethod @_Options

                $ProgressPreference = $_OriginalProgressPreference

                $versionMajorMinor = "{0}.{1}" -f $PSLibraryVersion.Major, $PSLibraryVersion.Minor

                # Filter for versions that match Major and Minor release, and exclude the HP VCM to OneView Migration Tool
                $matchedVersions = $resp | Where-Object { $_.tag_name -like "v$versionMajorMinor*" -and (-not($_.tag_name.startswith('HPVCtoOV'))) -and (-not($_.tag_name.startswith('HPSIMtoOV'))) } 

                "[{0}] Found versions online: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [System.String]::Join(' ,', $resp.tag_name) | Write-Verbose

                $newerVersion = $false

                # Compare the releases
                $matchedVersions | ForEach-Object { 
    
                    if ($newerVersion) 
                    { 
                        
                        Write-Verbose "Found previous version to compare: $newerVersion" 
                    
                    }

                    [version]$version = $_.tag_name -replace "v","" 

                    "[{0}] Comparing {1} to {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $version, $PSLibraryVersion.LibraryVersion | Write-Verbose
        
                    # Compare found version with library
                    if (-not($newerVersion) -and $version.build -gt $PSLibraryVersion.LibraryVersion.build) 
                    {
            
                        [version]$newerVersion = $version
                        $newerVersionObj = $_

                        "[{0}] Newer version found: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $newerVersion | Write-Verbose

                    }

                    elseif ($newerVersion.Build -lt $version.Build -and $version.build -gt $PSLibraryVersion.LibraryVersion.build) 
                    {

                        [version]$newerVersion = $version
                        $newerVersionObj = $_

                        "[{0}] Newer version found: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $newerVersion | Write-Verbose

                    }
    
                }

                if ($newerVersion) 
                { 

                    "[{0}] Found: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]$version | Write-Verbose

                    $PSLibraryVersion | Add-Member -NotePropertyName UpdateAvailable -NotePropertyValue $True

                    if ($ReleaseNotes) { $newerVersionObj.body -replace "## ","" -replace "\*"," ? " }

                    $caption = "Please Confirm";
                    $message = "You currently have v{0} installed. The HP OneView PowerShell Library v{1} was found that is newer. Do you want to download the current version of the HP OneView POSH Library (will open your web browser for you to download)?" -f $PSLibraryVersion.LibraryVersion, [String]$newerVersion
                    $yes     = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Open your browser to download latest HP OneView POSH Library version.";
                    $no      = New-Object System.Management.Automation.Host.ChoiceDescription "&No","No, you will do this later.";
                    $choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no);
                    $answer  = $host.ui.PromptForChoice($caption,$message,$choices,0) 

                    switch ($answer)
                    {

                        0 
                        {

                            "[{0}] Launching users browser to '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $newerVersionObj.html_url | Write-Verbose
                            
                            Start-Process "$($newerVersionObj.html_url)"
        
                        }

                    }     
    
                }

                else 
                { 
                
                    $PSLibraryVersion | Add-Member -NotePropertyName UpdateAvailable -NotePropertyValue $False

                    "[{0}] Library is already up-to-date." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                }

                $PSLibraryVersion

            }

            catch 
            {

                $errorMessage = "$($_[0].exception.message). $($_[0].exception.InnerException.message)"
                $ErrorRecord = New-ErrorRecord HPOneView.Library.UpdateConnectionError InvalidResult ConnectionError 'CheckOnline' -TargetType 'Switch' -Message "$($_[0].exception.message)." -InnerException $_.exception.InnerException
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else
        {

            $PSLibraryVersion

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVHealthStatus 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_HealthStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            Try
            {

                $healthStatus = Send-HPOVRequest $ApplianceHealthStatusUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $healthStatus.members | ForEach-Object { 
                
                $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.HealthStatus") 
            
                [void]$_HealthStatusCollection.Add($_)

            }

        }
    
    }

    End 
    {

        Return $_HealthStatusCollection | Sort-Object ApplianceConnection.Name,resourceType

    }

}

function Get-HPOVXApiVersion 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Cmdlet does not require authentication." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Check to see if a connection to the appliance exists
        # If ($ApplianceConnection -isnot [HPOneView.Appliance.Connection] -and $ApplianceConnection -isnot [System.Collections.IEnumerable] -and $ApplianceConnection -is [String])
        if ($ApplianceConnection -is [String])
        {

            if ((${Global:ConnectedSessions}.Name -notcontains $ApplianceConnection) -and (-not(${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceConnection).SessionID))
            {

                "[{0}] Appliance Session not found. Running FTS sequence?" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Creating temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ApplianceName = $ApplianceConnection

                [HPOneView.Appliance.Connection]$ApplianceConnection = New-TemporaryConnection $ApplianceConnection

                # $ApplianceConnection.Name = $_ApplianceName

                "[{0}] $($ApplianceConnection | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            }

            else
            {

                [HPOneView.Appliance.Connection]$ApplianceConnection = ${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceConnection

            }

        }

        $_XAPICollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                Try
                {

                    $_XAPIVersion = Send-HPOVRequest -Uri $ApplianceXApiVersionUri -Hostname $_appliance

                }
            
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                finally
                {

                    # Remove Temporary appliance connection
                    if ((${Global:ConnectedSessions} | Where-Object Name -eq $_appliance.Name).SessionID -eq 'TemporaryConnection')
                    {

                        "[{0}] Removing temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ConnectedSessions.RemoveConnection($_appliance)

                    }

                }

                $_XAPIVersion | ForEach-Object { $_.PSObject.TypeNames.insert(0,'HPOneView.Appliance.XAPIVersion') }

                [void]$_XAPICollection.Add($_XAPIVersion)
        
            }

        }        

        else
        {

            Try
            {

                $_XAPIVersion = Send-HPOVRequest -Uri $ApplianceXApiVersionUri -Hostname $ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            finally
            {

                # Remove Temporary appliance connection
                if ((${Global:ConnectedSessions} | Where-Object Name -eq $ApplianceConnection.Name).SessionID -eq 'TemporaryConnection')
                {

                    "[{0}] Removing temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ConnectedSessions.RemoveConnection($ApplianceConnection)

                }

            }

            New-Object HPOneView.Appliance.XApiVersion( $_XAPIVersion.currentVersion, $_XAPIVersion.minimumVersion, $_XAPIVersion.ApplianceConnection)
        
        }

    }

    End 
    { 
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Get-HPOVEulaStatus 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Object]$Appliance

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Need to create temporary Global:ConnectedSessions after validating it doesn't exist for appliance connection being created.
        # otherwise, cmdlet will fail when making call to REstClient and it performs the SSL validation and flag value in SSLChecked property
        # need to do the same with Set-HPOVEulaStatus
        # Check to see if a connection to the appliance exists

        if ($Appliance -is [String])
        {

            if (-not(${Global:ConnectedSessions}.Name -contains $Appliance) -and (-not(${Global:ConnectedSessions} | Where-Object Name -eq $Appliance).SessionID))
            {

                "[{0}] Appliance Session not found. Running FTS sequence?" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Creating temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ApplianceName = $Appliance

                [HPOneView.Appliance.Connection]$Appliance = New-TemporaryConnection $Appliance

                "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Appliance.Name | Write-Verbose
            
            }

            else # If (${Global:ConnectedSessions}.Name -contains $Appliance)
            {

                "[{0}] Appliance is a string value, lookup connection in global tracker." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [HPOneView.Appliance.Connection]$Appliance = ${Global:ConnectedSessions} | Where-Object Name -eq $Appliance

                "[{0}] Found connection in global tracker: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

            }
            
        }

        elseif ($Appliance -is [HPOneView.Appliance.Connection])
        {

            "[{0}] Appliance is a Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

        }
       
    }

    Process 
    {

        "[{0}] Getting EULA Status from '$($Appliance.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $_ApplianceEulaStatus = Send-HPOVRequest $ApplianceEulaStatusUri -Hostname $Appliance.Name

            $_EulaStatus = New-Object HPOneView.Appliance.EulaStatus($Appliance.Name, !$_ApplianceEulaStatus)

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        finally
        {

            # Remove Temporary appliance connection
            if ((${Global:ConnectedSessions} | Where-Object Name -eq $Appliance.Name).SessionID -eq 'TemporaryConnection')
            {

                "[{0}] Removing temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ConnectedSessions.RemoveConnection($Appliance)

            }

        }
        
    }

    End 
    { 

        Return $_EulaStatus
    
    }

}

function Set-HPOVEulaStatus 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Object]$Appliance,

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('Yes', 'No')]
        [String]$SupportAccess

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Check to see if a connection to the appliance exists
        if ($Appliance -is [String])
        {

            if (-not(${Global:ConnectedSessions}.Name -contains $Appliance) -and (-not(${Global:ConnectedSessions} | Where-Object Name -eq $Appliance).SessionID))
            {

                "[{0}] Appliance Session not found. Running FTS sequence?" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

                "[{0}] Creating temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

                $_ApplianceName = $Appliance

                [HPOneView.Appliance.Connection]$Appliance = New-TemporaryConnection $Appliance

                "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Appliance.Name | Write-Verbose
            
            }

            else # If (${Global:ConnectedSessions}.Name -contains $Appliance)
            {

                "[{0}] Appliance is a string value, lookup connection in global tracker." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [HPOneView.Appliance.Connection]$Appliance = ${Global:ConnectedSessions} | Where-Object Name -eq $Appliance

                "[{0}] Found connection in global tracker: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

            }

        }        

        elseif ($Appliance -is [HPOneView.Appliance.Connection])
        {

            "[{0}] Appliance is a Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

        }

        else
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException UnknownCondition InvalidOperation "Appliance" -Message "An unknown condition has ocurred."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
    
    }

    Process 
    {

        $body = [PSCustomObject]@{
            
            supportAccess = $supportAccess
        
        }

        Try
        {

            $_eulastatus = Send-HPOVRequest -Uri $ApplianceEulaSaveUri -Method POST -BOdy $body -Hostname $Appliance

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Finally
        {

            if ((${Global:ConnectedSessions} | Where-Object Name -eq $Appliance.Name).SessionID -eq 'TemporaryConnection')
            {

                "[{0}] Removing temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

                $ConnectedSessions.RemoveConnection($Appliance)

            }

        }
        
    }

    End 
    { 
    
        Return $_eulastatus
    
    }

}

function New-TemporaryConnection
{

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname
    
    )

    Process
    {

        $_ID = 99

        While (-not($FoundID))
        {

            if ($ConnectedSessions.ConnectionID -notcontains $_ID)
            {

                $FoundID = $_ID

            }

            $_ID--

        }

        $_TemporaryConnection = New-Object HPOneView.Appliance.Connection($_ID, $Hostname, 'TemporaryConnection')

        [void]${Global:ConnectedSessions}.Add($_TemporaryConnection)

        Return $_TemporaryConnection

    }    

}

function Get-HPOVApplianceNetworkConfig 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [Alias ("x", "export", 'exportFile')]
        [ValidateScript({Test-Path $_})]
        [String]$Location,
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceNetworkConfiguration = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            "[{0}] Processing Appliance Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            Try
            {
            
                $_appliancenetconfig = Send-HPOVRequest -Uri $ApplianceNetworkConfigUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        
            $_appliancenetconfig | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.ApplianceServerConfiguration") }
            $_appliancenetconfig.applianceNetworks | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.ApplianceServerConfiguration.ApplianceNetworks") }
        
            [void]$_ApplianceNetworkConfiguration.Add($_appliancenetconfig)

        }
    
    }

    End 
    {

        If ($PSBoundParameters['Location']) 
        {

            ForEach ($_ApplianceConfig in $_ApplianceNetworkConfiguration)
            {

                $_filename = "{0}_ApplianceNetConf.json" -f $_ApplianceConfig.ApplianceConnection.Name

                ForEach ($nic in $_ApplianceConfig.applianceNetworks) 
                {

                    if ($nic.IPv4Type -eq "DHCP") { $nic.app1IPv4Addr = $null }

                    if ($nic.IPv6Type -eq "DHCP") { $nic.app1IPv6Addr = $null }
                
                }

                $_ApplianceConfig = $_ApplianceConfig | Select-Object * -ExcludeProperty ApplianceConnection

                $_ApplianceConfig | convertto-json -depth 99 > ($Location + '\' + $_filename)

                Get-ChildItem ($Location + '\' + $_filename)

            }
            
        }
        
        Else 
        {
        
            Return $_ApplianceNetworkConfiguration

        }

    }

}

function Get-HPOVApplianceDateTime
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceDateTimeCol = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            "[{0}] Processing Appliance Connection {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {
            
                $_appliancedatetime = Send-HPOVRequest -Uri $ApplianceDateTimeUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
            $SyncWithHost = $true

            if ($_appliancedatetime.ntpServers.Count -gt 0)
            {

                $SyncWithHost = $false

            }

            New-Object HPOneView.Appliance.ApplianceLocaleDateTime($_appliancedatetime.locale,
                                                                   $_appliancedatetime.timezone,
                                                                   $_appliancedatetime.dateTime,
                                                                   [String[]]$_appliancedatetime.ntpServers,
                                                                   $_appliancedatetime.pollingInterval,
                                                                   $SyncWithHost,
                                                                   $_appliancedatetime.LocaleDisplayName,
                                                                   $_appliancedatetime.ApplianceConnection)

        }
    
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceDateTime
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = 'SyncHost')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'SyncHost')]
        [Switch]$SyncWithHost,

        [Parameter (Mandatory, ParameterSetName = 'NTPServers')]
        [Array]$NTPServers,

        [Parameter (Mandatory = $false, ParameterSetName = 'NTPServers')]
        [Int]$PollingInterval,

        [Parameter (Mandatory = $False, ParameterSetName = 'SyncHost')]
        [Parameter (Mandatory = $False, ParameterSetName = 'NTPServers')]
        [ValidateSet ('en_US','zh_CN','ja_JP')]
        [String]$Locale,

        [Parameter (Mandatory = $False, ParameterSetName = 'SyncHost')]
        [Parameter (Mandatory = $False, ParameterSetName = 'NTPServers')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_SyncWithHost = $false
        
            "[{0}] Processing Appliance Connection {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_CurrentConfig = Send-HPOVRequest -Uri $ApplianceDateTimeUri -Hostname $_appliance.Name

            }


            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_ApplianceTimeConfig = NewObject -ApplianceTimeLocale
            
            switch ($PSCmdlet.ParameterSetName)
            {

                'SyncWithHost'
                {

                    "[{0}] Seting ntpServers to 'null' for Sync with Host." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $_ApplianceTimeConfig.ntpServers = @()
                    $_SyncWithHost = $true

                }

                'NTPServers'
                {

                    ForEach ($_ntpserver in $NTPServers)
                    {

                        "[{0}] Adding '{1}' to collection."-f $MyInvocation.InvocationName.ToString().ToUpper(), $_ntpserver | Write-Verbose

                        [void]$_ApplianceTimeConfig.ntpServers.Add($_ntpserver)

                    }

                    if ($PSBoundParameters['PollingInterval'])
                    {

                        $_ApplianceTimeConfig.pollingInterval = $PollingInterval.ToString()

                    }

                }

            }

            if ($PSBoundParameters['TimeZone'])
            {

                $_ApplianceTimeConfig.timezone = $TimeZone

            }

            else
            {

                $_ApplianceTimeConfig.timezone = $_CurrentConfig.timezone

            }

            if ($PSBoundParameters['Locale'])
            {

                $_ApplianceTimeConfig.locale = $ApplianceLocaleSetEnum[$Locale]

            }

            else
            {

                $_ApplianceTimeConfig.locale = $_CurrentConfig.locale

            }

            Try
            {
            
                $_Results = Send-HPOVRequest -Uri $ApplianceDateTimeUri -Method POST -Body $_ApplianceTimeConfig -Hostname $_appliance.Name | Wait-HPOVTaskComplete

                if ('Warning', 'Completed' -notcontains $_Results.taskState)
                {

                    $ExceptionMessage = [String]::Join(' ', $_Results.taskErrors.Message)
                    $ErrorRecord = New-ErrorRecord InvalidOperationException ApplianceDateTimeInvalidOperation InvalidOperation $ApplianceConnection.Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_appliancedatetime = Send-HPOVRequest -Uri $ApplianceDateTimeUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            New-Object HPOneView.Appliance.ApplianceLocaleDateTime($_appliancedatetime.locale,
                                                                   $_appliancedatetime.timezone,
                                                                   $_appliancedatetime.dateTime,
                                                                   [String[]]$_appliancedatetime.ntpServers,
                                                                   $_appliancedatetime.pollingInterval,
                                                                   $SyncWithHost,
                                                                   $_appliancedatetime.LocaleDisplayName,
                                                                   $_appliancedatetime.ApplianceConnection)
            
        }
    
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceNetworkConfig 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
       
    [CmdletBinding (DefaultParameterSetName = "VMA")]
    Param 
    (
       
        [Parameter (Mandatory, ParameterSetName = "VMA")]
        [Parameter (Mandatory, ParameterSetName = "Composer")]
        [ValidateNotNullorEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateSet ('DHCP','STATIC')]
        [String]$IPv4Type = 'STATIC',

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' +
            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' +
            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' +
            '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' +
            '(/0*([1-9]|[12][0-9]|3[0-2]))?$' })]
        [Net.IPAddress]$IPv4Addr,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory, ParameterSetName = "Composer")]
        [ValidateScript({
        
            ($_ -ge 1 -and $_ -le 32) -or
            ($_ -match [Net.IPAddress]$_)            
        
        })]
        [String]$IPv4Subnet,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$IPv4Gateway,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateSet ('DHCP','STATIC','UNCONFIGURE')]
        [String]$IPv6Type = 'UNCONFIGURE',

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$IPv6Addr,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateNotNullorEmpty()]
        [String]$IPv6Subnet,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [String]$IPv6Gateway,

        [Parameter (Mandatory, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$ServiceIPv4Node1,

        [Parameter (Mandatory, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$ServiceIPv4Node2,

        [Parameter (Mandatory= $false, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$ServiceIPv6Node1,
        
        [Parameter (Mandatory= $false, ParameterSetName = "Composer")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$ServiceIPv6Node2,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [Alias ('overrideDhcpDns')]
        [Switch]$OverrideIPv4DhcpDns,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [Switch]$OverrideIPv6DhcpDns,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateNotNullorEmpty()]
        [String]$DomainName,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateNotNullorEmpty()]
        [Array]$SearchDomains,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateNotNullorEmpty()]
        [Alias ('nameServers')]
        [Array]$IPv4NameServers,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [ValidateNotNullorEmpty()]
        [Array]$IPv6NameServers,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Object]$NtpServers,

        [Parameter (Mandatory, ParameterSetName = "importFile")]
        [Alias ("i", "import")]
        [ValidateScript({Test-Path $_})]
        [Object]$importFile,

        [Parameter (Mandatory = $false, ParameterSetName = "VMA")]
        [Parameter (Mandatory = $false, ParameterSetName = "Composer")]
        [Parameter (Mandatory = $false, ParameterSetName = "importFile")]
        [ValidateNotNullOrEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSBoundParameters['NtpServers'])
        {

            Write-Warning 'The -NtpServer Parameter has been deprecated, and is now controlled in the Set-HPOVApplianceDateTime Cmdlet. Please update your scripts accordingly.'

        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if  ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $colStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        # Locate the Enclosure Group specified
        "[{0}] - Starting" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if ($ApplianceConnection.ApplianceType -eq 'Composer' -and (-not($PSBoundParameters['ServiceIPv4Node1']) -or -not($PSBoundParameters['ServiceIPv4Node2'])))
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException MissingParameterValues InvalidOperation $ApplianceConnection.Name -Message 'The connected appliance type is a Synergy Composer, however the required -ServiceIPv4Node1 and/or -ServiceIPv4Node2 Parameter (s) was(were) not provided. Please correct the call and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Validate the appliance can Begin Network configuration of the appliance
        Try
        {

            "[{0}] Validating Network can be configured on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $ApplianceNetworkStatusUri -Hostname $ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not($_resp.networkingAllowed))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException UnableToEditApplianceNetwork InvalidOperation $ApplianceConnection.Name -Message ($_resp.disabledReason -join " ")
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Get the current config (to get ETag & ensure we don't overwrite anything):
        Try
        {

            $_currentconfig = Send-HPOVRequest -Uri $ApplianceNetworkConfigUri -Hostname $ApplianceConnection.Name

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Switch ($PSCmdlet.ParameterSetName) 
        {
    
            {"VMA",'Composer' -contains $_}
            {

                 "[{0}] Looking for Primary interface configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                [Int]$i = 0
                
                $_deviceIndex = $null
                
                For ($i -eq 0; $i -le ($_currentconfig.applianceNetworks.Count - 1); $i++)
                {

                    if($_currentconfig.applianceNetworks[$i].interfaceName -eq "Appliance")
                    {
                        
                        "[{0}] Found interface: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_currentconfig.applianceNetworks[$i].interfaceName | Write-Verbose
                        
                        $_deviceIndex = $i

                        $_configured = $true
                        
                        #break out of for loop
                        break

                    }

                }

            }

            "importFile" 
            {

                try 
                {

                    $_importConfig = [String]::Join("", (Get-Content $importfile -ErrorAction Stop))

                    $_importConfig = $_importConfig -replace "\s","" | convertfrom-json -ErrorAction Stop

                }

                catch [System.Management.Automation.ItemNotFoundException] 
                {
    
                    $ErrorRecord = New-ErrorRecord System.Management.Automation.ItemNotFoundException ImportFileNotFound ObjectNotFound 'Set-HPOVApplianceNetworkConfig' -Message "$importFile not found!"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
    
                }
    
                catch [System.ArgumentException] 
                {
    
                    $ErrorRecord = New-ErrorRecord System.ArgumentException InvalidJSON ParseErrror 'Set-HPOVApplianceNetworkConfig' -Message "Input JSON format incorrect!"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)    

                }

    
                [Int]$i = 0

                For ($i -eq 0; $i -le ($_importConfig.applianceNetworks.Count - 1); $i++)
                {

                    if ($_importConfig.applianceNetworks[$i].IPv4Gateway -eq "127.0.0.1")
                    {

                        $_importConfig.applianceNetworks[$i].IPv4Gateway = $null

                    }

                    if ($_importConfig.applianceNetworks[$i].nameServers -is [String])
                    {

                        $_importConfig.applianceNetworks[$i].nameServers = New-Object.System.Collections.ArrayList

                    }

                    if ($_importConfig.applianceNetworks[$i].searchDomains -is [String])
                    {

                        $importConfig.applianceNetworks[$i].searchDomains = New-Object.System.Collections.ArrayList

                    }
                    
                    if (-not($_importConfig.applianceNetworks[$i].macAddress)) 
                    {

                        #$_macAddr = ($_importConfig.applianceNetworks | ? { $_.device -eq $_importConfig.applianceNetworks[$i].device }).macAddress

                        if (-not $_importConfig.applianceNetworks[$i].macAddress) 
                        {

                            $_macAddr = ($_currentconfig.applianceNetworks | Where-Object { $_.device -eq $_importConfig.applianceNetworks[$i].device }).macAddress

                        }

                        if(-not $_macAddr)
                        {

                            $ErrorRecord = New-ErrorRecord InvalidOperationException ApplianceNICResourceNotFound ObjectNotFound 'Device' -Message ($_importConfig.applianceNetworks[$i].device + "does not exist on the appliance.")
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_importConfig.applianceNetworks[$i] | Add-Member -NotePropertyName macAddress -NotePropertyValue $_macAddr
    
                    }

                    if ($_importConfig.applianceNetworks[$i].interfaceName -eq 'Appliance' -and $_importConfig.applianceNetworks[$i].ipv4Type -eq 'STATIC')
                    {

                        # Clear non-virtIpv4Addr value for non-Composer appliances
                        if ($ApplianceConnection.ApplianceType -ne 'Composer')
                        {

                            $_importConfig.applianceNetworks[$i].virtIpv4Addr = $null
                            $_importConfig.applianceNetworks[$i].app2Ipv4Addr = $null

                        }

                        # This is needed for when we attempt to reconnect back to the appliance
                        [IPAddress]$IPv4Addr = $_importConfig.applianceNetworks[$i].app1Ipv4Addr

                    }

                }

                #zero the $currentConfig.applianceNetworks array so we can sEnd it all new values
                $_currentConfig.applianceNetworks = $_importConfig.applianceNetworks

            }

        }

        if ($_configured)
        {

            # Update any non-null values that were passed-in:
            
            if ($Hostname) 
            {

                if ($DomainName)
                {

                    $Hostname += '.{0}' -f $DomainName

                }

                $_currentconfig.applianceNetworks[$_deviceIndex].hostname = $Hostname 

            }

            if ($DomainName)    { $_currentconfig.applianceNetworks[$_deviceIndex].domainName    = $DomainName }
            if ($SearchDomains) { $_currentconfig.applianceNetworks[$_deviceIndex].searchDomains = $SearchDomains }

            $_currentconfig.applianceNetworks[$_deviceIndex].IPv4Type = $IPv4Type.ToUpper()
            $_currentconfig.applianceNetworks[$_deviceIndex].IPv6Type = $IPv6Type.ToUpper() 

            switch ($IPv4Type)
            {

                'DHCP'
                {

                    if ($ApplianceConnection.ApplianceType -eq 'Composer')
                    {

                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidIPv4AddressType InvalidOperation 'IPv4Type' -Message 'The connected appliance type is a Synergy Composer, only Static IPv4Address configurations are allowed.'
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    '[{0}] Configuring DHCP for NIC' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                    $_currentconfig.applianceNetworks[$_deviceIndex].app1IPv4Addr = $null

                    # If $overrideIPv4DhcpDns is true, set it, if not make sure it is fale
                    if ($PSBoundParameters['OverrideIPv4DhcpDns']) 
                    { 
                        
                        $_currentconfig.applianceNetworks[$_deviceIndex].overrideIPv4DhcpDnsServers = [Bool]$OverrideIPv4DhcpDns 
                    
                    }

                    else 
                    { 
                        
                        $_currentconfig.applianceNetworks[$_deviceIndex].overrideIPv4DhcpDnsServers = $false 
                    
                    }

                }

                'STATIC'
                {

                    '[{0}] Configuring STATIC for NIC' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                    # Make sure override.. is false if STATIC ip addresses are in use.
                    $_currentconfig.applianceNetworks[$_deviceIndex].overrideIPv4DhcpDnsServers = $false 

                    if ((-not($PSBoundParameters['IPv4Subnet'])) -or ([Net.IPAddress]$IPv4Subnet -eq 0.0.0.0) -or $null -eq $IPv4Subnet)
                    {

                        $Message = 'A static IPv4 Address was provided, but not a valid IPv4Subnet Parameter value. Please correct this and try again.'
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.NetworkConfigurationException InvalidIPv4Subnet InvalidArgument 'IPv4Subnet' -Message $Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                    }
                    
                    # Calculate the CIDR bit value to the SubnetMask Address
                    if ($PSBoundParameters['IPv4Subnet'].Length -le 2)
                    {

                        Try
                        {

                            "[{0}] Converting Subnet CIDR Bit value to Subnet Mask Address." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            [Int64]$_Int64Value = ([convert]::ToInt64(('1' * $IPv4Subnet + '0' * (32 - $IPv4Subnet)), 2))

                            $IPv4Subnet = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($_Int64Value / 16777216)).ToString(),
                                                               ([math]::Truncate(($_Int64Value % 16777216) / 65536)).ToString(),
                                                               ([math]::Truncate(($_Int64Value % 65536)/256)).ToString(),
                                                               ([math]::Truncate($_Int64Value % 256)).ToString()

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    $_currentconfig.applianceNetworks[$_deviceIndex].IPv4Subnet  = $IPv4Subnet
                    $_currentconfig.applianceNetworks[$_deviceIndex].IPv4Gateway = $IPv4Gateway.IPAddressToString

                    if ($PSBoundParameters['IPv4NameServers']) 
                    { 
                        
                        $_currentconfig.applianceNetworks[$_deviceIndex].IPv4NameServers = $IPv4NameServers 
                    
                    }

                    if ($ApplianceConnection.ApplianceType -eq 'Composer')
                    {

                        '[{0}] Appliance is Composer, setting Service IP1 and Service IP2' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                        $_currentconfig.applianceNetworks[$_deviceIndex].virtIPv4Addr = $IPv4Addr.IPAddressToString
                        $_currentconfig.applianceNetworks[$_deviceIndex].app1IPv4Addr = $ServiceIPv4Node1.IPAddressToString
                        $_currentconfig.applianceNetworks[$_deviceIndex].app2IPv4Addr = $ServiceIPv4Node2.IPAddressToString

                    }

                    else
                    {

                        $_currentconfig.applianceNetworks[$_deviceIndex].app1IPv4Addr = $IPv4Addr.IPAddressToString

                    }

                }

            }

            switch ($IPv6Type)    
            { 

                'STATIC'
                {

                    if ($ApplianceConnection.ApplianceType -eq 'Composer')
                    {

                        $_currentconfig.applianceNetworks[$_deviceIndex].virtIPv6Addr = $IPv6Addr.IPAddressToString

                        if ($ServiceIPv6Node1 -and $ServiceIPv6Node2)
                        {

                            '[{0}] Appliance is Composer, setting Service IPv6 1' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                            $_currentconfig.applianceNetworks[$_deviceIndex].app1IPv6Addr = $ServiceIPv6Node1.IPAddressToString

                            '[{0}] Appliance is Composer, setting Service IPv6 2' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                            $_currentconfig.applianceNetworks[$_deviceIndex].app2IPv6Addr = $ServiceIPv6Node2.IPAddressToString

                        }

                    }

                    else
                    {

                        $_currentconfig.applianceNetworks[$_deviceIndex].app1IPv6Addr = $IPv6Addr.IPAddressToString

                    }

                    $_currentconfig.applianceNetworks[$_deviceIndex].IPv6Subnet   = $IPv6Subnet 
                    $_currentconfig.applianceNetworks[$_deviceIndex].IPv6Gateway  = $IPv6Gateway.IPAddressToString                    

                    if ($PSBoundParameters['IPv6NameServers']) 
                    { 
                        
                        $_currentconfig.applianceNetworks[$_deviceIndex].IPv6NameServers = $IPvV6NameServers 
                    
                    }

                }

                'DHCP'
                {

                    # If setting DHCP, clear any existing IP address:
                    if ($IPv6Type -ieq "DHCP") 
                    { 
                        
                        $_currentconfig.applianceNetworks[$_deviceIndex].app1IPv6Addr = $null 
                    
                    }

                    if ($PSBoundParameters['OverrideIPv6DhcpDns']) 
                    { 
                        
                        $_currentconfig.applianceNetworks[$_deviceIndex].overrideIPv6DhcpDnsServers = [Bool]$overrideIPv6DhcpDns 
                        $_currentconfig.applianceNetworks[$_deviceIndex].IPv6NameServers            = $IPv6NameServers
                    
                    }

                }
                
            }

            # Hard code the following settings, for now:
            $_currentconfig.applianceNetworks[$_deviceIndex].confOneNode = "true"  # Always "true", for now
            $_currentconfig.applianceNetworks[$_deviceIndex].activeNode = "1"      # Always "1", for now
        
        }

        "[{0}] Configuration to be applied: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_currentconfig | ConvertTo-Json -Depth 99 | out-string) | Write-Verbose

        # Remove MAC Address value or DHCP setting will break
        if ($_currentconfig.macAddress -and $ApplianceConnectionApplianceType -ne 'Composer')
        { 
            
            $_currentconfig.macAddress = $null 
        
        }

        # This is an asynch method, so get the returned Task object
        Try
        {

            $_task = Send-HPOVRequest -uri $ApplianceNetworkConfigUri -Method POST  -Body $_currentconfig -Hostname $ApplianceConnection | Wait-HPOVTaskStart

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Validate status code 200, even though it should be HTTP/202
        if ($_task.category -eq "tasks" -and $_task.taskState -eq "Running") 
        {
        
            # Start a new stopwatch object
            $sw = [diagnostics.stopwatch]::StartNew()
                
            Do 
            {

                # Should I make this 120 seconds instead of 90?
                $_PercentComplete = [Math]::Round(((($sw.Elapsed.Minutes * 60) + $sw.Elapsed.Seconds) / 90) * 100,$MathMode)
                
                if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                { 
                    
                    "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Percent Complete: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PercentComplete | Write-Verbose
                    Start-Sleep -s 1

                }
                  
                else 
                {

                    # Display progress-bar
                    Write-Progress -activity "Update Appliance Network Configuration" -Status "Processing $_PercentComplete%" -percentComplete $_PercentComplete 

                }

            } until ($_PercentComplete -eq 100)

            # Stop the stopwatch
            $sw.stop()
            
            Write-Progress -activity "Update Appliance Network Configuration" -Completed
        
        }

        # Task failed validation
        elseif ($_task.taskState -eq "Error") 
        {

            if ($_task.taskErrors -is [Array] -and $_task.taskErrors.count -gt 1 ) 
            {

                for ($e = 0; $e -gt $_task.taskErrors.count; $e++) 
                {

                    if ($e -ne $_task.taskErrors.length) 
                    {
                        
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.NetworkConfigurationException NoAuthSession AuthenticationError 'Set-HPOVApplianceNetworkConfig' -Message "No valid session ID found. Please use Connect-HPOVMgmt to connect and authenticate to an appliance."
                        $PSCmdlet.WriteError($ErrorRecord)    

                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoAuthSession AuthenticationError 'Set-HPOVApplianceNetworkConfig' -Message "No valid session ID found. Please use Connect-HPOVMgmt to connect and authenticate to an appliance."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)    

                    }

                }

            }

        }

        if ($IPv4Type -eq "static") 
        {

            Start-Sleep -Seconds 5

            "[{0}] Connecting to new static IP address {1} to validate it is an HPE OneView appliance." -f $MyInvocation.InvocationName.ToString().ToUpper(), $IPv4Addr.IPAddressToString | Write-Verbose

            "[{0}] Add appliance address {1} to TrustedHosts collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $IPv4Addr.IPAddressToString | Write-Verbose

            # $Validator.AddTrustedHost($IPv4Addr.IPAddressToString)
            [HPOneView.PKI.SslValidation]::AddTrustedHost($IPv4Addr.IPAddressToString)
            
            # Check to make sure we connect to a OneView appliance
            Try
            {

                $Url = "https://{0}" -f $IPv4Addr.IPAddressToString

                $_WebClient = (New-Object HPOneView.Utilities.Net).RestClient($Url, 'GET', 0)

                [System.Net.WebResponse]$_response = $_WebClient.GetResponse()
                $_reader = New-Object IO.StreamReader($_response.GetResponseStream())
                $_resp = $_reader.ReadToEnd()
                $_reader.close()

            }

            Catch
            {

                "[{0}] Exception caught: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception | Write-Verbose

                # Try to connect to the appliance with the original address
                Try
                {

                    $_task = Send-HPOVRequest -uri $_task.uri -Hostname $ApplianceConnection

                    if ($_task.taskState -eq 'Error')
                    {

                        $_task.taskErrors | ForEach-Object { $Message += ('{0} {1} ({2}) {3}' -f $_.message, $_.details, $_.errorCode, ($_.recommEndedActions -Join ' ')) }
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.NetworkConfigurationException InvalidApplianceNetworkConfigResult InvalidResult 'Set-HPOVApplianceNetworkConfig' -Message $Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    else
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # If successful, update current POSH session
            if ($_resp -match "<title>OneView</title>") 
            { 

                "[{0}] Updating Global Connection Sessions appliance object with new appliance address: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IPv4Addr.IPAddressToString | Write-Verbose
                
                # if ($Validator.TrustedHosts.ContainsKey($ApplianceConnection.Name))
                if ([HPOneView.PKI.SslValidation]::TrustedHosts.ContainsKey($ApplianceConnection.Name))
                {

                    "[{0}] Removing appliance address {1} from TrustedHosts collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceConnection.Name | Write-Verbose

                    # $Validator.RemoveTrustedHost($ApplianceConnection.Name)
                    [HPOneView.PKI.SslValidation]::RemoveTrustedHost($ApplianceConnection.Name)

                }            

                "[{0}] Updating ConnectedSessions Name property with updated address value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IPv4Addr.IPAddressToString | Write-Verbose

                ($Global:ConnectedSessions | Where-Object name -eq $ApplianceConnection.Name).SetName($IPv4Addr.IPAddressToString)

            }

            else 
            {

                # Unable to connect to new appliance address or connection failed. Need to generate error here.
                $ExceptionMessage = "Unable to reconnect to the appliance. Please check to make sure there are no IP Address conflicts or your set the IP Address and Subnet Mask correctly."
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.NetworkConnectionException ApplianceUnreachable ConnectionError 'IPv4Addr' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)    

            }

        }

        # Check to see if we can get the final status of the task resource
        Try
        {

            $Task = Send-HPOVRequest $_task.uri -Hostname $ApplianceConnection.Name | Wait-HPOVTaskComplete 

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        [void]$colStatus.Add($Task)

    }

    End
    {

        Return $colStatus

    }

}

function Get-HPOVSnmpReadCommunity 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (
    
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceSnmpConfigCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_applSnmpReadCommunityStr = Send-HPOVRequest $ApplianceSnmpReadCommunityUri -Hostname $_appliance

                New-Object HPOneView.Appliance.SnmpReadCommunity ($_applSnmpReadCommunityStr.communityString,
                                                                  $_applSnmpReadCommunityStr.uri,
                                                                  $_applSnmpReadCommunityStr.ApplianceConnection)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }            

        }
    
    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVSnmpReadCommunity 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceSnmpConfigCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            "[{0}] New SNMP Read Community Value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose
            
            $_NewApplSnmpReadCommunityStr = [PsCustomObject]@{ "communityString" = $name }

            Try
            {

                $_rspNewApplSnmpReadCommunity = Send-HPOVRequest -Uri $ApplianceSnmpReadCommunityUri -Method PUT -Body $_NewApplSnmpReadCommunityStr -Hostname $_appliance

                $_rspNewApplSnmpReadCommunity.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.SnmpCommunity')

                [void]$_ApplianceSnmpConfigCollection.Add($_rspNewApplSnmpReadCommunity)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
    
    }

    End
    {

        Return $_ApplianceSnmpConfigCollection

    }

}

function New-HPOVSnmpV3User
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Mandatory, ParameterSetName = "ApplianceSnmpUser")]
        [Switch]$ApplianceSnmpUser,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateSet ("None", "AuthOnly","AuthAndPriv")]
        [ValidateNotNullOrEmpty()]
        [String]$SecurityLevel = "None",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateSet ('none', "MD5", "SHA", 'SHA1', 'SHA256', 'SHA384', 'SHA512')]    
        [ValidateNotNullOrEmpty()]
        [String]$AuthProtocol = 'none',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$AuthPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateSet ('none', "des56", '3des', 'aes128', 'aes192', 'aes256')]    
        [ValidateNotNullOrEmpty()]
        [String]$PrivProtocol = 'none',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$PrivPassword,

        [Parameter (Mandatory = $False, ParameterSetName = "ApplianceSnmpUser")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'ApplianceSnmpUser') 
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_CredentialsCol = [System.Collections.ArrayList]::new()

        if ($SecurityLevel -eq "AuthOnly" -and 
            ($AuthPassword)) 
        {

            # Generate Terminateing error
            $ExceptionMessage = "The -SecurityLevel Parameter was set to 'AuthOnly', but did not include -AuthPassword Parameter. An AuthPassword is required."
            $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException MissingRequiredParameters InvalidArgument 'SecurityLevel' Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($SecurityLevel -eq "AuthAndPriv" -and (
            -not $AuthPassword -or 
            -not $PrivPassword )) 
        {

            # Generate Terminateing error
            $ExceptionMessage = "The -SecurityLevel Parameter was set to 'AuthAndPriv', but did not include -AuthPassword and/or -PrivPassword Parameters."
            $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException MissingRequiredParameters InvalidArgument 'SecurityLevel' Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }

    }

    Process
    {

        if ($PSBoundParameters['AuthPassword'])
        {

            $_DecryptAuthPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($AuthPassword))

        }

        if ($PSBoundParameters['PrivPassword'])
        {

            $_DecryptPrivPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($PrivPassword))

        }

        if (-not $ApplianceSnmpUser)
        {

            if ($SecurityLevel -ne "None")
            {

                if ($PSBoundParameters['AuthPassword'])
                {

                    '[{0}] Adding Auth Password' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_DecryptAuthPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($AuthPassword))
                    $_AuthPasswordConnectionAttributes = New-Object HPOneView.Library.GenericAttributes('SnmpV3AuthorizationPassword', $_DecryptAuthPassword, 'SecuritySensitive')

                    [void]$_CredentialsCol.Add($_AuthPasswordConnectionAttributes)

                }

                if ($PSBoundParameters['PrivPassword'])
                {

                    '[{0}] Adding Privacy Password' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_DecryptPrivPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($PrivPassword))
                    $_PrivPasswordConnectionAttributes = New-Object HPOneView.Library.GenericAttributes('SnmpV3PrivacyPassword', $_DecryptAuthPassword, 'SecuritySensitive')

                    [void]$_CredentialsCol.Add($_PrivPasswordConnectionAttributes)

                }

            }

            else
            {

                '[{0}] Creating an SNMPv3 user without authentication or privacy password.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            
            New-Object HPOneView.Networking.SnmpV3User ($Username, $_CredentialsCol, $SnmpAuthProtocolEnum[$AuthProtocol], $SnmpPrivProtocolEnum[$PrivProtocol])
            
        }

        else
        {

            $_NewSnmpV3User = New-Object HPOneView.Appliance.SnmpV3User ($Username, 
                                                                         $Snmpv3UserAuthLevelEnum[$SecurityLevel], 
                                                                         $SnmpAuthProtocolEnum[$AuthProtocol],
                                                                         $_DecryptAuthPassword,
                                                                         $ApplianceSnmpV3PrivProtocolEnum[$PrivProtocol],
                                                                         $_DecryptPrivPassword)

            ForEach ($_appliance in $ApplianceConnection)
            {

                '[{0}] Adding SNMPv3 User to: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $ApplianceSnmpV3UsersUri -Method POST -Body $_NewSnmpV3User -Hostname $_appliance

                    $_SnmpV3User = New-Object HPOneView.Appliance.SnmpV3User ($_resp.userName, 
                                                                              $_resp.securityLevel, 
                                                                              $_resp.authenticationProtocol,
                                                                              $null,
                                                                              $_resp.privacyProtocol,
                                                                              $null,
                                                                              $_resp.id,
                                                                              $_resp.created,
                                                                              $_resp.modified,
                                                                              $_resp.eTag,
                                                                              $_resp.uri)

                    $_SnmpV3User | Add-Member -NotePropertyName ApplianceConnection -NotePropertyValue $_resp.ApplianceConnection

                    $_SnmpV3User

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVSnmpV3User
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,
    
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'ApplianceSnmpUser') 
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        $_Uri = $ApplianceSnmpV3UsersUri

        if ($Name)
        {

            $_operator = 'eq'

            if ($Name.Contains('*'))
            {

                $_operator = 'matches'

            } 

            $_Uri = "{0}?filter=userName {1} '{2}'" -f $_Uri, $_operator, $Name.Replace('*', '%25')

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_Uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_resp.Count -eq 0 -and $Name)
            {


                $_Message    = "SNMPv3 User '{0}' was not found on {1} Appliance Connection." -f $Name, $_appliance.Name 
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.SnmpV3UserResourceException SnmpV3UserNotFound ObjectNotFound "Name" -Message $_Message
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_entry in $_resp.members)
                {

                    $_SnmpV3User = New-Object HPOneView.Appliance.SnmpV3User($_entry.userName, 
                                                                            $_entry.securityLevel, 
                                                                            $_entry.authenticationProtocol,
                                                                            "",
                                                                            $_entry.privacyProtocol,
                                                                            "",
                                                                            $_entry.id,
                                                                            $_entry.created,
                                                                            $_entry.modified,
                                                                            [String]$_entry.eTag,
                                                                            $_entry.uri)

                    $_SnmpV3User | Add-Member -NotePropertyName ApplianceConnection -NotePropertyValue $_entry.ApplianceConnection

                    $_SnmpV3User

                }                

            }            

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVSnmpV3User
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.SnmpV3User]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_ResourceCol = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        }

        "[{0}] SNMPv3 User object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Username | Write-Verbose

        $RemoveMessage = "Remove SNMPv3 user '{0}'" -f $InputObject.Username

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, $RemoveMessage))
        {   
                        
            Try
            {
            
                Send-HPOVRequest -Uri $InputObject.uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                if ($_.Exception.Message -match "Supplied SNMPv3 user id is invalid. Please provide a valid SNMPv3 User id and retry.")
                {

                    $ExceptionMessage = "The SNMPv3 user you are trying to remove is associated with an existing SNMPv3 Trap Destination. Please remove the trap destination prior to attempting to remove the user."
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.SnmpV3UserResourceException InvalidOperation InvalidOperation "InputObject" -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceSnmpV3EngineId
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
                    
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $ApplianceSnmpV3EngineIdUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError

            }

            New-Object HPOneView.Appliance.SnmpV3EngineId ($_resp.value, $_resp.uri, $_resp.ApplianceConnection)
        
        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceSnmpV3EngineId
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [String]$EngineID,
                    
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if (-not ($ApplianceSnmpV3EngineIdValidationPattern.Match($EngineId)).Success)
        {

            $ExceptionMessage = "The provided EngineId value is not the required 16 character length."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidParameter InvalidOperation 'EngineId' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    Process 
    {

         $_Uri = $ApplianceSnmpV3EngineIdUri

        $_UpdatedGlobalSetting = NewObject -GlobalSetting
        $_UpdatedGlobalSetting.name = "applianceSNMPv3EngineId"
        $_UpdatedGlobalSetting.value = $EngineID

        "[{0}] Updating applianceSNMPv3EngineId setting: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EngineID | Write-Verbose

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_Uri -Method PUT -Body $_UpdatedGlobalSetting -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            New-Object HPOneView.Appliance.SnmpV3EngineId ($_resp.value, $_resp.uri, $_resp.ApplianceConnection)
        
        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceTrapDestination
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Destination,

        [Parameter (Mandatory = $false)]
        [ValidateSet ('SNMPv1', 'SNMPv3')]
        [Array]$Type,
                    
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        if (-not $PSBoundParameters['Type'])
        {

            $Type = @('SNMPv1','SNMPv3')

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            $SnmpTrapDestinationCol = [System.Collections.ArrayList]::new()

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Switch ($Type)
            {

                'SNMPv1'
                {

                    # This code does not work. Will need to create a collection of results and do PowerShell Linq-style filtering

                    $_Uri = $ApplianceSnmpV1TrapDestUri                

                    Try
                    {

                        $_ApplianceSnmpV1trapDestinations = Send-HPOVRequest -Uri $_Uri -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    if ($Destination)
                    {

                        if ($Destination.Contains('*'))
                        {

                            $_ApplianceSnmpV1trapDestinations.members = $_ApplianceSnmpV1trapDestinations.members | Where-Object destination -matches $Destination

                        }

                        else
                        {

                            $_ApplianceSnmpV1trapDestinations.members = $_ApplianceSnmpV1trapDestinations.members | Where-Object destination -eq $Destination

                        }

                    }

                    ForEach ($_entry in $_ApplianceSnmpV1trapDestinations.members)
                    {

                        $_SnmpTrap = New-Object HPOneView.Appliance.SnmpV1TrapDestination ($_entry.destination, 
                                                                                           $_entry.port, 
                                                                                           $_entry.communityString, 
                                                                                           $_entry.uri, 
                                                                                           $_entry.ApplianceConnection)

                        [void]$SnmpTrapDestinationCol.Add($_SnmpTrap)

                    }

                }

                'SNMPv3'
                {

                    $_Uri = $ApplianceSnmpV3TrapDestUri

                    if ($Destination)
                    {

                        $_operator = 'eq'

                        if ($Destination.Contains('*'))
                        {

                            $_operator = 'matches'

                        } 

                        $_Uri = "{0}?filter=destinationAddress {1} '{2}'" -f $_Uri, $_operator, $Destination.Replace('*', '%25')

                    }

                    Try
                    {

                        $_ApplianceSnmpV3trapDestinations = Send-HPOVRequest -Uri $_Uri -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    ForEach ($_entry in $_ApplianceSnmpV3trapDestinations.members)
                    {

                        Try
                        {

                            $_SnmpV3User = Send-HPOVRequest -Uri $_entry.userUri -Hostname $_appliance

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        # (string Username, string SecurityLevel, string AuthProtocol, string AuthPassphrase, string PrivateProtocol, string PrivatePassphrase)
                        $_SnmpV3UserObject = New-Object HPOneView.Appliance.SnmpV3User($_SnmpV3User.userName,
                                                                                       $_SnmpV3User.securityLevel,
                                                                                       $_SnmpV3User.authenticationProtocol,
                                                                                       $_SnmpV3User.authenticationPassphrase,
                                                                                       $_SnmpV3User.privacyProtocol,
                                                                                       $_SnmpV3User.privacyPassphrase,
                                                                                       $_SnmpV3User.id,
                                                                                       $_SnmpV3User.created,
                                                                                       $_SnmpV3User.modified,
                                                                                       [String]$_SnmpV3User.eTag,
                                                                                       $_SnmpV3User.uri)

                        # (string TrapDestinationAddress, int Port, string Uri, SnmpV3User SnmpV3User, string SnmpV3UserUri, Library.ApplianceConnection ApplianceConnection )
                        $_SnmpTrap = New-Object HPOneView.Appliance.SnmpV3TrapDestination ($_entry.destinationAddress, 
                                                                                           $_entry.port, 
                                                                                           $_entry.uri, 
                                                                                           $_SnmpV3UserObject,
                                                                                           $_entry.userUri,
                                                                                           $_entry.ApplianceConnection)

                        [void]$SnmpTrapDestinationCol.Add($_SnmpTrap)

                    }

                }

            }
            
            if ($SnmpTrapDestinationCol.Count -eq 0 -and $Destination)
            {

                $_Message = "SNMP Trap Destination '{0}' was not found on {1} Appliance Connection." -f $Destination, $_appliance.Name 
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.SnmpResourceException SnmpTrapDestinationNotFound ObjectNotFound "Destination" -Message $_Message
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                $SnmpTrapDestinationCol.ToArray()

            }

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVApplianceTrapDestination
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'SnmpV3')]
        [ValidateNotNullOrEmpty()]
        [String]$Destination,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'SnmpV3')]
        [ValidateNotNullOrEmpty()]
        [Int]$Port = 162,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$CommunityString,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'SnmpV3')]
        [ValidateSet ('SNMPv1', 'SNMPv3')]
        [String]$Type = 'SNMPv1',
        
        [Parameter (Mandatory, ParameterSetName = 'SnmpV3')]
        [HPOneView.Appliance.SnmpV3User]$SnmpV3User,
                    
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'SnmpV3')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }
    
    Process
    {
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Switch ($Type)
            {

                'SNMPv1'
                {

                    '[{0}] Creating an SNMPv1 trap destination.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    '[{0}] Getting list of existing SNMPv1 trap destinations.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_ExistingTrapDestinations = Send-HPOVRequest -Uri $ApplianceSnmpV1TrapDestUri -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    $_SnmpV1TrapDest = New-Object HPOneView.Appliance.SnmpTrapDestinationValidation($Destination)

                    ForEach ($_entry in $_ExistingTrapDestinations.members)
                    {

                        [void]$_SnmpV1TrapDest.existingDestinations.Add($_entry.destination)

                    }
                    
                    '[{0}] Validating SNMPv1 trap destination.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_resp = Send-HPOVRequest -Uri $ApplianceSnmpV3TrapDestValidationUri -Method POST -Body $_SnmpV1TrapDest -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                    $_Uri = '{0}/{1}' -f $ApplianceSnmpV1TrapDestUri, ($_SnmpV1TrapDest.existingDestinations.Count + 1)

                    $_NewSnmpTrapDestination = New-Object HPOneView.Appliance.NewSnmpV1TrapDestination ($Destination, $Port, $CommunityString, $_Uri)

                }

                'SNMPv3'
                {

                    '[{0}] Creating an SNMPv3 trap destination.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    '[{0}] SNMPv3 User ID: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $SnmpV3User.id | Write-Verbose

                    $_Uri = $ApplianceSnmpV3TrapDestUri

                    $_NewSnmpTrapDestination = New-Object HPOneView.Appliance.NewSnmpV3TrapDestination ($Destination, $Port, $SnmpV3User)

                }

            }

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_Uri -Method POST -Body $_NewSnmpTrapDestination -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            switch ($Type)
            {

                'SNMPv1'
                {

                    New-Object HPOneView.Appliance.SnmpV1TrapDestination ($_resp.destination, 
                                                                            $_resp.port, 
                                                                            $_resp.communityString, 
                                                                            $_resp.uri, 
                                                                            $_resp.ApplianceConnection)

                }

                'SNMPv3'
                {

                    Try
                    {

                        $_SnmpV3User = Send-HPOVRequest -Uri $_resp.userUri -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_SnmpV3UserObject = New-Object HPOneView.Appliance.SnmpV3User($_SnmpV3User.userName,
                                                                                   $_SnmpV3User.securityLevel,
                                                                                   $_SnmpV3User.authenticationProtocol,
                                                                                   $_SnmpV3User.authenticationPassphrase,
                                                                                   $_SnmpV3User.privacyProtocol,
                                                                                   $_SnmpV3User.privacyPassphrase,
                                                                                   $_SnmpV3User.id,
                                                                                   $_SnmpV3User.created,
                                                                                   $_SnmpV3User.modified,
                                                                                   [String]$_SnmpV3User.eTag,
                                                                                   $_SnmpV3User.uri)

                    New-Object HPOneView.Appliance.SnmpV3TrapDestination ($_resp.destinationAddress, 
                                                                        $_resp.port, 
                                                                        $_resp.uri, 
                                                                        $_SnmpV3UserObject,
                                                                        $_resp.userUri,
                                                                        $_resp.ApplianceConnection)
                }

            }

        }        

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVApplianceTrapDestination
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_ResourceCol = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        }

        if ($InputObject -isnot [HPOneView.Appliance.SnmpV3TrapDestination] -and $InputObject -isnot [HPOneView.Appliance.SnmpV1TrapDestination])
        {

            $ExceptionMessage = "The InputObject is not a supported object type. Only HPOneView.Appliance.SnmpV1TrapDestination and HPOneView.Appliance.SnmpV1TrapDestination objects are supported."
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.SnmpResourceException InvalidObjectType InvalidOperation "InputObject" -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        $RemoveMessage = "Remove {0} trap destination '{1}'"

        switch ($InputObject.Gettype().FullName)
        {

            'HPOneView.Appliance.SnmpV3TrapDestination'
            {

                "[{0}] SNMPv3 Trap Destination object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.DestinationAddress | Write-Verbose
                
                $RemoveMessage = $RemoveMessage -f 'SNMPv3', $InputObject.DestinationAddress

            }

            'HPOneView.Appliance.SnmpV1TrapDestination'
            {

                "[{0}] SNMPv1 Trap Destination object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.DestinationAddress | Write-Verbose
                
                $RemoveMessage = $RemoveMessage -f 'SNMPv1', $InputObject.DestinationAddress

            }

        }

        "[{0}] Object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Uri | Write-Verbose
        
        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, $RemoveMessage))
        {   
                        
            Try
            {

                $_Etag = '*'

                if ($null -ne $InputObject.eTag)
                {

                    $_Etag = $InputObject.eTag

                }
            
                Send-HPOVRequest -Uri $InputObject.uri -Method DELETE -AddHeader @{'If-Match' = $_Etag } -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceGlobalSetting 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    [OutputType ([HPOneView.Appliance.GlobalSetting])]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [String]$name,
            
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceGlobalSettingCol = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_settings = Send-HPOVRequest $ApplianceGlobalSettingsUri -Hostname $_appliance

                if ($Name)
                {

                    $_settings.members = $_settings.members | Where-Object name -like $Name

                }

                ForEach ($_setting in $_settings.members)
                {

                    New-Object HPOneView.Appliance.GlobalSetting ($_setting.name,
                                                                  $_setting.value,
                                                                  $_setting.etag,
                                                                  $_setting.created,
                                                                  $_setting.modified,
                                                                  $_setting.group,
                                                                  $_setting.settingCategory,
                                                                  $_setting.uri,
                                                                  $_setting.applianceConnection)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceGlobalSetting 
{

   # .ExternalHelp HPOneView.500.psm1-help.xml
      
    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Pipeline')]
        [Alias ('Object')]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.GlobalSetting]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [String]$Value,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = 'Pipeline')]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            $PipelineInput - $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ApplianceGlobalSettingCol = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput)
        {


            "[{0}] Processing object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

            Try
            {

                $_UpdatedGlobalSetting = NewObject -GlobalSetting
                $_UpdatedGlobalSetting.name = $InputObject.Name
                $_UpdatedGlobalSetting.value = $Value

                "[{0}] Updated Global Setting: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

                $_results = Send-HPOVRequest -Uri $Object.Uri -Method PUT -Body $_UpdatedGlobalSetting -Hostname $Object.ApplianceConnection

                New-Object HPOneView.Appliance.GlobalSetting ($_results.name,
                                                              $_results.value,
                                                              $_results.etag,
                                                              $_results.created,
                                                              $_results.modified,
                                                              $_results.group,
                                                              $_results.settingCategory,
                                                              $_results.uri,
                                                              $_results.applianceConnection)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Getting current global setting value for $Name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_setting = Get-HPOVApplianceGlobalSetting -Name $Name -ApplianceConnection $_appliance -ErrorAction Stop 

                    $_UpdatedGlobalSetting = NewObject -GlobalSetting
                    $_UpdatedGlobalSetting.name = $Name
                    $_UpdatedGlobalSetting.value = $Value

                    "[{0}] Updated Global Setting: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_setting | Write-Verbose

                    $_results = Send-HPOVRequest -Uri $_setting.Uri -Method PUT -Body $_UpdatedGlobalSetting -Hostname $_appliance

                    New-Object HPOneView.Appliance.GlobalSetting ($_results.name,
                                                                  $_results.value,
                                                                  $_results.etag,
                                                                  $_results.created,
                                                                  $_results.modified,
                                                                  $_results.group,
                                                                  $_results.settingCategory,
                                                                  $_results.uri,
                                                                  $_results.applianceConnection)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                
            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceProxy
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Authentication')]
        [ValidateNotNullorEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Authentication')]
        [ValidateNotNullorEmpty()]
        [Int]$Port,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Authentication')]
        [ValidateNotNullorEmpty()]
        [Switch]$Https,

        [Parameter (Mandatory, ParameterSetName = 'Authentication')]
        [ValidateNotNullorEmpty()]
        [String]$Username,

        [Parameter (Mandatory, ParameterSetName = 'Authentication')]
        [ValidateNotNullorEmpty()]
        [SecureString]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Authentication')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Authentication')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        $_ApplianceProxyConfig = NewObject -ApplianceProxy
        $_ApplianceProxyConfig.server   = $Hostname
        $_ApplianceProxyConfig.port     = $Port
        
        if ($PSCmdlet.ParameterSetName -eq 'Authentication')
        {
            
            $_ApplianceProxyConfig.username = $Username
            $_ApplianceProxyConfig.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
        
        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            if ($Https)
            {

                '[{0}] Setting Proxy to HTTPS.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ApplianceProxyConfig.communicationProtocol = 'HTTPS'

                '[{0}] Getting HTTPS certificate from endpoint.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Uri = '{0}/{1}' -f $RetrieveHttpsCertRemoteUri, $Hostname

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_Uri Hostname $_appliance
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            Try
            {

                $_resp = Send-HPOVRequest -uri $ApplianceProxyConfigUri -Method POST -Body $_ApplianceProxyConfig -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)
                
            }

            if ($PSBoundParameters['Async'])
            {

                $_resp

            }

            else
            {

                $_resp | Wait-HPOVTaskComplete

            }            
                
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVApplianceProxy
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            $RemoveMessage = "remove appliance HTTP/HTTPS proxy configuration"

            if ($PSCmdlet.ShouldProcess($_appliance.Name, $RemoveMessage))
            {   
                            
                Try
                {
                
                    $_resp = Send-HPOVRequest -Uri $ApplianceProxyConfigUri -Method DELETE -AddHeader @{'If-Match' = "*" }  -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($PSBoundParameters['Async'])
                {

                    $_resp

                }

                else
                {

                    $_resp | Wait-HPOVTaskComplete

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }    
                
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceProxy
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -uri $ApplianceProxyConfigUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)
                
            }

            New-Object HPOneView.Appliance.ProxyServer ($_resp.server,
                                                        $_resp.port,
                                                        $_resp.communicationProtocol,
                                                        $_resp.username,
                                                        $_resp.ApplianceConnection)
                
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVRemoteSupport
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceRemoteSupportCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            # Get Appliance Remote Support registration
            Try
            {
            
                $_ApplianceRegistration = Send-HPOVRequest -Uri $RemoteSupportRegistrationUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            # Get Appliance Remote Support configuration
            Try
            {
            
                $_ApplianceConfig = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Get Appliance Remote Support Insight Online portal configuration
            Try
            {
            
                $_InsightOnlineConfig = Send-HPOVRequest -Uri $InsightOnlinePortalRegistraionUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_InsightOnlineConfig.userName)
            {

                $_InsightOnlineEnabled = $True

            }

            else
            {

                $_InsightOnlineEnabled = $false

            }

            New-Object HPOneView.Appliance.RemoteSupport.Configuration ($_ApplianceRegistration.registered,
                                                              $_ApplianceConfig.enableRemoteSupport,
                                                              $_ApplianceRegistration.registered,
                                                              $_ApplianceConfig.companyName,
                                                              $_ApplianceConfig.marketingOptIn,
                                                              $_ApplianceConfig.autoEnableDevices,
                                                              $_ApplianceConfig.enableEmailNotification,
                                                              $_InsightOnlineEnabled,
                                                              $_InsightOnlineConfig.userName,
                                                              $_ApplianceConfig.eTag,
                                                              $_ApplianceConfig.created,
                                                              $_ApplianceConfig.modified,
                                                              $_ApplianceConfig.uri,
                                                              $_ApplianceConfig.ApplianceConnection)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVRemoteSupport
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'InsightOnline')]
        [ValidateNotNullorEmpty()]
        [String]$CompanyName,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ParameterSetName = 'InsightOnline')]
        [Switch]$OptimizeOptIn,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ParameterSetName = 'InsightOnline')]
        [Bool]$AutoEnableDevices,

        [Parameter (Mandatory, ParameterSetName = 'InsightOnline')]
        [ValidateNotNullorEmpty()]
        [String]$InsightOnlineUsername,

        [Parameter (Mandatory, ParameterSetName = 'InsightOnline')]
        [ValidateNotNullorEmpty()]
        [SecureString]$InsightOnlinePassword,

        [Parameter (Mandatory, ParameterSetName = 'Enable')]
        [Switch]$Enable,

        [Parameter (Mandatory, ParameterSetName = 'Disable')]
        [Switch]$Disable,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'InsightOnline')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Enable')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Disable')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'InsightOnline')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Enable')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceRemoteSupportCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            Try
            {
            
                $_CurrentConfiguration = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Disable'])
            {

                $_CurrentConfiguration.enableRemoteSupport = $false

            }

            elseif ($PSBoundParameters['Enable'])
            {

                $_CurrentConfiguration.enableRemoteSupport = $true

                # Check to make sure that 1 RS contact is default
                Try
                {

                    RemoteSupportDefaultContactExists $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            else
            {

                # Check to make sure that 1 RS contact is default
                Try
                {

                    RemoteSupportDefaultContactExists $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                switch ($PSBoundParameters.Keys)
                {

                    'CompanyName'
                    {

                        $_CurrentConfiguration.companyName = $CompanyName

                    }

                    'OptimizeOptIn'
                    {

                        $_CurrentConfiguration.marketingOptIn = $OptimizeOptIn

                    }

                    'AutoEnableDevices'
                    {

                        $_CurrentConfiguration.autoEnableDevices = $AutoEnableDevices

                    }

                }

                $_CurrentConfiguration.enableRemoteSupport = $true

            }

            if ($PSCmdlet.ParameterSetName -eq 'InsightOnline')
            {

                $_PortalRegsitrationObject = NewObject -InsightOnlineRegistration
                $_PortalRegsitrationObject.userName = $InsightOnlineUsername
                $_PortalRegsitrationObject.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($InsightOnlinePassword))

                Try
                {
                
                    $_InsightOnlineConfig = Send-HPOVRequest -uri $InsightOnlinePortalRegistraionUri -Method POST -Body $_PortalRestrationObject -Hostname $_appliance.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
            Try
            {
            
                $_UpdatedConfiguration = Send-HPOVRequest -uri $RemoteSupportConfigUri -Method PUT -Body $_CurrentConfiguration -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $Async)
            {

                $_UpdatedConfiguration = $_UpdatedConfiguration | Wait-HPOVTaskComplete

            }

            $_UpdatedConfiguration

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVRemoteSupport
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        
        if (-not $PSBoundParameters['InputObject'])
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_Collection     = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        $_PatchOperation       = NewObject -PatchOperation
        $_PatchOperation.op    = 'replace'
        $_PatchOperation.path  = '/supportEnabled'
        $_PatchOperation.value = $true

        switch ($InputObject.category)
        {

            'server-hardware'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportComputeSettingsUri, $InputObject.uuid

            }

            'enclosures'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportEnclosureSettingsUri, $InputObject.uuid

            }

            default
            {

                # Unsupported
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
            
        }

        try
        {

            $_Resp = Send-HPOVRequest -Uri $_uri -Method PATCH -Body $_PatchOperation -Hostname $ApplianceConnection

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['Async'])
        {

            $_Resp

        }

        else
        {

            Try
            {

                $_Resp | Wait-HPOVTaskComplete

            }

            Catch
            {

                $PSCmdlet.ThrowTerninatingError($_)

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVRemoteSupport
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        
        if (-not $PSBoundParameters['InputObject'])
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_Collection     = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        $_PatchOperation       = NewObject -PatchOperation
        $_PatchOperation.op    = 'replace'
        $_PatchOperation.path  = '/supportEnabled'
        $_PatchOperation.value = $false

        switch ($InputObject.category)
        {

            'server-hardware'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportComputeSettingsUri, $InputObject.uuid

            }

            'enclosures'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportEnclosureSettingsUri,$InputObject.uuid

            }

            default
            {

                # Unsupported
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
            
        }

        try
        {

            $_Resp = Send-HPOVRequest -Uri $_uri -Method PATCH -Body $_PatchOperation -Hostname $ApplianceConnection

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['Async'])
        {

            $_Resp

        }

        else
        {

            Try
            {

                $_Resp | Wait-HPOVTaskComplete

            }

            Catch
            {

                $PSCmdlet.ThrowTerninatingError($_)

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function RemoteSupportDefaultContactExists
{

    [CmdletBinding ()]
    Param 
    (

        [Object]$ApplianceConnection

    )

    Process
    {

        # Check to make sure that 1 RS contact is default
        Try
        {

            $_Contacts = Send-HPOVRequest -Uri $RemoteSupportContactsUri -Hostname $ApplianceConnection

            # No default contact exists, generate terminating error
            if (-not $_Contacts.members.default)
            {

                $ExceptionMessage = 'The appliance {0} does not have a configured default contact. One must exist before enabling Remote Support.' -f $ApplianceConnection
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportException NoDefaultContact InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            }

            '[{0}] Default Contact: ' -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Contacts.members | Where-Object default).uri | Write-Verbose

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }    

}

function Get-HPOVRemoteSupportContact
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default" )]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_RemoteSupportContactsCol = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        ForEach($_appliance in $ApplianceConnection)
        {

            Try
            {

                $_RemoteSupportContacts = Send-HPOVRequest -Uri $RemoteSupportContactsUri -appliance $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Name'])
            {

                [Array]$_RemoteSupportContacts.members = $_RemoteSupportContacts.members | Where-Object { ('{0} {1}' -f $_.firstName, $_.lastName) -like $Name}

                if (-not $_RemoteSupportContacts.members)
                {

                    '[{0}] The "{1}" Remote Support Contact was not found on {2}. Please check the name and try again.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                    $ExceptionMessage = 'The "{0}" Remote Support Contact was not found on {1}. Please check the name and try again.' -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException ObjectNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

            ForEach ($_Contact in $_RemoteSupportContacts.members) 
            {

                $_Contact.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.RemoteSupport.Contact')

                $_Contact

            }

        }

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

    }
    
}

function New-HPOVRemoteSupportContact
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default" )]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('GivenName')]
        [String]$Firstname,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Surname')]
        [String]$Lastname,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Email,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$PrimaryPhone,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$AlternatePhone,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Language = 'en',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Notes,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Default,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_RemoteSupportContactCol = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        $_c = 0

        ForEach($_Connection in $ApplianceConnection)
        {

            $_c++ 

            "[{0}] Processing {1} of {2} Appliance Connection(s)" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_c, ($ApplianceConnection | Measure-Object).Count | Write-Verbose

            $_RemoteSupportContact = NewObject -RemoteSupportContact

            $_RemoteSupportContact.default        = $PSBoundParameters['Default'].IsPresent
            $_RemoteSupportContact.alternatePhone = $AlternatePhone
            $_RemoteSupportContact.email          = $Email
            $_RemoteSupportContact.firstName      = $Firstname
            $_RemoteSupportContact.lastName       = $Lastname
            $_RemoteSupportContact.language       = $Language
            $_RemoteSupportContact.notes          = $Notes
            $_RemoteSupportContact.primaryPhone   = $PrimaryPhone

            $_PatchOp       = NewObject -PatchOperation
            $_PatchOP.op    = 'add'
            $_PatchOP.path  = '/contacts'
            $_PatchOP.value = $_RemoteSupportContact

            Try
            {

                $_Contacts = Send-HPOVRequest -Uri $RemoteSupportContactsUri -Hostname $_Connection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Check to see if there is a default contact, if so, add it as an array to the operation and set its default property to false
            if ($PSBoundParameters['Default'])
            {

                "[{0}] Checking for existing default contact" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($_Contacts.members | Where-Object default)
                {

                    "[{0}] Default contact found: {0} {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Contacts.members | Where-Object default).firstName, ($_Contacts.members | Where-Object default).lastName | Write-Verbose
                    
                    $_DefaultContact = $_Contacts.members | Where-Object default
                    $_DefaultContact.default = $false

                    $_UpdatePatchOp       = NewObject -PatchOperation
                    $_UpdatePatchOp.op    = 'replace'
                    $_UpdatePatchOp.path  = '/contacts/{0}' -f $_DefaultContact.contactKey
                    $_UpdatePatchOp.value = $_DefaultContact

                    $_NewContact = $_PatchOp.PSObject.Copy()

                    $_PatchOp = [System.Collections.ArrayList]::new()
                    [void]$_PatchOp.Add($_NewContact)
                    [void]$_PatchOp.Add($_UpdatePatchOp)

                }

                else
                {

                    "[{0}] No default contact. Configured contacts: {0}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Contacts.count | Write-Verbose

                }

            }

            elseif (-not ($_Contacts.members | Where-Object default) -and -not $PSBoundParameters['Default'])
            {

                "[{0}] No default contacts were present, and new contact was not specified as default. Setting it as Default contact." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $_PatchOP.value.default = $true

            }
            
            Try
            {

                # Task object is returned dur to PATCH operation
                $_resp = Send-HPOVRequest -Uri $RemoteSupportUri -Method PATCH -Body $_PatchOp -Hostname $_Connection | Wait-HPOVTaskComplete

                # If not successful, generate terminating error
                if ($_resp.taskState -ne 'Completed')
                {

                    $ExceptionMessage = [String]::Join(' ', $_resp.taskErrors.Message)
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidResult InvalidResult "Contact" -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            Try
            {

                # Get newly created contact
                $_Contacts = Send-HPOVRequest -Uri $RemoteSupportContactsUri -Hostname $_Connection

                $_NewContact = $_Contacts.members | Where-Object { ('{0} {1}' -f $_.firstName, $_.lastName) -like ('{0} {1}' -f $Firstname, $Lastname) }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_NewContact.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.RemoteSupport.Contact')

            $_NewContact

        }

    }

    End
    {

        "Done." | Write-Verbose

    }

}

function Set-HPOVRemoteSupportPrimaryContact
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Contact')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process 
    {

        "[{0}] Remote Support Contact Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        If ($InputObject.type -eq 'Contact')
        {

            If (-not ($InputObject.ApplianceConnection))
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else
        {

            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'Contact'. Please check the object provided and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        Try
        {

            $InputObject.default = $true

            $_PatchOp = NewObject -PatchOperation
            $_PatchOp.op = 'replace'
            $_PatchOp.path = "/contacts/{0}" -f $InputObject.contactKey
            $_PatchOp.value = $InputObject
        
            Send-HPOVRequest -Uri $RemoteSupportUri -Method PATCH -Body $_PatchOp -Hostname $InputObject.ApplianceConnection | Wait-HPOVTaskComplete

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVRemoteSupportContact
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Contact')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_RemoteSupportContactsCol = [System.Collections.ArrayList]::new()
        $_TaskCollection           = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Remote Support Contact Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

            If ($InputObject.type -eq 'Contact')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_RemoteSupportContactsCol.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'Contact'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Processing Contact Name {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

                Try
                {

                    $_Contact = Get-HPOVRemoteSupportContact -ApplianceConnection $_appliance | Where-Object firstName -eq $InputObject

                    $_Contact | ForEach-Object {

                        [void]$_RemoteSupportContactsCol.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_contact in $_RemoteSupportContactsCol) 
        {

            $Name          = "{0} {1}" -f $_contact.firstName, $_contact.lastName
            $RemoveMessage = "Remove Remote Support Contact '{0}'" -f $Name

            if ($_contact.default)
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException UnableToRemoveDefaultContact InvalidOperation "Contact" -TargetType 'PSObject' -Message ("The Contact resource '{0}' is currently the default. The removal of the Default Contact is not supported. If you wish to remove this contact, please set another contact as the Default first." -f $Name)
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                if ($PSCmdlet.ShouldProcess($_contact.ApplianceConnection,$RemoveMessage))
                {   
                             
                    Try
                    {
                    
                        $_task = Send-HPOVRequest -Uri $_contact.uri -Method DELETE -Hostname $_contact.ApplianceConnection -AddHeader @{'If-Match' = $_contact.eTag}

                        [void]$_TaskCollection.Add($_task)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSBoundParameters['WhatIf'])
                {

                    "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else
                {

                    "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }
            
        }

        Return $_TaskCollection

    }

}

function Get-HPOVRemoteSupportPartner
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_uri = $RemoteSupportChannelPartnersUri

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($Name)
            {

                [Array]$_resp.members = $_resp.members | Where-Object name -match $Name

                if ($_resp.members.count -eq 0)
                {

                    $ExceptionMessage = "Unable to locate {0} on Appliance Connection {1}." -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException RemoteSupportContactNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                } 

            }
            
            $_resp.members | ForEach-Object {

                $_.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.RemoteSupport.Partner')

            }

            $_resp.members

        }        

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVRemoteSupportPartner
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateSet ('Support','Reseller')]
        [String]$Type,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Int]$PartnerId,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Default,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }

    Process
    {

        $_RemoteSupportPartnerObject             = NewObject -RemoteSupportPartner
        $_RemoteSupportPartnerObject.id          = $PartnerId;
        $_RemoteSupportPartnerObject.default     = $Default.IsPresent;
        $_RemoteSupportPartnerObject.partnerType = $Type.ToUpper()

        "[{0}] Validating PartnerID: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PartnerId | Write-Verbose

        # Validate PartnerID
        Try
        {

            $_resp = Send-HPOVRequest -Uri $RemoteSupportChannelPartnersValidatorUri -Method POST -Body $PartnerId.ToString() -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Try
        {

            $_resp = Send-HPOVRequest -Uri $RemoteSupportChannelPartnersUri -Method POST -Body $_RemoteSupportPartnerObject -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.RemoteSupport.Partner')
        $_resp

    }

    End
    {

        "Done." | Write-Verbose

    }

}

function Remove-HPOVRemoteSupportPartner
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Partner')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_RemoteSupportPartnerCol = [System.Collections.ArrayList]::new()
        $_TaskCollection          = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Remote Support Contact Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ($InputObject.type -eq 'ChannelPartner')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_RemoteSupportPartnerCol.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'ChannelPartner'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Processing Contact Name {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Contact | Write-Verbose

                Try
                {

                    $_Partner = Get-HPOVRemoteSupportPartner -Name $InputObject -ApplianceConnection $_appliance -ErrorAction Stop

                    $_Partner | ForEach-Object {

                        [void]$_RemoteSupportPartnerCol.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_partner in $_RemoteSupportPartnerCol) 
        {

            $RemoveMessage = "Remove Remote Support Channel Partner '{0}'" -f $_partner.Name

            if ($PSCmdlet.ShouldProcess($_partner.ApplianceConnection,$RemoveMessage))
            {   
                            
                Try
                {
                
                    Send-HPOVRequest -Uri $_partner.uri -Method DELETE -Hostname $_partner.ApplianceConnection -addHeader @{'If-Match' = $_partner.eTag}

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
                        
        }

    }

}

function Get-HPOVRemoteSupportSetting
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default" )]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process 
    {

        switch ($InputObject.category)
        {

            'server-hardware'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportComputeSettingsUri, $InputObject.uuid

            }

            'enclosures'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportEnclosureSettingsUri,$InputObject.uuid

            }

            default
            {

                # Unsupported
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        Try
        {

            $_ResourceRemoteSupportSettings = Send-HPOVRequest -uri $_uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_ResourceRemoteSupportSettings | Add-Member -NotePropertyName ResourceName -NotePropertyValue $InputObject.name
        $_ResourceRemoteSupportSettings | Add-Member -NotePropertyName ResourceType -NotePropertyValue $InputObject.category

        ForEach ($_EnumKey in $RemoteSupportResourceSettingEnum.GetEnumerator())
        {

            $_Setting    = $null
            $EnumKeyName = $_EnumKey.Name
            $Uri         = $_ResourceRemoteSupportSettings.$EnumKeyName

            if ($Uri)
            {

                'Processing: {0}' -f $Uri, $EnumKeyName | Write-Verbose

                Try
                {

                    $_Setting = Send-HPOVRequest -Uri $Uri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            else
            {

                '{0} contains a null value.' -f $EnumKeyName | Write-Verbose

            }        
            
            $_ResourceRemoteSupportSettings | Add-Member -NotePropertyName $_EnumKey.Value -NotePropertyValue $_Setting

        }

        $_ResourceRemoteSupportSettings.PSObject.TypeNames.Insert(0,'HPOneView.RemoteSupport.ResourceSetting')

        $_ResourceRemoteSupportSettings

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVRemoteSupportSetting
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]

    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$PrimaryContact,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$SecondaryContact,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$ServicePartner,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$Reseller,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('PackagedSupport', 'SupportAgreement')]
        [String]$ContractType,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$SupportID,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$NewSerialNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$NewProductNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Switch]$Enabled,

        [Parameter (Mandatory, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Switch]$Disabled,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        $_RemoteSupportSettingsToSet = [System.Collections.ArrayList]::new()

        switch ($InputObject.category)
        {

            'server-hardware'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportComputeSettingsUri, $InputObject.uuid

            }

            'enclosures'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportEnclosureSettingsUri, $InputObject.uuid

            }

            default
            {

                # Unsupported
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
            
        }

        Switch ($PSBoundParameters.Keys)
        {

            'PrimaryContact'
            {

                if ($PrimaryContact.Type -ne 'Contact')
                {

                    $ExceptionMessage = 'The PrimaryContact object is not a valid Remote Support Contact.'
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportContactException InvalidPrimaryContact InvalidArgument "InputObject" -TargetType $PrimaryContact.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_PrimaryContactOp = NewObject -PatchOperation
                $_PrimaryContactOp.op    = 'replace'
                $_PrimaryContactOp.path  = '/primaryContactUri'
                $_PrimaryContactOp.value = $PrimaryContact.uri

                [Void]$_RemoteSupportSettingsToSet.Add($_PrimaryContactOp)
                
            }

            'SecondaryContact'
            {

                if ($SecondaryContact.Type -ne 'Contact')
                {

                    $ExceptionMessage = 'The SecondaryContact object is not a valid Remote Support Contact.'
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportContactException InvalidSecondaryContact InvalidArgument "InputObject" -TargetType $SecondaryContact.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_SecondaryContactOp = NewObject -PatchOperation
                $_SecondaryContactOp.op    = 'replace'
                $_SecondaryContactOp.path  = '/secondaryContactUri'
                $_SecondaryContactOp.value = $SecondaryContact.uri

                [Void]$_RemoteSupportSettingsToSet.Add($_SecondaryContactOp)
                
            }

            'Reseller'
            {

                if ($Reseller.Type -ne 'ChannelPartner' -or $Reseller.partnerType -ne 'RESELLER')
                {

                    $ExceptionMessage = 'The Reseller object is not a valid Remote Support reseller partner.'
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportPartnerException InvalidReseller InvalidArgument "InputObject" -TargetType $Reseller.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_ResellerOp = NewObject -PatchOperation
                $_ResellerOp.op    = 'replace'
                $_ResellerOp.path  = '/salesChannelPartnerUri'
                $_ResellerOp.value = $Reseller.uri

                [Void]$_RemoteSupportSettingsToSet.Add($_ResellerOp)
                
            }

            'ServicePartner'
            {
                
                if ($ServicePartner.Type -ne 'ChannelPartner' -or $ServicePartner.partnerType -ne 'SUPPORT')
                {

                    $ExceptionMessage = 'The Reseller object is not a valid Remote Support suport partner.'
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportPartnerException InvalidServicePartner InvalidArgument "InputObject" -TargetType $ServicePartner.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_ServicePartnerOp = NewObject -PatchOperation
                $_ServicePartnerOp.op    = 'replace'
                $_ServicePartnerOp.path  = '/supportChannelPartnerUri'
                $_ServicePartnerOp.value = $ServicePartner.uri

                [Void]$_RemoteSupportSettingsToSet.Add($_ServicePartnerOp)
                
            }

            'SupportID'
            {

                $_SupportIDOp = NewObject -PatchOperation
                $_SupportIDOp.op    = 'replace'
                $_SupportIDOp.path  = '/entitlement'
                $_SupportIDOp.value = [PSCustomOBject]@{

                    obligationType = $ContractType;
                    obligationId   = $SupportID

                }

                [Void]$_RemoteSupportSettingsToSet.Add($_SupportIDOp)
                
            }

            'NewSerialNumber'
            {

                $_NewSerialNumberOp = NewObject -PatchOperation
                $_NewSerialNumberOp.op    = 'replace'
                $_NewSerialNumberOp.path  = '/enteredSerialNumber'
                $_NewSerialNumberOp.value = $NewSerialNumber

                [Void]$_RemoteSupportSettingsToSet.Add($_NewSerialNumberOp)
                
            }

            'NewProductNumber'
            {

                $_NewProductNumberOp = NewObject -PatchOperation
                $_NewProductNumberOp.op    = 'replace'
                $_NewProductNumberOp.path  = '/enteredProductNumber'
                $_NewProductNumberOp.value = $NewProductNumber

                [Void]$_RemoteSupportSettingsToSet.Add($_NewProductNumberOp)
                
            }
            
        }

        if ($PSBoundParameters['Enabled'])
        {

            $_EnableOp = NewObject -PatchOperation
            $_EnableOp.op    = 'replace'
            $_EnableOp.path  = '/supportEnabled'
            $_EnableOp.value = $true

            [Void]$_RemoteSupportSettingsToSet.Add($_EnableOp)

        }

        elseif ($PSBoundParameters['Disabled'])
        {

            $_DisableOp = NewObject -PatchOperation
            $_DisableOp.op    = 'replace'
            $_DisableOp.path  = '/supportEnabled'
            $_DisableOp.value = $false

            [Void]$_RemoteSupportSettingsToSet.Add($_DisableOp)

        }

        Try
        {

            $_resp = Send-HPOVRequest -Uri $_uri -Method PATCH -Body $_RemoteSupportSettingsToSet -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['Async'])
        {

            $_resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVRemoteSupportDataCollectionSchedule
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('AHS','Basic')]
        [String]$Type,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [DateTime]$DateTime,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SchedulesToUpdate = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach($_Appliance in $ApplianceConnection)
        {

            # Get the default schedules on the appliance
            Try
            {

                $_Schedules = Send-HPOVRequest -Uri $RemoteSupportDataCollectionScheduleUri -Hostname $_Appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Type'])
            {

                $_Type = 'AHS','Basic'

            }

            else
            {

                $_Type = $Type

            }

            Switch ($_Type)
            {

                'AHS'
                {

                    $_schedule = $_Schedules.members | Where-Object serviceName -eq 'Active_Health_Service_Collection'

                    "[{0}] Processing schedule: {1}({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_schedule.scheduleName, $_schedule.serviceName | Write-Verbose
                    $_schedule.hourOfDay = [Int]$DateTime.Hour
                    $_schedule.minute    = $DateTime.Minute    
                    $_schedule.dayOfWeek = [Int]$DateTime.DayOfWeek + 1 # Needs to be a value of 1 through 7. Windows defaults to 0 - 6.

                    $_PatchOperation = NewObject -PatchOperation

                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/schedules/{0}' -f $_schedule.taskKey
                    $_PatchOperation.value = $_schedule

                    [void]$_SchedulesToUpdate.Add($_PatchOperation)        
                    
                }

                'Basic'
                {

                    $_schedule = $_Schedules.members | Where-Object serviceName -eq 'Server_Basic_Configuration_Collection'

                    "[{0}] Processing schedule: {1}({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_schedule.scheduleName, $_schedule.serviceName | Write-Verbose
                    $_schedule.hourOfDay = [Int]$DateTime.Hour
                    $_schedule.minute    = $DateTime.Minute    
                    $_schedule.dayOfMonth = [Int]$DateTime.Day

                    $_PatchOperation = NewObject -PatchOperation

                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/schedules/{0}' -f $_schedule.taskKey
                    $_PatchOperation.value = $_schedule

                    [void]$_SchedulesToUpdate.Add($_PatchOperation)        

                }
                
            }

            Try
            {

                $_resp = Send-HPOVRequest -Uri $RemoteSupportUri -Method PATCH -Body $_SchedulesToUpdate -Hostname $_Appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Async'])
            {

                $_resp

            }

            else
            {

                $_resp | Wait-HPOVTaskComplete

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVRemoteSupportDataCollectionSchedule
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default")]
    Param 
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('AHS','Basic')]
        [String]$Type,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach($_Appliance in $ApplianceConnection)
        {

            # Get the default schedules on the appliance
            Try
            {

                $_Schedules = Send-HPOVRequest -Uri $RemoteSupportDataCollectionScheduleUri -Hostname $_Appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Type'])
            {

                $_Type = 'AHS','Basic'

            }

            else
            {

                $_Type = $Type

            }

            Switch ($_Type)
            {

                'AHS'
                {

                    $_Schedules.members | Where-Object serviceName -eq 'Active_Health_Service_Collection' | ForEach-Object {

                        New-Object HPOneView.Appliance.RemoteSupport.Schedule($_.scheduleName,
                                                                                $_.repeatOption,
                                                                                $_.hourOfDay,
                                                                                $_.minute,
                                                                                [DayOfWeek]$_.dayOfWeek,
                                                                                $_.ApplianceConnection)

                    }
                    
                }

                'Basic'
                {

                    $_Schedules.members | Where-Object serviceName -eq 'Server_Basic_Configuration_Collection' | ForEach-Object {

                        New-Object HPOneView.Appliance.RemoteSupport.Schedule($_.scheduleName,
                                                                              $_.repeatOption,
                                                                              $_.hourOfDay,
                                                                              $_.minute,
                                                                              $_.dayOfMonth,
                                                                              $_.ApplianceConnection)

                    }

                }
                
            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Start-HPOVRemoteSupportCollection
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,
        
        [Parameter (Mandatory)]
        [ValidateSet ('AHS', 'Basic')]
        [String]$Type,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Switch]$Async,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SchedulesToUpdate = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $_DataCollection = [PSCustomObject]@{
            type           = "CollectionType";
            collectionType = "AHS"
        }

        switch ($InputObject.category)
        {

            'enclosures'
            {

                $_DataCollection.collectionType = 'Basic'
                $_Uri = '{0}?deviceID={1}&category=enclosures' -f $RemoteSupportDataCollectionsUri, $InputObject.uuid

            }

            'server-hardware'
            {

                $_DataCollection.collectionType = $RemoteSupportCollectionEnum[$Type]

                $_Uri = '{0}?deviceID={1}&category=server-hardware' -f $RemoteSupportDataCollectionsUri, $InputObject.uuid

            }

            ${ResourceCategoryEnum.ServerProfile}
            {

                if ($null -ne $InputObject.serverHardwareUri)
                {

                    $_DataCollection.collectionType = $RemoteSupportCollectionEnum[$Type]

                    $_Uri = '{0}?deviceID={1}&category=server-hardware' -f $RemoteSupportDataCollectionsUri, $InputObject.uuid

                }

                else
                {

                    $ExceptionMessage = 'The {0} Server Profile resource is not assigned to a compute resource.' -f $InputObject.category, $InputObject.name 
                    $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }                

            }

            default
            {

                # Unsupported
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware", "server-profile" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        if ($_Uri)
        {

            Try
            {
    
                $_resp = Send-HPOVRequest -Uri $_Uri -Method POST -Body $_DataCollection -Hostname $ApplianceConnection
    
            }
    
            Catch
            {
    
                $PSCmdlet.ThrowTerminatingError($_)
    
            }
    
            if ($PSBoundParameters['Async'])
            {
    
                $_resp
    
            }
    
            else
            {
    
                $_resp | Wait-HPOVTaskComplete
    
            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVRemoteSupportEntitlementStatus
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        
        if (-not $PSBoundParameters['InputObject'])
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        $_ResourcesToProcess = [System.Collections.ArrayList]::new()

        switch ($InputObject.category)
        {

            $ResourceCategoryEnum.Enclosure
            {

                "[{0}] Processing Enclosure: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
                
                [void]$_ResourcesToProcess.Add($InputObject.PSObject.Copy())

            }

            $ResourceCategoryEnum.LogicalEnclosure
            {

                "[{0}] Processing Logical Enclosure: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                ForEach ($_Uri in $InputObject.enclosureUris)
                {

                    Try
                    {
        
                        $_Resource = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection                
        
                    }
        
                    Catch
                    {
        
                        $PSCmdlet.ThrowTerminatingError($_)
        
                    }

                    [void]$_ResourcesToProcess.Add($_Resource)

                }

            }

            $ResourceCategoryEnum.EnclosureGroup
            {

                "[{0}] Processing Enclosure Group, and getting associated Logical Enclosures: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
                
                $_Uri = '{0}?parentUri={1}&name=ENCLOSURE_GROUP_TO_LOGICAL_ENCLOSURE' -f $AssociationsUri, $InputObject.uri
    
                Try
                {
    
                    [Array]$_AssoiatedLEs = (Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection).members | ForEach-Object { Send-HPOVRequest $_.childUri -Hostname $_.ApplianceConnection}

                    ForEach ($_Uri in $InputObject.enclosureUris)
                    {
    
                        Try
                        {
            
                            $_Resource = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection                
            
                        }
            
                        Catch
                        {
            
                            $PSCmdlet.ThrowTerminatingError($_)
            
                        }
    
                        [void]$_ResourcesToProcess.Add($_Resource)
    
                    }
    
                }
    
                Catch
                {
    
                    $PSCmdlet.ThrowTerminatingError($_)
    
                }

            }

            $ResourceCategoryEnum.ServerHardware
            {

                "[{0}] Processing server hardware device: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                [void]$_ResourcesToProcess.Add($InputObject.PSObject.Copy())

            }

            $ResourceCategoryEnum.ServerProfile
            {

                "[{0}] Processing server profile: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                if ($Null -eq $InputObject.serverHardwareUri)
                {

                    "[{0}] Server Profile is currently unassigned." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                }

                else
                {

                    Try
                    {
        
                        $_Resource = Send-HPOVRequest -Uri $InputObject.serverHardwareUri -Hostname $ApplianceConnection                
        
                    }
        
                    Catch
                    {
        
                        $PSCmdlet.ThrowTerminatingError($_)
        
                    }

                    [void]$_ResourcesToProcess.Add($_Resource)

                }                

            }

            default
            {

                # Generae error of unsupported resource
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware"., "server-profile", "enclosure-group", "logical-enclosure" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'String' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        ForEach ($_Resource in $_ResourcesToProcess)
        {

            "[{0}] Getting Remote Support status for: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Resource.name | Write-Verbose

            Try
            {

                $_RemoteSupportStatus = Send-HPOVRequest -Uri $_Resource.remoteSupportUri -Hostname $ApplianceConnection                

            }

            Catch [HPOneView.Appliance.RemoteSupportResourceException]
            {

                $ExceptionMessage = "The device {0} is not eligible for Remote Support." -f $_Resource.name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportResourceException DeviceNotEligible InvalidOperation "Server" -Message $ExceptionMessage -InnerException $_.Exception.InnerException
                $PSCmdlet.WriteError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_RemoteSupportStatus.supportEnabled)
            {

                "[{0}] Resource has Remote Support enabled, getting entitlement information." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_ResourceEntitlementStatus = Send-HPOVRequest -Uri $_RemoteSupportStatus.entitlementUri -Hostname $ApplianceConnection

                }

                Catch
                {
    
                    $PSCmdlet.ThrowTerminatingError($_)
    
                }

                if ($null -eq $_ResourceEntitlementStatus.obligationStartDate)
                {

                    [DateTime]$_ResourceEntitlementStatus.obligationStartDate = '01/01/1970'
                    
                }

                if ($null -eq $_ResourceEntitlementStatus.obligationEndDate)
                {

                    [DateTime]$_ResourceEntitlementStatus.obligationEndDate = '01/01/1970'

                }

                if ($null -eq $_ResourceEntitlementStatus.offerStartDate)
                {

                    [DateTime]$_ResourceEntitlementStatus.offerStartDate = '01/01/1970'

                }

                if ($null -eq $_ResourceEntitlementStatus.offerEndDate)
                {

                    [DateTime]$_ResourceEntitlementStatus.offerEndDate = '01/01/1970'

                }

                # Get resource name
                switch ($_Resource.type)
                {

                    'server-hardware'
                    {

                        if ($null -ne $_Resource.serverName)
                        {

                            $_ResourceName = $_Resource.serverName

                        }

                        else
                        {

                            $_ResourceName = $_Resource.name

                        }

                    }

                    'enclosures'
                    {

                        $_ResourceName = $_Resource.name

                    }

                }

                $_EntitlementStatus = New-Object HPOneView.RemoteSupport.ContractAndWarrantyStatus ($_ResourceName,
                                                                                                    $_Uri,
                                                                                                    $_Resource.serialNumber,
                                                                                                    $_ResourceEntitlementStatus.entitlementPackage,
                                                                                                    $_ResourceEntitlementStatus.entitlementStatus,
                                                                                                    $_ResourceEntitlementStatus.offerStatus,
                                                                                                    $_ResourceEntitlementStatus.coverageDays,
                                                                                                    $_ResourceEntitlementStatus.coverageHoursDay1to5,
                                                                                                    $_ResourceEntitlementStatus.coverageHoursDay6,
                                                                                                    $_ResourceEntitlementStatus.coverageHoursDay7,
                                                                                                    $_ResourceEntitlementStatus.responseTimeDay1to5,
                                                                                                    $_ResourceEntitlementStatus.responseTimeDay6,
                                                                                                    $_ResourceEntitlementStatus.responseTimeDay7,
                                                                                                    [DateTime]$_ResourceEntitlementStatus.obligationStartDate,
                                                                                                    [DateTime]$_ResourceEntitlementStatus.obligationEndDate,
                                                                                                    [DateTime]$_ResourceEntitlementStatus.offerStartDate,
                                                                                                    [DateTime]$_ResourceEntitlementStatus.offerEndDate,
                                                                                                    $_ResourceEntitlementStatus.countryCode,
                                                                                                    $_ResourceEntitlementStatus.obligationType,
                                                                                                    $_ResourceEntitlementStatus.entitlementKey,
                                                                                                    $_ResourceEntitlementStatus.obligationId,
                                                                                                    $_ResourceEntitlementStatus.coversHolidays,
                                                                                                    $_ResourceEntitlementStatus.isEntitled,
                                                                                                    $_ResourceEntitlementStatus.responseTimeHolidays,
                                                                                                    $_ResourceEntitlementStatus.explanation,
                                                                                                    $_resourceEntitlementStatus.ApplianceConnection
                                                                                                )

            }

            else
            {

                "[{0}] Remote Support is disabled for the resource, returning ." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_EntitlementStatus = New-Object HPOneView.RemoteSupport.ContractAndWarrantyStatus ($_ResourceName,
                                                                                                    $_Uri,
                                                                                                    $_Resource.serialNumber,
                                                                                                    $false,
                                                                                                    'INVALID',
                                                                                                    $_Resource.ApplianceConnection
                                                                                                    )
                
            }

            $_EntitlementStatus

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }    

}

function Update-HPOVRemoteSupportEntitlement
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin
    {

        Write-Warning "Not Implemented."

        Return $null

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        if (-not $PSBoundParameters['InputObject'])
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        $_PatchOperation       = NewObject -PatchOperation
        $_PatchOperation.op    = 'replace'
        $_PatchOperation.path  = '/refreshState'
        $_PatchOperation.value = "RefreshPending"

        switch ($InputObject.category)
        {

            'server-hardware'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportComputeSettingsUri, $InputObject.uuid

            }

            'enclosures'
            {

                $_uri = '{0}/{1}' -f $RemoteSupportEnclosureSettingsUri, $InputObject.uuid

            }

            default
            {

                # Unsupported
                $ExceptionMessage = 'The {0} input object is an unsupported resource category type, "{1}". Only "server-hardware" or "enclosure" resources are supported.' -f $InputObject.category, $InputObject.name 
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
            
        }

        try
        {

            $_Resp = Send-HPOVRequest -Uri $uri -Method PATCH -Body $_PatchOperation -Hostname $ApplianceConnection

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['Async'])
        {

            $_Resp

        }

        else
        {

            Try
            {

                $_Resp | Wait-HPOVTaskComplete

            }

            Catch
            {

                $PSCmdlet.ThrowTerninatingError($_)

            }

        }

    }
    
    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVRemoteSupportDefaultSite
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $_connection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $defaultSiteCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        ForEach($_Connection in $ApplianceConnection)
        {

            Try
            {

                $_defaultSite = Send-HPOVRequest $RemoteSupportDefaultSitesUri -appliance $_Connection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_defaultSite.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.RemoteSupport.DefaultSite')

            [void]$defaultSiteCollection.Add($_defaultSite)

        }

    }

    End 
    {

        return $defaultSiteCollection

    }

}

function Set-HPOVRemoteSupportDefaultSite
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default" )]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('a1')]
        [String]$AddressLine1,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('a2')]
        [String]$AddressLine2,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$City,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Province')]
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$PostalCode,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Country,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$TimeZone,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $_connection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $defaultSiteCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach($_Connection in $ApplianceConnection)
        {

            Try
            {

                $_DefaultSite = Send-HPOVRequest -uri $RemoteSupportDefaultSitesUri -Hostname $_Connection
                $_method      = 'PUT'
                $_uri         = $_DefaultSite.uri
                
                
            }

            Catch 
            {

                if ($_.FullyQualifiedErrorId -match 'ResourceNotFound')
                {

                    $_method      = 'POST'
                    $_uri         = $RemoteSupportDefaultSitesUri
                    $_DefaultSite = NewObject -RemoteSupportSite

                }

                else
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }            

            }

            $_DefaultSite.streetAddress1 = $AddressLine1
            if ($PSBoundParameters['AddressLine2']) { $_DefaultSite.streetAddress2 = $AddressLine2 }
            $_DefaultSite.city           = $City 
            $_DefaultSite.provinceState  = $State
            $_DefaultSite.countryCode    = $Country
            if ($PSBoundParameters['PostalCode']) { $_DefaultSite.postalCode = $PostalCode }            
            $_DefaultSite.timeZone       = $TimeZone
         
            Try
            {

                $_resp = Send-HPOVRequest -method $_method -uri $_uri -body $_defaultSite -Hostname $_Connection

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.RemoteSupport.DefaultSite')

            $_resp

        }

    }

    End 
    {
        
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# // TODO: Get-HPOVRemoteTechnician
# // TODO: Enable-HPOVRemoteTechnician
# // TODO: Disable-HPOVRemoteTechnician
# // TODO: Connect-HPOVRemoteTechnician
# // TODO: Test-HPOVRemoteTechicianConnectivity
# // TODO: Disconnect-HPOVRemoteTechnician
# // TODO: Get-HPOVRemoteTechnicianAcl
# // TODO: New-HPOVRemoteTechnicianAcl
# // TODO: Remove-HPOVRemoteTechnicianAcl

function Get-HPOVBaseline 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "ISOFileName" )]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "ISOFileName")]
        [ValidateNotNullOrEmpty()]
        [Alias ('isoFileName','FileName')]
        [Object]$File,

        [Parameter (Mandatory, ParameterSetName = "BaselineName")]
        [Alias ('name')]
        [ValidateNotNullOrEmpty()]
        [String]$SppName,

        [Parameter (Mandatory = $false, ParameterSetName = "BaselineName")]
        [ValidateNotNullOrEmpty()]
        [String]$Version,

        [Parameter (Mandatory = $false, ParameterSetName = "HotFixesOnly")]
        [Switch]$HotfixesOnly,

        [Parameter (Mandatory = $false, ParameterSetName = "ISOFileName")]
        [Parameter (Mandatory = $false, ParameterSetName = "BaselineName")]
        [Parameter (Mandatory = $false, ParameterSetName = "HotFixesOnly")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "ISOFileName")]
        [Parameter (Mandatory = $false, ParameterSetName = "BaselineName")]
        [Parameter (Mandatory = $false, ParameterSetName = "HotFixesOnly")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $BaselineCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        ForEach($_Connection in $ApplianceConnection)
        {

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_Connection.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            switch ($PSCmdlet.ParameterSetName) 
            {
                
                "BaselineName" 
                {
                
                    "[{0}] SppName Parameter provided: $($SppName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($SppName.Contains('*'))
                    {

                        [Void]$_Query.Add(("fwbaseline_name%3A{0}" -f $SppName.Replace("*", "%2A")))

                    }

                    else
                    {

                        [Void]$_Query.Add(("fwbaseline_name:'{0}'" -f $SppName))

                    } 

                    if ($Version) 
                    {

                        "[{0}] Version Parameter provided: $($version)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                        [Void]$_Query.Add(("fwbaseline_version:'{0}'" -f $Version))
                    
                    }                
            
                }
            
                "ISOFileName" 
                {

                    if ($File) 
                    { 

                        if ($File.EndsWith('.exe') -or $File.EndsWith('.scexe') -or $File.EndsWith('.rpm') -or $File.EndsWith('.zip'))
                        {

                            "[{0}] Looking for hotfix file" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if ($File.Contains('*'))
                            {

                                [Void]$_Query.Add(("fwbaseline_fileName%3A{0}" -f $File.Replace("*", "%2A")))

                            }

                            else
                            {

                                [Void]$_Query.Add(("fwbaseline_fileName:'{0}'" -f $File))

                            }

                        }

                        else
                        {

                            "[{0}] Looking for Baseline ISO file" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if (-not $File.EndsWith('iso'))
                            {

                                $File += '.iso'
                                
                            }

                            if ($File.Contains('*'))
                            {

                                [Void]$_Query.Add(("fwbaseline_isoFileName%3A{0}" -f $File.Replace("*", "%2A")))

                            }

                            else
                            {

                                [Void]$_Query.Add(("fwbaseline_isoFileName:'{0}'" -f $File))

                            }                        

                        }
                    
                    }

                }

                'HotfixesOnly'
                {

                    [Void]$_Query.Add("fwbaseline_bundleType:Hotfix")

                }
            
                default 
                {
            
                    "[{0}] No Parameter provided. Looking for all SPP Baselines." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }
            
            }

            # Build the final URI
            $_uri = '{0}?category=firmware-drivers&sort=name:asc&query={1}' -f $IndexUri, [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                $_BundlesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $_BundlesFromIndexCol)
            {

                if ($PSBoundParameters['File']) 
                {

                    $ExceptionMessage = "The Baseline resource name '{0}' was not found on '{1}' appliance." -f $File, $_Connection.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'File' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                elseif ($PSBoundParameters['SppName'] -and -not $PSBoundParameters['Version']) 
                {

                    $ExceptionMessage = "The Baseline name '{0}' was not found on '{1}' appliance." -f $SppName, $_Connection.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'SppName' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                elseif ($PSBoundParameters['Version']) 
                {

                    $ExceptionMessage = "The Baseline name '{0}' version '{1}' was not found on '{2}' appliance." -f $SppName, $Version, $_Connection.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'SppName' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }            

            # foreach ($_baseline in $_baselines.members)
            foreach ($_baseline in $_BundlesFromIndexCol)
            {
            
                # Inject repository location as a property, should not cause issues with other API calls with the resource
                # $_Locations = [System.Collections.ArrayList]::new()
                $_Locations = [System.Collections.Generic.List[String]]::new()

                ForEach ($_Location in ($_baseline.locations.PSObject.Members | Where-Object { $_.MemberType -eq 'NoteProperty'}))
                {

                    [void]$_Locations.Add($_Location.Value)

                }

                # $_baseline.locations = [String]::Join(', ', $_Locations.ToArray())

                $_FwComponentsList = [System.Collections.Generic.List[HPOneView.Appliance.Baseline+FwComponent]]::new()

                ForEach ($_Component in $_baseline.fwComponents)
                {

                    $_FwComponentsList.Add((New-Object HPOneView.Appliance.Baseline+FwComponent($_Component.name,
                                                                                                $_Component.componentVersion,
                                                                                                $_Component.fileName,
                                                                                                $_Component.swKeyNameList)))

                }

                $_HotFixes = New-Object "System.Collections.Generic.List[HPOneView.Appliance.Baseline+Hotfix]"

                ForEach ($_Hotfix in $_baseline.hotfixes)
                {

                    $_HotFixes.Add((New-Object HPOneView.Appliance.Baseline+HotFix($_Hotfix.hotfixName,
                                                                                   $_Hotfix.releaseDate,
                                                                                   $_Hotfix.resourceId)))
                }

                $_ParentBundle = $null
                
                if ($null -ne $_baseline.parentBundle)
                {

                    $_ParentBundle = New-Object HPOneView.Appliance.Baseline+ParentBaseline($_baseline.parentBundle.parentBundleName, 
                                                                                            $_baseline.parentBundle.releaseDate, 
                                                                                            $_baseline.parentBundle.version)

                }

                $_SupportedOsList = [System.Collections.Generic.List[String]]::new()

                ForEach ($_SupportedOS in $_baseline.supportedOSList)
                {

                    $_SupportedOsList.Add($_SupportedOS)

                }

                switch ($_baseline.bundleType)
                {

                    {'Custom', 'SPP' -contains $_}
                    {

                        [HPOneView.Appliance.Baseline]::new($_baseline.name,
                                                            $_baseline.description,
                                                            $_baseline.status,
                                                            $_baseline.version,
                                                            $_baseline.releaseDate,
                                                            $_baseline.bundleType,
                                                            $_baseline.bundleSize,
                                                            $_baseline.resourceId,
                                                            $_baseline.uuid,
                                                            $_baseline.xmlKeyName,
                                                            $_baseline.isoFileName,
                                                            $_baseline.baselineShortName,
                                                            $_SupportedOsList,
                                                            $_baseline.supportedLanguages,
                                                            $_FwComponentsList,
                                                            $_baseline.state,
                                                            $_baseline.hpsumVersion,
                                                            $_ParentBundle,
                                                            $_HotFixes,
                                                            $_Locations,
                                                            $null,
                                                            $_baseline.uri,
                                                            $_baseline.eTag,
                                                            $_baseline.created,
                                                            $_baseline.modified,
                                                            $_baseline.resourceState,
                                                            $_baseline.scopesUri,
                                                            $_baseline.applianceConnection)

                    }

                    'Hotfix'
                    {

                        [HPOneView.Appliance.BaselineHotfix]::new($_baseline.name,
                                                                  $_baseline.description,
                                                                  $_baseline.status,
                                                                  $_baseline.version,
                                                                  $_baseline.releaseDate,
                                                                  $_baseline.bundleType,
                                                                  $_baseline.bundleSize,
                                                                  $_baseline.resourceId,
                                                                  $_baseline.uuid,
                                                                  $_baseline.xmlKeyName,
                                                                  $_baseline.isoFileName,
                                                                  $_baseline.baselineShortName,
                                                                  $_SupportedOsList,
                                                                  $_baseline.supportedLanguages,
                                                                  $_FwComponentsList,
                                                                  $_baseline.state,
                                                                  $_baseline.hpsumVersion,
                                                                  $_ParentBundle,
                                                                  $_HotFixes,
                                                                  $_Locations,
                                                                  $null,
                                                                  $_baseline.uri,
                                                                  $_baseline.eTag,
                                                                  $_baseline.created,
                                                                  $_baseline.modified,
                                                                  $_baseline.resourceState,
                                                                  $_baseline.scopesUri,
                                                                  $_baseline.applianceConnection,
                                                                  $_baseline.signatureFileName)

                    }

                }

            }

        }

    }

    End 
    {
        
         "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVBaseline 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateScript({Test-Path $_})]
        [Alias ('sppFile')]
        [Object]$File,

        [Parameter (Mandatory = $false)]
        [ValidateScript({Test-Path $_})]
        [Object]$CompSigFile,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['File']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if (-not(Test-Path $File -PathType Leaf))
        {

            $ExceptionMessage = "The baseline file '{0}' was not found. Please check the path and filename." -f $File.Name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineFileNotFound ObjectNotFound 'File' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)                

        }

        if ($File -isnot [System.IO.FileInfo])
        { 
            
            $File = Get-ChildItem -Path $File
            
        }

        if ($PSBoundParameters['CompSigFile'])
        {

            if ($CompSigFile -isnot [System.IO.FileInfo])
            {

                $CompSigFile = Get-ChildItem -Path $CompSigFile

            }

            if ($CompSigFile.Length -le 0)
            {
            
                $ExceptionMessage = "The CompSigFile resource '{0}' file size is 0." -f $CompSigFile.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException ResourceCannotBeZero InvalidArgument 'CompSigFile' -TargetType 'System.IO.FileInfo' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        if ($File.Length -le 0)
        {
        
            $ExceptionMessage = "The File resource '{0}' file size is 0." -f $File.Name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException ResourceCannotBeZero InvalidArgument 'File' -TargetType 'System.IO.FileInfo' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_BaselineExists = $null

            "[{0}] Processing Appliance $($_appliance.Name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Check if the Baseline exists already, instead of waiting for filetransfer to finish
            "[{0}] Checking if Baseline exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_BaselineExists = Get-HPOVBaseline -FileName ($File.BaseName.Replace('.','_') + $File.Extension) -ApplianceConnection $_appliance -ErrorAction SilentlyContinue

            }

            Catch
            {

              $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $_BaselineExists)
            {

                # Start upload file
                Try
                {

                    $_Params = @{
                        URI                 = $ApplianceFwBundlesUri;
                        File                = $File.FullName;
                        ApplianceConnection = $_appliance
                    }

                    if ($PSBoundParameters['Scope'])
                    {

                        $_sb = [System.Collections.ArrayList]::new()

                        ForEach ($_Scope in $Scope)
                        {

                            "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                            [void]$_sb.Add($_Scope.Uri)

                        }

                        $_ScopeHttpHeader = @{'initialScopeUris' = [String]::Join(', ', $_sb.ToArray())}

                        $_Params.Add('AddHeader', $_ScopeHttpHeader)

                    }

                    $AddTask = Upload-File @_Params

                    if ((-not $PSBoundParameters['Async'] -and $PSBoundParameters['CompSigFile']) -or (-not $PSBoundParameters['Async']))
                    {

                        "[{0}] Response is a task resource, calling Wait-HPOVTaskComplete" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $AddTask = $AddTask | Wait-HPOVTaskComplete

                    }

                    # Upload CompSigFile first
                    if ($PSBoundParameters['CompSigFile'])
                    {

                        "[{0}] Adding CompSig file to appliance: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $CompSigFile.Name | Write-Verbose

                        $uploadCompSigTask = Upload-File -Uri ($ApplianceFwCompSigUri -f $CompSigFile.Name) -File $CompSigFile.FullName -ApplianceConnection $_appliance

                        if ($uploadCompSigTask.tastState -eq 'Error')
                        {

                            $ExceptionMessage = "{0}" -f $uploadCompSigTask.taskErrors.message
                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalidCompSigFileUploadOperation InvalidOperation 'CompSigFile' -TargetType 'System.IO.FileInfo' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }
                
                    $AddTask

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($_BaselineExists)
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceAlreadyExists ResourceExists 'File' -Message ("The Baseline '{0}' is already present on the appliance. Please upload a different baseline." -f $File.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Save-HPOVBaseline
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory)]
        [ValidateScript ({Test-Path $_})]
        [System.IO.FileSystem]$Path,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['File']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if (-not(Test-Path $File -PathType Leaf))
        {

            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineFileNotFound ObjectNotFound 'File' -Message ("The baseline file '{0}' was not found. Please check the path and filename." -f $File.Name)
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)                

        }

        if ($File -isnot [System.IO.FileInfo])
        { 
            
            $File = Get-ChildItem -Path $File
            
        }

        if ($File.Length -le 0)
        {
        
            $ExceptionMessage = ("The File resource '{0}' file size is 0." -f $File.Name)
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException ResourceCannotBeZero InvalidArgument 'File' -TargetType 'System.IO.FileInfo' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_BaselineExists = $null

            "[{0}] Processing Appliance $($_appliance.Name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Check if the Baseline exists already, instead of waiting for filetransfer to finish
            "[{0}] Checking if Baseline exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_BaselineExists = Get-HPOVBaseline -FileName ($File.BaseName.Replace('.','_') + $File.Extension) -ApplianceConnection $_appliance -ErrorAction SilentlyContinue

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $_BaselineExists)
            {

                # Start upload file
                Try
                {

                    $_Params = @{
                        URI                 = $ApplianceFwBundlesUri;
                        File                = $File.FullName;
                        ApplianceConnection = $_appliance
                    }

                    if ($PSBoundParameters['Scope'])
                    {

                        $_sb = [System.Collections.ArrayList]::new()

                        ForEach ($_Scope in $Scope)
                        {

                            "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                            [void]$_sb.Add($_Scope.Uri)

                        }

                        $_ScopeHttpHeader = @{'initialScopeUris' = [String]::Join(', ', $_sb.ToArray())}

                        $_Params.Add('AddHeader', $_ScopeHttpHeader)

                    }

                    $task = Upload-File @_Params

                    if (-not($PSBoundParameters['Async']))
                    {

                        "[{0}] Response is a task resource, calling Wait-HPOVTaskComplete" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $task = $task | Wait-HPOVTaskComplete

                    }
                
                    $Task

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($_BaselineExists)
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceAlreadyExists ResourceExists 'File' -Message ("The Baseline '{0}' is already present on the appliance. Please upload a different baseline." -f $File.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function New-HPOVCustomBaseline
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [Object]$SourceBaseline,

        [Parameter (Mandatory)]
        [Array]$Hotfixes,

        [Parameter (Mandatory)]
        [String]$BaselineName,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['SourceBaseline']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        $_CustomBaseline = NewObject -CustomBaseline

        # Validate Source Baseline
        switch ($SourceBaseline.GetType().Name)
        {

            'PSCustomObject'
            {
                
                if ($SourceBaseline.category -ne 'firmware-drivers')
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalidBaselineResource InvalidArgument 'SourceBaseline' -TargetType 'PSObject' -Message "The provided SourceBaseline object is not the required category, 'firmware-drivers'. Please correct the input Parameter."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
                
                "[{0}] Baseline Object Provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Baseline Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $SourceBaseline.shortName | Write-Verbose
                "[{0}] Baseline URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $SourceBaseline.uri | Write-Verbose

            }

            'String'
            {

                "[{0}] Baseline Name Provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),$SourceBaseline | Write-Verbose

                # Get Source Baseline from Baseline Name
                Try
                {

                    $BaselineParamName = $SourceBaseline.Clone()
                    $SourceBaseline = Get-HPOVBaseline -SppName $SourceBaseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                    If (-not $SourceBaseline)
                    {

                        $ExceptionMessage = "The provided SourceBaseline '{0}' was not found." -f $BaselineParamName
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'SourceBaseline' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

        }
        
        # Loop through Hotfixes
        ForEach ($_HotFix in $Hotfixes)
        {

            switch ($_HotFix.GetType().Name)
            {

                'PSCustomObject'
                {
                    
                    if ($_HotFix.category -ne 'firmware-drivers' -and $_HotFix.bundleType -ne 'Hotfix')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalidBaselineResource InvalidArgument 'Hotfixes' -TargetType 'PSObject' -Message "The provided Hotfix object is not the required category and type. Only 'firmware-drivers' category and 'Hotfix' type are allowed. Please correct the input Parameter."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                    
                    "[{0}] Hotfix baseline object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Hotfix baseline Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),$_HotFix.shortName | Write-Verbose
                    "[{0}] Hotfix baseline URI: {1}" -f $MyInvocation.InvocationName.ToString(),$_HotFix.uri | Write-Verbose

                }

                'String'
                {

                    "[{0}] Hotfix Name Provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_HotFix | Write-Verbose

                    # Get Source Baseline from Baseline Name
                    Try
                    {

                        $_HotFixName = $_HotFix.Clone()
                        $_HotFix = Get-HPOVBaseline  -File $_HotFix -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                        If (-not $_HotFix)
                        {

                            $ExceptionMessage = "The provided Hotfix '{0}' was not found." -f $_HotFixName
                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Hotfixes' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

            }

            [void]$_CustomBaseline.hotfixUris.Add($_HotFix.uri)

        }

        $_CustomBaseline.baselineUri        = $SourceBaseline.uri
        $_CustomBaseline.customBaselineName = $BaselineName

        $_Params = @{
            URI      = $ApplianceFwBundlesUri;
            Method   = 'POST';
            Body     = $_CustomBaseline;
            Hostname = $ApplianceConnection.Name
        }

        if ($PSBoundParameters['Scope'])
        {

            $_sb = [System.Collections.ArrayList]::new()

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_sb.Add($_Scope.Uri)

            }

            $_ScopeHttpHeader = @{'initialScopeUris' = [String]::Join(', ', $_sb.ToArray())}

            $_Params.Add('AddHeader', $_ScopeHttpHeader)

        }
        
        # Post the new object to the appliance
        Try
        {

            $_Resp = Send-HPOVRequest -Uri $ApplianceFwDriversUri -Method POST -Body $_CustomBaseline -Hostname $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not($PSBoundParameters['Async']))
        {

            $_Resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_Resp

        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString() | Write-Verbose
    
    }

}

function Restore-HPOVCustomBaseline
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
    
        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskCollection     = [System.Collections.ArrayList]::new()
        $_BaselineCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting all baseline resources" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_baselineresources = Send-HPOVRequest $ApplianceFwBundlesUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            foreach ($_baseline in ($_baselineresources.members | Where-Object bundleType -eq 'Custom' -and state -eq 'Removed'))
            {

                $_CustomBaselineRestore = NewObject -CustomBaselineRestore

                $_CustomBaselineRestore.baselineUri        = $_baseline.uri    
                $_CustomBaselineRestore.customBaselineName = $_baseline.name

                "[{0}] Looking up Associations for '$($_baseline.name) [$($_baseline.uuid)]' custom baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    $_uri = '{0}?parentUri={1}' -f $AssociationsUri, $_baseline.uri

                    $_baselineassociations = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                foreach ($_association in $_baselineassociations.members)
                {

                    "[{0}] Adding '$($_association.childUri)' to object collection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [void]$_CustomBaselineRestore.hotfixUris.Add($_association.childUri)

                }

                "[{0}] Sending request to recreate '$_CustomBaselineRestore.customBaselineName' custom baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $ApplianceFwBundlesUri -Body $_CustomBaselineRestore -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [void]$_TaskCollection.Add($_resp)
                
            }                

        }
        
    }

    End
    {

        "[{0}] done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $_TaskCollection

    }


}

function Remove-HPOVBaseline
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("b",'Baseline')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipeline)]
        [Switch]$Force,
    
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        { 

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        "[{0}] Baseline provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Name, $InputObject.uri | Write-Verbose

        If ($InputObject.category -eq $ResourceCategoryEnum.Baseline)
        {

            If (-not($InputObject.ApplianceConnection))
            {

                $ExceptionMessage = "The Baseline resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        elseif ($InputObject -is [PSCustomObject] -and $InputObject.category -ne $ResourceCategoryEnum.Baseline)
        {

            $ExceptionMessage = "The Baseline resource is not an expected category type [{0}]. Allowed resource category type is '{01}'. Please check the object provided and try again." -f $InputObject.category, $ResourceCategoryEnum.Baseline
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, ("remove baseline '{0}'" -f $InputObject.Name))) 
        {

            "[{0}] Removing Baseline '{1}' from appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.ApplianceConnection | Write-Verbose

            $_Uri = $InputObject.Uri

            if ($Force)
            {

                $_Uri += '?force=true'

            }

            Try
            {
                
                Send-HPOVRequest -Uri $_Uri -Method DELETE -Hostname $InputObject.ApplianceConnection -AddHeader @{'If-Match' = $InputObject.eTag }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVBaselineRepository
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $False)]
        [ValidateSet ('Internal', 'External')]
        [String]$Type,
    
        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose 

            "[{0}] Getting baseline repo information resources" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

            $_Uri = '{0}?sort=name:asc' -f $ApplianceRepositoriesUri

            if ($Name)
            {

                $_Uri += "&filter=name EQ '{0}'" -f $Name

            }

            if ($Type)
            {

                $_Uri += "&filter=repositoryType EQ '{0}'" -f $RepositoryType[$Type]

            }

            Try
            {

                $_BaselineRepos = Send-HPOVRequest -Uri $_Uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($Name -and $_BaselineRepos.Count -eq 0)
            {

                $ExceptionMessage = "The specified '{0}' baseline repository resource was not found on '{1}' appliance connection. Please check the name and try again." -f $Name, $_appliance.Name 
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineRepositoryResourceException BaselineRepositoryResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_RepoEntry in $_BaselineRepos.members)
                {

                    $_RepoEntry.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.BaselineRepository')

                    $_RepoEntry

                }

            }

        }
        
    }

    End
    {

        "[{0}] done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVExternalRepository
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'PSCredentials')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'PSCredentials')]
        [String]$Hostname,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'PSCredentials')]
        [String]$Directory,

        [Parameter (Mandatory, ParameterSetName = 'PSCredentials')]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [SecureString]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredentials')]
        [Switch]$Http,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredentials')]
        [String]$Certificate,

        [Parameter (Mandatory = $false,ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false,ParameterSetName = 'PSCredentials')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredentials')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        if (-not $PSBoundParameters['Password'] -and $PSBoundParameters['Username'] -and $PSCmdlet.ParameterSetName -eq 'Default')
        {

            [SecureString]$Password = read-host -AsSecureString "Password"
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            
        }

        elseif ($Password -is [SecureString] -and $PSCmdlet.ParameterSetName -eq 'Default')
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSCmdlet.ParameterSetName -eq 'Default')
        {

            $_DecryptPassword = "$Password"

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username        = $Credential.UserName
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }
        
        $_ExternalRepository = NewObject -ExternalRepository

        $_Protocol = 'https'

        if ($PSBoundParameters['Http'])
        {

            "[{0}] Setting protocol to HTTP." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_Protocol = 'http'

        }

        $_ExternalRepository.repositoryName = $Name
        $_ExternalRepository.userName       = $Username
        $_ExternalRepository.password       = $_DecryptPassword
        $_ExternalRepository.repositoryURI  = '{0}://{1}/{2}' -f $_Protocol, $Hostname, $Directory
        $_ExternalRepository.base64Data     = $Certificate
        
        # Post the new object to the appliancenvocationName.ToString().ToUpper())] Processing Appliance $($_Connection.Name)"
        Try
        {

            $_Resp = Send-HPOVRequest -Uri $ApplianceRepositoriesUri -Method POST $_ExternalRepository -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not($PSBoundParameters['Async']))
        {

            $_Resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_Resp

        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString() | Write-Verbose
    
    }

}

function Set-HPOVExternalRepository
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdLetBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default", ValueFromPipeline)]
        [Parameter (Mandatory, ParameterSetName = "PSCredentials", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredentials')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredentials')]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [SecureString]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredentials')]
        [String]$Certificate,

        [Parameter (Mandatory = $false,ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false,ParameterSetName = 'PSCredentials')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
        }        

    }

    Process
    {

        if ($InputObject.category -ne 'repository-manager')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is not supported." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.repositoryType -eq 'FirmwareInternalRepo')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is an Internal Baseline Repository. Only External repositories can be removed." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineRepositoryResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_UpdatedInputObject = NewObject -ExternalRepository | Select-Object * -ExcludeProperty repositoryType, repositoryURI
        $_UpdatedInputObject.repositoryName = $InputObject.name

        # Commented out until PATCH fully works
        #$_UpdatedInputObject = NewObject -PatchOperation
        #$_UpdatedInputObject.op = 'replace'
        #$_UpdatedInputObject.path = '/repository'

        #$_UpdatedValues = [PSCustomObject]@{}

        [Uri]$_RepositoryUrlObject       = $InputObject.repositoryUrl.Clone()
        [String]$_RespositoryUrlToUpdate = $InputObject.repositoryUrl.Clone()

        switch ($PSBoundParameters.Keys)
        {

            'Name'
            {

                "[{0}] Updating repository name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose
                #$_UpdatedValues | Add-Member -NotePropertyName respositoryName -NotePropertyValue $Name
                $_UpdatedInputObject.repositoryName = $Name

            }

            'Certificate'
            {

                "[{0}] Updating repository HTTPS certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                #$_UpdatedValues | Add-Member -NotePropertyName base64Data -NotePropertyValue $Certificate
                $_UpdatedInputObject.base64Data = $Certificate

            }

            'Credential'
            {

                "[{0}] Updating repository credentials with PSCredential object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $Username        = $Credential.UserName
                $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

                #$_UpdatedValues | Add-Member -NotePropertyName userName -NotePropertyValue $Username
                #$_UpdatedValues | Add-Member -NotePropertyName password -NotePropertyValue $_DecryptPassword
                $_UpdatedInputObject.userName = $Username
                $_UpdatedInputObject.password = $_DecryptPassword

            }

            'Username'
            {

                "[{0}] Updating repository username." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                #$_UpdatedValues | Add-Member -NotePropertyName userName -NotePropertyValue $userName
                $_UpdatedInputObject.userName = $Username

            }

            'Password'
            {

                "[{0}] Updating repository password." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

                #$_UpdatedValues | Add-Member -NotePropertyName password -NotePropertyValue $_DecryptPassword

                $_UpdatedInputObject.password = $_DecryptPassword

            }

        }

        #$_UpdatedInputObject.value = $_UpdatedValues
    
        if ($PSCmdlet.ShouldProcess($InputObject.Name, ("Modify repository from appliance {0}" -f $InputObject.ApplianceConnection)))
        {   
            
            Try
            {

                #$_Resp = Send-HPOVRequest -Uri $InputObject.uri -Method PATCH -Body $_UpdatedInputObject -AddHeader @{'If-Match' = $InputObject.eTag} -Hostname $InputObject.ApplianceConnection
                $_Resp = Send-HPOVRequest -Uri $InputObject.uri -Method PUT -Body $_UpdatedInputObject -AddHeader @{'If-Match' = $InputObject.eTag} -Hostname $InputObject.ApplianceConnection

                if (-not $PSBoundParameters['Async'])
                {

                     $_Resp | Wait-HPOVTaskComplete

                }

                else
                {

                    $_Resp

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVExternalRepository
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdLetBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false,ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
        }        

    }

    Process
    {

        if ($InputObject.category -ne 'repository-manager')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is not supported." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.repositoryType -eq 'FirmwareInternalRepo')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is an Internal Baseline Repository. Only External repositories can be removed." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineRepositoryResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_RefreshRepositoryOperation       = NewObject -PatchOperation
        $_RefreshRepositoryOperation.op    = 'replace'
        $_RefreshRepositoryOperation.path  = '/refreshState'
        $_RefreshRepositoryOperation.value = 'RefreshPending'

        if ($PSCmdlet.ShouldProcess($InputObject.Name, ("Refresh repository on appliance {0}" -f $InputObject.ApplianceConnection)))
        {   
            
            Try
            {

                $_Resp = Send-HPOVRequest -Uri $InputObject.uri -Method PATCH -Body $_RefreshRepositoryOperation -Hostname $InputObject.ApplianceConnection

                if (-not $PSBoundParameters['Async'])
                {

                     $_Resp | Wait-HPOVTaskComplete

                }

                else
                {

                    $_Resp

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVExternalRepository
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false,ParameterSetName = 'Default')]
        [Switch]$Force,

        [Parameter (Mandatory = $false,ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
        }        

    }

    Process
    {

        if ($InputObject.category -ne 'repository-manager')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is not supported." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.repositoryType -eq 'FirmwareInternalRepo')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is an Internal Baseline Repository. Only External repositories can be removed." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineRepositoryResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_uri = $InputObject.uri
    
        if ($PSCmdlet.ShouldProcess($InputObject.Name, ("Remove repository from appliance {0}" -f $InputObject.ApplianceConnection)))
        {   
            
            if ($Force)
            {

                $_uri += '?force=true'

            }

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection

                if (-not $PSBoundParameters['Async'])
                {

                    $_resp | Wait-HPOVTaskComplete

                }

                else
                {

                    $_resp

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVSupportDump 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "values")]
    Param 
    (

        [Parameter (Mandatory = $false,ValueFromPipeline = $false, ParameterSetName = "values")]
        [Parameter (Mandatory = $false,ValueFromPipeline = $false, ParameterSetName = "Object")]
        [Alias ("save")]
        [String]$Location = (get-location).Path,

        [Parameter (Mandatory,ValueFromPipeline = $false, ParameterSetName = "values")]
        [ValidateSet ("Appliance","LI")]
        [String]$Type,

        [Parameter (Mandatory = $false,ValueFromPipeline = $false, ParameterSetName = "values")]
        [Switch]$Encrypted,

        [Parameter (Mandatory,ValueFromPipeline, ParameterSetName = "Object")]
        [Alias ('liobject','li','name')]
        [object]$LogicalInterconnect,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "values")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Object")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters["LogicalInterconnect"]) -and $PSCmdlet.ParameterSetName -eq "Object") 
        { 
            
            $PipelineInput = $true 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        # Validate the path exists. If not, create it.
        "[{0}] Validating $($Location) exists" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not(Test-Path $Location)) 
        { 
            
            "[{0}] $($Location) Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            New-Item -ItemType directory -path $Location 
        
        }

    }

    Process
    {

        if ($PipelineInput -and $LogicalInterconnect)
        {

            "[{0}] Pipeline object: $($LogicalInterconnect.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Validate input object is a Logical Interconnect resource
            if ($LogicalInterconnect.category -ne 'logical-interconnects')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectResourceException InvalidLogicalInterconnectResource InvalidArgument 'LogicalInterconnect' -TargetType $LogicalInterconnect.GetType().Name -Message "The LogicalInterconnect Parameter value is invalid. Resource category provided '$($LogicalInterconnect.category)', expected 'logical-interconnects'. Please check the value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
            
            $Request = [PSCustomObject]@{errorCode = $LogicalInterconnect.name}

            $targetURI = $LogicalInterconnect.uri + "/support-dumps"

            "[{0}] Received information from pipeline" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Request : $($request | out-string) " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] URI: $($targetURI)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Send the request
            Write-Host "Please wait while the Support Dump is generated. This can take a few minutes..."

            Try
            {

                $resp = Send-HPOVRequest $targetUri POST $Request -Hostname $LogicalInterconnect.ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Now that the Support Dump has been requested, download the file
            Try
            {

                Download-File $resp.uri $LogicalInterconnect.ApplianceConnection $Location

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else 
        {

            "[{0}] Support Dump Type: $($type)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            switch ($Type)
            {
                        
                "appliance" 
                {

                    ForEach ($_appliance in $ApplianceConnection)
                    {

                        #Build the request and specify the target URI. Do not change errorCode value.
                        "[{0}] Requesting Appliance Support Dump..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $request = [PSCustomObject]@{
                                
                            errorCode = "CI";
                            encrypt   = [Bool]$Encrypted.IsPresent
                            
                        }

                        $targetURI = $ApplianceSupportDumpUri
                            
                        "[{0}] Request : $($request | out-string) " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] URI: $($targetURI)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        # Send the request
                        Write-Host "Please wait while the Support Dump is generated. This can take a few minutes..."

                        Try
                        {

                            $resp = Send-HPOVRequest $targetUri POST $Request -Hostname $_appliance

                        }
                            
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        # Now that the Support Dump has been requested, download the file
                        Try
                        {

                            Download-File $resp.uri $_appliance.Name $Location

                        }
                            
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }                    

                }
                            
                "li" 
                { 

                    "[{0}] Requesting $LogicalInterconnect Support Dump..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                    if ($LogicalInterconnect -is [String]) 
                    {

                        Try
                        {

                            $resp = Get-HPOVLogicalInterconnect -InputObject $LogicalInterconnect -Hostname $ApplianceConnection

                        }
                            
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                    
                        $request = @{errorCode = $resp.name.SubString(0,10)}
                        
                        $targetURI = $resp.uri + "/support-dumps"
                        
                        "[{0}] Processing '$($resp.name) Logical Interconnect" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose


                    }

                    elseif ($LogicalInterconnect -is [PSCustomObject]) 
                    {
                            
                        "[{0}] Logical Interconnect Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] Processing '$($LogicalInterconnect.name) Logical Interconnect" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $request = @{errorCode = $LogicalInterconnect.name.SubString(0,10)}

                        $targetUri = $LogicalInterconnect.uri

                    }

                    # Send the request
                    Write-Host "Please wait while the Support Dump is generated. This can take a few minutes..."

                    Try
                    {

                        $resp = Send-HPOVRequest $targetUri POST $Request -Hostname $ApplianceConnection

                    }
                            
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Now that the Support Dump has been requested, download the file
                    Try
                    {

                        Download-File $resp.uri $ApplianceConnection.Name $Location

                    }
                            
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            } 
                    
        }

    }

    End 
    {
        
        "Done." | Write-Verbose
            
    }

}

function Get-HPOVAutomaticBackupConfig
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_AutoBackupStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_AutomaticBackup = Send-HPOVRequest -Uri $ApplianceAutoBackupConfUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_AutomaticBackup.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AutomaticBackupConfig')

            [void]$_AutoBackupStatusCollection.Add($_AutomaticBackup)


        }
        
    }

    End
    {

        Return $_AutoBackupStatusCollection

    }

}

function Set-HPOVAutomaticBackupConfig
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Directory,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Username,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [SecureString]$Password,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$HostSSHKey,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('SCP','SFTP')]
        [String]$Protocol = 'SCP',

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('Daily','Weekly')]
        [String]$Interval,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Array]$Days,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateScript ({[RegEx]::IsMatch($_,"([01]?[0-9]|2[0-3]):[0-5][0-9]")})]
        [String]$Time,

        [Parameter (Mandatory, ParameterSetName = 'Disable')]
        [Switch]$Disabled,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Disable')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Disable')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_AutoBackupStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_resp = $null

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_AutomaticBackupStatus = Send-HPOVRequest -Uri $ApplianceAutoBackupConfUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_AutoBackupConfig = NewObject -AutoBackupConfig

            $_AutoBackupConfig.eTag = $_AutomaticBackupStatus.eTag

            if ($PSBoundParameters['Disabled'])
            {

                $_AutomaticBackupStatus.enabled = $false

            }

            else
            {

                if (-not $HostSSHKey.StartsWith('ssh-rsa'))
                {

                    $_ExceptionMessage = 'The provided HostSSHKey is not a valid OpenSSL RSA key.'
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AutomatedBackupConfigException InvalidedHostSSHRsaKey InvalidArgument 'HostSSHKey' -Message $_ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_AutoBackupConfig.remoteServerDir       = $Directory
                $_AutoBackupConfig.remoteServerName      = $Hostname
                $_AutoBackupConfig.remoteServerPublicKey = ($HostSSHKey | Out-String)
                $_AutoBackupConfig.userName              = $Username
                $_AutoBackupConfig.password              = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

                if ($PSBoundParameters['Protocol'])
                {

                    $_AutoBackupConfig.protocol = $Protocol

                }

                else
                {

                    $_AutoBackupConfig.protocol = $_AutomaticBackupStatus.Protocol

                }

                if ($PSBoundParameters['Interval'])
                {

                    $_AutoBackupConfig.scheduleInterval = $Interval.ToUpper()

                }

                else
                {
            
                    $_AutoBackupConfig.scheduleInterval = $_AutomaticBackupStatus.scheduleInterval
            
                }

                if ($PSBoundParameters['Days'] -and $PSBoundParameters['Interval'] -eq 'Weekly')
                {

                    ForEach ($_day in $Days)
                    {

                        [void]$_AutoBackupConfig.scheduleDays.Add($DayOfWeekEnum.$_day.ToUpper())

                    }

                }

                else
                {
            
                    $_AutoBackupConfig.scheduleDays = $_AutomaticBackupStatus.scheduleDays
            
                }

                if ($PSBoundParameters['Time'])
                {

                    $_AutoBackupConfig.scheduleTime = $Time

                }

                else
                {
            
                    $_AutoBackupConfig.scheduleTime = $_AutomaticBackupStatus.scheduleTime
            
                }

            }

            # Prompt the user if they really want to disable Automatic Backups
            if ($PSBoundParameters['Disabled'])
            {

                if ($PSCmdlet.ShouldProcess($_appliance.Name,'disable automatic backup schedule on appliance')) 
                {

                    Try
                    {

                        $_resp = Send-HPOVRequest -Uri $ApplianceAutoBackupConfUri PUT $_AutomaticBackupStatus -Hostname $_appliance

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSBoundParameters['WhatIf'])
                {

                    "[{0}] User provided -WhatIf switch." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else
                {
                
                    "[{0}] User cancelled or stated 'No'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Return

                }

            }

            else
            {

                "[{0}] Sending request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $ApplianceAutoBackupConfUri -Method PUT -Body $_AutoBackupConfig -Hostname $_appliance

                }
                    
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            if ($PSBoundParameters['Async'])
            {

                $_resp

            }

            else
            {
                
                $_resp | Wait-HPOVTaskComplete

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVBackup
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [DateTime]$Before,
            
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [DateTime]$After,
        
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Validate the path exists. If not, create it.
        if ($PSBoundParameters['Location'] -and -not(Test-Path $Location))
        {
             
            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            New-Item $Location -itemtype directory

        }

        $_BackupFileStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {
                
                $_Backups = Send-HPOVRequest -Uri $ApplianceBackupUri -Hostname $_appliance

            }   

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Before'])
            {

                $_Backups.members | Where-Object { [DateTime]$_.created -le $Before.ToUniversalTime() }

            }

            elseif ($PSBoundParameters['After'])
            {

                $_Backups.members | Where-Object { [DateTime]$_.created -ge $After.ToUniversalTime() }

            }

            else
            {

                $_Backups.members

            }            

        }
        
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Save-HPOVBackup
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("save")]
        [String]$Location = (get-location).Path,

        [Parameter (Mandatory, ParameterSetName = "SaveRemoteOnly")]
        [Switch]$SaveRemoteOnly,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SaveRemoteOnly")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Validate the path exists. If not, create it.
        if ($PSBoundParameters['Location'] -and -not(Test-Path $Location))
        {
             
            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            New-Item $Location -itemtype directory | Out-Null

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Check to see if Automatic Backup is set on the appliance.
            Try
            {

                $_AutomaticBackup = Send-HPOVRequest -Uri $ApplianceAutoBackupConfUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Getting appliance created backup file" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_CurrentBackup = Send-HPOVRequest -Uri $ApplianceBackupUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_CurrentBackup.Count -eq 0)
            {

                "[{0}] Appliance does not contain a backup file. Generate non-terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = 'No backup files were found on "{0}" appliance.' -f $_appliance
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ApplianceBackupException EmptyBackupFileList ObjectNotFound ApplianceConnection -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_BackupToDownload in $_CurrentBackup.members)
                {

                    if ($_AutomaticBackup.enabled -and $PSBoundParameters['SaveRemoteOnly'])
                    {

                        "[{0}] Appliance supports remtoe backups. Saving backup file to remote location: {1}/{2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_AutomaticBackup.remoteServerName, $_AutomaticBackup.remoteServerDir | Write-Verbose

                        Try
                        {

                            Send-HPOVRequest -Uri $_BackupToDownload.saveUri -Method PUT -Hostname $_BackupToDownload.ApplianceConnection | Wait-HPOVTaskComplete
                            
                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }
                    
                    else
                    {

                        Try
                        {
                            
                            $_Results = Download-File $_BackupToDownload.downloadUri $_appliance $Location

                            [System.IO.FileInfo]$_Results.file

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }    

                }
                
            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }
    
}

function New-HPOVBackup 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("save")]
        [String]$Location = (get-location).Path,
        
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async,
            
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Validate the path exists. If not, create it.
        if ($PSBoundParameters['Location'] -and -not(Test-Path $Location))
        {
             
            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            New-Item $Location -itemtype directory

        }

        $_BackupFileStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Check to see if Automatic Backup is set on the appliance.
            Try
            {

                $_AutomaticBackup = Send-HPOVRequest -Uri $ApplianceAutoBackupConfUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Please wait while the appliance backup is generated. This can take a few minutes..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {
                
                $_taskStatus = Send-HPOVRequest -Uri $ApplianceBackupUri -Method POST -Hostname $_appliance | Wait-HPOVTaskComplete -timeout (New-Timespan -minutes 45)

                "[{0}] Response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $($_taskStatus | out-string) | Write-Verbose

                $_backupObject = Send-HPOVRequest -Uri $_taskStatus.associatedResource.resourceUri -Hostname $_appliance
                
            }   

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # If no automatic backup is configured, then download
            if (-not($_AutomaticBackup.enabled) -or $PSBoundParameters['Force'])
            {

                "[{0}] Backup File URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_backupObject.downloadUri | Write-Verbose

                "[{0}] Downloading to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Location | Write-Verbose

                Try
                {

                    $_resp = Download-File $_backupObject.downloadUri $_appliance $Location

                    [void]$_BackupFileStatusCollection.Add([System.IO.FileInfo]$_resp.file)

                }
            
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            else
            {

                "[{0}] Created backup will be saved to remote location: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_AutomaticBackup.remoteServerName | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_backupObject.saveUri -Method PUT -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not($PSboundParameters['Async']))
                {

                    "[{0}] Monitoring remote save operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_resp = Wait-HPOVTaskComplete $_resp

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                [void]$_BackupFileStatusCollection.Add($_resp)

            }

        }
        
    }

    End
    {

        Return $_BackupFileStatusCollection

    }

}

function New-HPOVRestore 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("File")]
        [String]$FileName,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose
            
            # Validate the path exists. If not, create it.
            if (-not(Test-Path $FileName))
            {
                 
                "[{0}] Backup file specified does not exist." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RestoreException BackupFileNotFound ObjectNotFound 'FileName' -Message "'$FileName' was not found. Please check the directory and/or name and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($PSCmdlet.ShouldProcess($_appliance.Name,'restore backup to appliance')) 
            {    
            
                # Send the request
                "[{0}] Please wait while the appliance backup is uploaded. This can take a few minutes..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $resp = Upload-File -Uri $ApplianceRestoreRepoUri $FileName -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                if ($resp.id)
                {

                    "[{0}] Sending request to restore appliance" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_restoreObject = [PSCustomObject]@{

                        type                 = "RESTORE"
                        uriOfBackupToRestore = $resp.uri

                    }

                    Try
                    {
                    
                        $_restoreStatus = Send-HPOVRequest -Uri $ApplianceRestoreUri -Method POST -Body $_restoreObject -Hostname $_appliance
                    
                        Write-warning "Appliance restore in progress. All users are now logged off."
                    
                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $sw = [System.Diagnostics.Stopwatch]::StartNew()

                    While ($_restoreStatus.status -eq "IN_PROGRESS") 
                    {

                        $_statusMessage = "{0} {1}% [{2}min {3}sec]" -f $ApplianceUpdateProgressStepEnum[$_restoreStatus.progressStep],$_restoreStatus.percentComplete, $sw.Elapsed.Minutes, $sw.Elapsed.Seconds

                        # Handle the call from -Verbose so Write-Progress does not get borked on display.
                        if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                        { 

                            "[{0}] - $_statusMessage" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        { 

                            Write-Progress -id 1 -activity "Restoring Appliance Backup $($_restoreStatus.id)" -status $_statusMessage -percentComplete $_restoreStatus.percentComplete
                        
                        }


                        Try
                        {
                    
                            $_restoreStatus = Send-HPOVRequest $_restoreStatus.uri -Hostname $_appliance
                                    
                        }
                    
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    } # Until ($restoreStatus.percentComplete -eq 100 -or $restoreStatus -ne "IN_PROGRESS")

                    $sw.Stop()

                    "[{0}] - Operation took $($sw.elapsed.minutes)min $($sw.elapsed.seconds)sec" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Write-Progress -id 1 -activity "Restoring Appliance Backup $($_restoreStatus.id)" -status $_statusMessage -Completed

                    Write-warning "Appliance restore in has completed for $($_appliance.Name). Address Pool ranges will need to be re-enabled, and verify the managed or monitored resources do not need a refresh."

                }

                [void]$_ApplianceStatus.Add($_restoreStatus)

            }

        }
    
    }

    End 
    {

        Return $_ApplianceStatus
    
    }

}

function Download-File 
{

    <#
        .DESCRIPTION
        Helper function to download files from appliance.
                     
        .Parameter uri
        The location where the Support Dump or backup will be downloaded from
             
        .Parameter SaveLocation
        The full path to where the Support Dump or backup will be saved to. This path will not be validated in this helper function
 
        .Parameter ApplianceConnection
        The Appliance Connection Object, Name or ConnectionID
 
        .INPUTS
        None. You cannot pipe objects to this cmdlet.
                     
        .OUTPUTS
        Downloads the requested file using net.WebRequest
 
        .EXAMPLE
        PS C:\> Download-File /rest/appliance/support-dumps/ci5401AB76-CI-2013_09_04-04_52_00.014786.sdmp -ApplianceConnection MyAppliance.domain.com c:\temp
             
    #>


    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [String]$uri,
        
        [Parameter (Mandatory)]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory)]
        [Alias ("save")]
        [ValidateNotNullOrEmpty()]
        [String]$SaveLocation

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif  ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        else
        {

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        $_downloadfilestatus = NewObject -DownloadFileStatus
    
        $fsCreate = [System.IO.FileAccess]::Create
        $fsWrite = [System.IO.FileAccess]::Write

        "[{0}] Download URI: $uri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        [System.Net.ServicePointManager]::UseNagleAlgorithm = $false
        [System.Net.httpWebRequest]$_fileDownload           = RestClient GET $uri $ApplianceConnection.Name
        $_fileDownload.Headers.Item('Accept-Encoding')      = 'gzip, deflate'
        $_fileDownload.accept                               = "application/zip,application/octet-stream,*/*"
        $_fileDownload.Headers.Item("auth")                 = $ApplianceConnection.SessionID

        $i = 0

        ForEach ($_h in $_fileDownload.Headers) 
        {
            
            "[{0}] Request Header $($i): $($_h) = $($_fileDownload.Headers[$i])" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $i++
        
        }
            
        "[{0}] Request: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_fileDownload | Write-Verbose
        
        Try
        {

            # Get response
            "[{0}] Getting response" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            [Net.httpWebResponse]$_rs = $_fileDownload.GetResponse()

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Finally
        {

            if ($rs)
            {

                $_rs.Close()

            }

        }        

        # Display the response status if verbose output is requested
        "[{0}] Response Status: $([Int]$_rs.StatusCode) $($_rs.StatusDescription)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $i = 0

        ForEach ($_h in $_rs.Headers) 
        { 
            
            "[{0}] Response Header $($i): $($_h) = $($_rs.Headers[$i])" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $i++ 
        
        }

        # Request is a redirect to download file contained in the response headers
        if (($_rs.headers["Content-Disposition"]) -and ($_rs.headers["Content-Disposition"].StartsWith("attachment; filename="))) 
        {
        
            $_fileName = ($_rs.headers["Content-Disposition"].SubString(21)) -replace "`"",""
        
        }
                        
        # Detect if the download is a Support Dump or Appliance Backup
        elseif ($uri.Contains("/rest/backups/archive"))
        {

            # Need to get the Appliance file name
            $_fileName = $uri.split("/")
            
            $_fileName = $_fileName[-1] + ".bkp"
        
        }

        else 
        {
            # Need to get the Support Dump file name
            $_fileName = $uri.split("/")

            $_fileName = $ApplianceConnection.Name + "_" + $_fileName[-1]

        }

        if ($_rs.headers['Content-Length']) 
        { 
            
            [int64]$_fileSize = $_rs.headers['Content-Length'] 
            Write-Verbose ('*****Filesize from Header: {0}' -f $_fileSize)
        
        }

        elseif ($_rs.ContentLength) 
        { 
            
            [int64]$_fileSize = $_rs.ContentLength 
            Write-Verbose ('*****Filesize from ContentLength: {0}' -f $_fileSize)
        
        }

        "[{0}] Filename: $($_fileName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        "[{0}] Filesize: $($_fileSize)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        if($_rs.StatusCode -eq 200) 
        {

            Try
            {

                # Read from response and write to file
                $_stream = $_rs.GetResponseStream() 
                
                # Define buffer and buffer size
                Write-Verbose ('Creating Buffer of size: {0}MB' -f ((1024 * 8192) / 1MB))
                [byte[]]$_buffer   = New-Object byte[] (1024 * 8192)
                [Int] $_bytesRead  = 0

                Write-Verbose ('Buffer size: {0}' -f $_buffer.length)

                # This is used to keep track of the file upload progress.
                $_numBytesRead     = 0
                $_numBytesWrote    = 0
     
                "[{0}] Saving to $($saveLocation)\$($_fileName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_fs = New-Object IO.FileStream ($saveLocation + "\" + $_fileName),'Create' #,'Write','Read'

                # Throughput Stopwatch
                $_sw = New-Object System.Diagnostics.StopWatch
                $_progresssw = New-Object System.Diagnostics.StopWatch
                $_sw.Start()
                $_progresssw.Start()

                while (($_bytesRead = $_stream.Read($_buffer, 0, $_buffer.Length)) -gt 0)
                {

                    # Write from buffer to file
                    $_fs.Write($_buffer, 0, $_bytesRead)
                
                    # Keep track of bytes written for progress meter
                    $_total += $_bytesRead

                    # Elapsed time to calculate throughput
                    $_transferrate = ($_total / $_sw.Elapsed.TotalSeconds) / 1MB

                    # Use the Write-Progress cmd-let to show the progress of uploading the file.
                    [Int]$_percent = (($_total / $_fileSize)  * 100)

                    $_status = '{0:0}MB of {1:0}MB @ {2:N2}MB/s' -f ($_total / 1MB), ($_fileSize / 1MB), $_transferrate

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                
                        if ($_progresssw.Elapsed.TotalMilliseconds -ge 500)
                        {
                            
                            "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Downloading file: $_fileName, status: $_status, Percent: $_percent" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $_progresssw.Restart()

                        }
                    
                    }
                  
                    else 
                    { 
                    
                        if ($_progresssw.Elapsed.TotalMilliseconds -ge 500)
                        {

                            Write-Progress -id 0 -Activity "Downloading file $_fileName" -Status $_status -percentComplete $_percent 

                            $_progresssw.Restart()

                        }                        
                
                    }

                } # While ($_bytesRead -gt 0)

                Write-Progress -id 0 -Activity "Downloading file $_fileName" -Completed

                "[{0}] File saved to $($saveLocation)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_downloadfilestatus.status              = 'Completed'
                $_downloadfilestatus.file                = "$saveLocation\$_fileName"
                $_downloadfilestatus.ApplianceConnection = $ApplianceConnection.Name

                Return $_downloadfilestatus

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            finally
            {

                # Clean up our work
                if ($_stream) { $_stream.Close() }
                if ($_rs) { $_rs.Close() }
                if ($_fs) { $_fs.Close() }

            }

        }

        else
        {

            # Clean up
            if ($_rs) { $_rs.Close() }
            if ($_fs) { $_fs.Close() }

            Throw 'Unhandled download exception'

        }    
        
    }

}

function Upload-File 
{

    <#
 
        .SYNOPSIS
        Upload a file to the appliance.
 
        .DESCRIPTION
        This cmdlet will upload a file to the appliance that can accepts file uploads (SPP firmware bundle, Appliance Restore, and Appliance Updates.)
 
        .Parameter URI
        Location where to upload file to.
 
        .Parameter File
        Full path to the file to be uploaded.
 
        .Parameter AddHeader
        Provide a Hashtable of additional HTTP headers to include
         
        .Parameter ApplianceConnection
        Appliance Connection
 
        .INPUTS
        None. You cannot pipe objects to this cmdlet.
 
        .OUTPUTS
        Write-Progress
        The progress of uploading the file to the appliance.
 
        .LINK
        Add-HPOVBaseline
 
        .LINK
        New-HPOVRestore
 
        .EXAMPLE
        PS C:\> Upload-File "/rest/firmware-bundles" "C:\Users\me\Documents\SPP2012060B.2012_0525.1.iso"
 
        Upload a new SPP into the appliance.
 
        .EXAMPLE
        PS C:\> Upload-File "/rest/restores" "C:\Users\me\Documents\appliance.bak"
 
        Upload a backup file to restore in the appliance.
 
    #>


    [CmdletBinding ()]

    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Alias ('u')]
        [String]$uri,

        [Parameter (Mandatory)]
        [Alias ('f')]
        [ValidateScript( {Test-Path $_})]
        [System.IO.FileInfo]$File,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Object]$AddHeader,

        [Parameter (Mandatory = $false)]
        [ValidateSet ('PUT', 'POST')]
        [String]$Method = 'POST',
        
        [Parameter (Mandatory = $false)]
        [Alias ('Hostname')]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        else
        {

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }
    
    Process 
    {

        # $_fileObj = Get-Item -path $File
        
        $fs = New-Object IO.FileStream ($File.FullName, $FSOpenMode, $FSRead)

        # [String]$filename = $_fileObj.name

        "[{0}] Uploading {1} file to appliance, this may take a few minutes..." -f $MyInvocation.InvocationName.ToString().ToUpper(), $File.FullName | Write-Verbose

        try 
        {

            $uri = "{0}?uploadfilename={1}" -f $uri, $File.Name
            
            # $_encoding = $null
            $_DispositionContentType = "application/octet-stream"
            
            if ($File.Extension -eq '.crl')
            {

                # $_encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")

                $_DispositionContentType = "application/pkix-crl"

                "[{0}] Setting HttpWebRequest body encoding to 'ISO-8859-1': {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Bool]$_encoding | Write-Verbose
                
            }

            "[{0}] Setting Disposition Content-Type to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DispositionContentType | Write-Verbose            

            [System.Net.httpWebRequest]$uploadRequest = RestClient $Method $uri -Appliance $ApplianceConnection.Name

            $boundary = "---------------------------" + [DateTime]::Now.Ticks.ToString("x")
            [byte[]]$BoundaryBytes = [System.Text.Encoding]::UTF8.GetBytes("`r`n--" + $boundary + "`r`n");
            $disposition = "Content-Disposition: form-data; name=`"file`"; filename=`"{0}`";`r`nContent-Type: {1}`r`n`r`n" -f $File.Name, $_DispositionContentType
            [byte[]]$ContentDispBytes = [System.Text.Encoding]::UTF8.GetBytes($disposition);
            [byte[]]$EndBoundaryBytes = [System.Text.Encoding]::UTF8.GetBytes("`r`n--" + $boundary + "--`r`n")

            $uploadRequest.Timeout = 1200000
            $uploadRequest.ContentType = "multipart/form-data; boundary={0}" -f $boundary
            $uploadRequest.Headers.Item("auth") = $ApplianceConnection.SessionID
            $uploadRequest.Headers.Item("uploadfilename") = $File.Name
            $uploadRequest.AllowWriteStreamBuffering = $false
            $uploadRequest.SendChunked = $false
            $uploadRequest.ContentLength = $BoundaryBytes.length + $ContentDispBytes.length + $File.Length + $EndBoundaryBytes.Length
            $uploadRequest.Headers.Item("ContentLength") = $BoundaryBytes.length + $ContentDispBytes.length + $File.Length + $EndBoundaryBytes.Length

            ForEach ($_Header in $AddHeader)
            {

                $uploadRequest.Headers.($_Header.Name) = $_Header.Value

            }

            "[{0}] Request: POST {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $uri | Write-Verbose

            $i = 0

            foreach ($h in $uploadRequest.Headers) 
            {
                
                "[{0}] Request Header ({1}) {2} : {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $i, $h, $uploadRequest.Headers[$i] | Write-Verbose
                
                $i++
            
            }

            $rs = $uploadRequest.GetRequestStream()

            [byte[]]$readbuffer = New-Object byte[] (4096 * 1024)        
            $rs.write($BoundaryBytes, 0, $BoundaryBytes.Length);
            $rs.write($ContentDispBytes, 0, $ContentDispBytes.Length);

            # This is used to keep track of the file upload progress.
            $numBytesToRead = $fs.Length    
            [int64]$numBytesRead = 0

            if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
            { 
            
                "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            }

            $_sw = [System.Diagnostics.Stopwatch]::StartNew()
            $_progresssw = [System.Diagnostics.Stopwatch]::StartNew()

            while ($byteCount = $fs.Read($readbuffer, 0, $readbuffer.length))
            {

                $rs.write($readbuffer, 0, $byteCount)
                
                $rs.flush()
            
                # Keep track of where we are at clearduring the read operation
                $_numBytesRead += $bytecount

                # Use the Write-Progress cmd-let to show the progress of uploading the file.
                [Int]$_percent = [math]::floor(($_numBytesRead / $fs.Length) * 100)

                # Elapsed time to calculat throughput
                [Int]$_elapsed = $_sw.ElapsedMilliseconds / 1000
                
                if ($_elapsed -ne 0 ) 
                {

                    [single]$_transferrate = [Math]::Round(($_numBytesRead / $_elapsed) / 1mb)
                
                } 
                
                else 
                {

                    [single]$_transferrate = 0.0
                
                }

                $status = "({0:0}MB of {1:0}MB transferred @ {2}MB/s) Completed {3}%" -f ($_numBytesRead / 1MB), ($numBytesToRead / 1MB), $_transferrate, $_percent

                # Handle the call from -Verbose so Write-Progress does not get borked on display.
                if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                { 

                    "[{0}] Uploading file {1}, status: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $File.Name, $status | Write-Verbose
                    
                }
                  
                else 
                { 

                    if ($_progresssw.Elapsed.TotalMilliseconds -ge 500)
                    {

                        if ($_numBytesRead % 1mb -eq 0) 
                        { 
                            
                            Write-Progress -activity "Upload File" -status ("Uploading '{0}'" -f $File.Name) -CurrentOperation $status -PercentComplete $_percent 
                        
                        }

                    }

                }

            }

            "[{0}] Finalizing upload." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $fs.close()

            $rs.write($EndBoundaryBytes, 0, $EndBoundaryBytes.Length)

            $rs.close()

            $_sw.stop()
            $_sw.Reset()

            Write-Progress -activity "Upload File" -status ("Uploading '{0}'" -f $File.Name)  -Complete

        }

        catch [System.Exception] 
        {

            Write-Verbose "Exception caught while uploading file."

            Write-Verbose ("Exception: {0}" -f $_.Exception.Message)
            Write-Verbose ("InnerException: {0}" -f $_.Exception.InnerException.Message)

            if ($fs)
            {

                $fs.close() 
                
            }

            if ($_sw.IsRunning) 
            { 
                
                $_sw.Stop() 
                $_sw.Reset()
            
            }

            # Dispose if still exist
            if ($rs)
            {

                $rs.close() 
                
            }

            $PSCmdlet.ThrowTerminatingError($_)

        }

        try 
        {

            "[{0}] Upload Request completed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
            if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
            {

                "[{0}] Waiting for completion response from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else 
            { 

                Write-Progress -activity "Upload File" -status ("Uploading '{0}'" -f $File.Name)  -CurrentOperation "Waiting for completion response from appliance." -percentComplete $_percent 
            
            }

            [Net.httpWebResponse]$WebResponse = $uploadRequest.getResponse()
            
            "[{0}] Response Status: ({1}) {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Int]$WebResponse.StatusCode, $WebResponse.StatusDescription | Write-Verbose
            
            $uploadResponseStream = $WebResponse.GetResponseStream()

            # Read the response & convert to JSON
            $reader = New-Object System.IO.StreamReader($uploadResponseStream)
            $responseJson = $reader.ReadToEnd()

            $uploadResponse = ConvertFrom-Json $responseJson

            $uploadResponseStream.Close()

            # need to parse the output to know when the upload is truly complete
            "[{0}] Response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($uploadResponse | out-string) | Write-Verbose
            
            $i = 0

            foreach ($h in $WebResponse.Headers) 
            { 
                
                "[{0}] Response Header {1}: {2} = {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $i, $h, $WebResponse.Headers[$i] | Write-Verbose
                
                $i++ 
            
            }

            $uploadRequest = $Null

            Write-Progress -activity "Upload File" -CurrentOperation "Uploading $Filename " -Completed

        }

        catch [Net.WebException] 
        {

            "[{0}] WebException caught. Getting exception response from API." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
 
            Try
            {

                $sr = New-Object IO.StreamReader ($_.Exception.Response.GetResponseStream())

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            $errorObject = $sr.readtoEnd() | ConvertFrom-Json
            
            "[{0}] Error Response from API: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($errorObject | Out-String) | Write-Verbose

            # dispose if still exist
            if ($rs)
            {

                $rs.close() 
                
            }
            
            if ($fs)
            {

                $fs.close() 
                
            }

            $sr.close()

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.UploadFileException $errorObject.ErrorCode InvalidResult 'Upload-File' -Message $errorObject.Message -InnerException $_.Exception

            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }

    }

    End 
    {

        if ($uploadResponseStream)
        {
            
            $uploadResponseStream.Close()

        }

        # Handle file uploads that generate task resource (i.e. Upload SPP Baseline)
        if ($uploadResponse.category -eq "tasks") 
        {
            
            "[{0}] Response is a task resource" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose    

            $uploadResponse | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "HPOneView.Appliance.TaskResource") }

            Add-Member -InputObject $uploadResponse -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($ApplianceConnection.Name, $ApplianceConnection.ConnectionId)) -Force 
            
            return $uploadResponse

        }

        elseif ($null -ne $WebResponse.Headers)
        {

            if ($WebResponse.Headers['Location'])
            {

                try
                {

                    "[{0}] Response is a task resource provided by HTTP Location header." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $uri = $WebResponse.Headers['Location']

                    $taskResource = Send-HPOVRequest -Uri $uri -Hostname $ApplianceConnection.Name
                    
                    Return $taskResource

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }            

            }

            else
            {

                "[{0}] Response does not contain any HTTP headers or task location." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }            

        }        
        
    }

}

 
function Get-HPOVScmbCertificates 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "convert")]
        [ValidateNotNullOrEmpty()]
        [Alias ("save")]
        [String]$Location = ($pwd).path,

        [Parameter (Mandatory = $false, ParameterSetName = "convert")]
        [ValidateNotNullOrEmpty()]
        [Alias ("pfx")]
        [Switch]$ConvertToPFx,
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "convert")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "convert")]
        [Switch]$InstallApplianceRootCA,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "convert")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        $TaskCollection = [System.Collections.ArrayList]::new()
        
        # Validate the path exists. If not, create it.
        if (-not(Test-Path $Location))
        { 

            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            New-Item -path $Location -ItemType Directory

        }

    }

    Process
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' appliance connection (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.count | Write-Verbose

            # Appliance CA
            $caFile = '{0}\{1}_ca.cer' -f $Location, $_appliance.Name
        
            # Appliance Public Key
            $publicKeyFile = '{0}\{1}_cert.cer' -f $Location, $_appliance.Name
        
            # Rabbit Client Private Key
            $privateKeyFile = '{0}\{1}_privateKey.key' -f $Location, $_appliance.Name

            # Check to see if the Rabbit client cert was already created
            Try
            {

                $_keys = Send-HPOVRequest -Uri $ApplianceRabbitMQKeyPairUri -Hostname $_appliance.Name

            }

            Catch [HPOneView.ResourceNotFoundException]
            {

                "[{0}] RabbitMQ SSL cert key pair does not exist." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_rabbitbody = NewObject -RabbitmqCertReq

                    # Generate the client private key request
                    # "[{0}] Body: $($_rabbitbody | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Send-HPOVRequest -Uri $ApplianceScmbRabbitmqUri -Method POST -Body $_rabbitbody -Hostname $_appliance.Name | Wait-HPOVTaskComplete | Out-Null

                    # Retrieve generated keys
                    $_keys = Send-HPOVRequest -Uri $ApplianceRabbitMQKeyPairUri -Hostname $_appliance.Name

                }

                Catch
                {
            
                    $PSCmdlet.ThrowTerminatingError($_)
            
                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
            try 
            {

                New-Item $PrivateKeyFile -type file -force -value $_keys.base64SSLKeyData

                $PrivateKeyFile = [System.IO.FileInfo]$PrivateKeyFile

                "[{0}] Created rabbitmq_readonly user Private Key: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PrivateKeyFile.Name | Write-Verbose 

            }

            catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)
        
            }

            try 
            {

                New-Item $PublicKeyFile -type file -force -value $_keys.base64SSLCertData

                $PublicKeyFile = [System.IO.FileInfo]$PublicKeyFile

                "[{0}] Created rabbitmq_readonly user Public Key: {0}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PublicKeyFile.FullName | Write-Verbose 

            }

            catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            If ($PSBoundParameters['ConvertToPFx'])
            {
            
                Try
                {

                    ConvertTo-Pfx -PrivateKeyFile $PrivateKeyFile -PublicKeyFile $PublicKeyFile -Password $Password

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                
            
            }

            try 
            {

                $_Resp = Send-HPOVRequest -Uri $ApplianceInternalCertificateAuthority -Hostname $_appliance.Name

                $_ca = $_Resp.members[0].certificateDetails.base64Data

                New-Item $caFile -type file -force -value $_ca

                "[{0}] Created {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $caFile | Write-Verbose
        
            }

            catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['InstallApplianceRootCA'])
            {

                # Get certificate
                [Security.Cryptography.X509Certificates.X509Certificate2]$Cert = [System.Convert]::FromBase64String($_ca.Replace('-----BEGIN CERTIFICATE-----',$null).Replace('-----End CERTIFICATE-----',$null)) 

                $StoreScope = "CurrentUser"
                $StoreName  = "Root" 

                # Save to users Trusted Root Authentication Hosts store
                $store = New-Object System.Security.Cryptography.X509Certificates.X509Store $StoreName, $StoreScope

                $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)

                try 
                {

                    "[{0}] Attempting to add cert to store" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $store.Add($cert)
                    $store.Close()

                    "[{0}] Cert added successfully" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                catch 
                {

                    $store.Close()

                    $PSCmdlet.ThrowTerminatingError($_.Exception)

                }

            }

        }

    }

}

function ConvertTo-Pfx
{

    # Modified from Script provided by Vadims Padans (https://www.sysadmins.lv/blog-en/how-to-convert-pem-to-x509certificate2-in-powershell-revisited.aspx)

    [CmdletBinding ()]
    Param
    ( 

        [Parameter (Mandatory)]
        [System.IO.FileSystemInfo]$PrivateKeyFile,

        [Parameter (Mandatory)]
        [System.IO.FileSystemInfo]$PublicKeyFile,
    
        [Parameter (Mandatory)]
        [SecureString]$Password
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {

        function __normalizeAsnInteger ($array) 
        {

            $padding = $array.Length % 8

            if ($padding) 
            {

                $array = $array[$padding..($array.Length - 1)]
                
            }

            [array]::Reverse($array)

            [Byte[]]$array

        }

        function __extractCert([String]$Text) 
        {

            $keyFlags = [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable

            $Text -match "(?msx).*-{5}BEGIN\sCERTIFICATE-{5}(.+)-{5}End\sCERTIFICATE-{5}" | Out-Null

            $RawData = [Convert]::FromBase64String($matches[1])

            try 
            {

                New-Object Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $RawData, "", $keyFlags

            }
            
            catch 
            {
                
                throw "The data is not valid security certificate."
            
            }

            Write-Debug "X.509 certificate is correct."

        }

        # returns [byte[]]
        function __composePRIVATEKEYBLOB($modulus, $PublicExponent, $PrivateExponent, $Prime1, $Prime2, $Exponent1, $Exponent2, $Coefficient) {

            Write-Debug "Calculating key length."

            $bitLen = "{0:X4}" -f $($modulus.Length * 8)

            Write-Debug "Key length is $($modulus.Length * 8) bits."

            # Change from Invoke-Expression due to security "issues" and guidance from MS
            # [byte[]]$bitLen1 = Invoke-Expression 0x$([Int]$bitLen.Substring(0,2))
            [byte[]]$bitLen1 = '0x{0}' -f [Int]$bitLen.Substring(0,2)
            # [byte[]]$bitLen2 = Invoke-Expression 0x$([Int]$bitLen.Substring(2,2))
            [byte[]]$bitLen2 = '0x{0}' -f [Int]$bitLen.Substring(2,2)
            [Byte[]]$PrivateKey = 0x07,0x02,0x00,0x00,0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x32,0x00
            [Byte[]]$PrivateKey = $PrivateKey + $bitLen1 + $bitLen2 + $PublicExponent + ,0x00 + $modulus + $Prime1 + $Prime2 + $Exponent1 + $Exponent2 + $Coefficient + $PrivateExponent

            Return $PrivateKey

        }

        # returns RSACryptoServiceProvider for dispose purposes
        function __attachPrivateKey($Cert, [Byte[]]$PrivateKey) {

            $cspParams = New-Object Security.Cryptography.CspParameters -Property @{
                ProviderName = $ProviderName
                KeyContainerName = "pspki-" + [Guid]::NewGuid().ToString()
                KeyNumber = 1 # AT_KEYEXCHANGE
            }

            $rsa = New-Object Security.Cryptography.RSACryptoServiceProvider $cspParams
            $rsa.ImportCspBlob($PrivateKey)
            $Cert.PrivateKey = $rsa
            Return $rsa

        }

        # returns Asn1Reader
        function __decodePkcs1($base64) 
        {

            Write-Debug "Processing PKCS#1 RSA KEY module."

            $asn = New-Object SysadminsLV.Asn1Parser.Asn1Reader @(,[Convert]::FromBase64String($base64))

            if ($asn.Tag -ne 48) {throw "The data is invalid."}

            Return $asn

        }

        # returns Asn1Reader
        function __decodePkcs8($base64) 
        {

            Write-Debug "Processing PKCS#8 Private Key module."

            $asn = New-Object SysadminsLV.Asn1Parser.Asn1Reader @(,[Convert]::FromBase64String($base64))

            if ($asn.Tag -ne 48) {throw "The data is invalid."}

            # version
            if (!$asn.MoveNext()) {throw "The data is invalid."}

            # algorithm identifier
            if (!$asn.MoveNext()) {throw "The data is invalid."}

            # octet string
            if (!$asn.MoveNextCurrentLevel()) {throw "The data is invalid."}
            if ($asn.Tag -ne 4) {throw "The data is invalid."}
            if (!$asn.MoveNext()) {throw "The data is invalid."}

            Return $asn

        }

        $PfxFileName = $PrivateKeyFile.FullName.Replace(".key",".pfx")

        # Merge Public and Private Key file contents together
        [String]$PrivateKeyFileContents = [System.IO.File]::ReadAllLines($PrivateKeyFile.FullName)
        [String]$CertFileContents       = [System.IO.File]::ReadAllLines($PublicKeyFile.FullName)

        Write-Debug "Extracting certificate information..."

        $Cert = __extractCert $CertFileContents # Validate PEM certificate

        $PrivateKeyFileContents -match "(?msx).*-{5}BEGIN\sRSA\sPRIVATE\sKEY-{5}(.+)-{5}End\sRSA\sPRIVATE\sKEY-{5}" | Out-Null
        $asn = __decodePkcs1 $matches[1]

        # private key version
        if (!$asn.MoveNext()) {throw "The data is invalid."}

        # modulus n
        if (!$asn.MoveNext()) {throw "The data is invalid."}

        $modulus = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "Modulus length: $($modulus.Length)"

        # public exponent e
        if (!$asn.MoveNext()) {throw "The data is invalid."}

        # public exponent must be 4 bytes exactly.
        $PublicExponent = if ($asn.GetPayload().Length -eq 3) 
        {
            ,0 + $asn.GetPayload()

        } 
        
        else 
        {

            $asn.GetPayload()

        }

        Write-Debug "PublicExponent length: $($PublicExponent.Length)"

        # private exponent d
        if (!$asn.MoveNext()) {throw "The data is invalid."}
        $PrivateExponent = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "PrivateExponent length: $($PrivateExponent.Length)"

        # prime1 p
        if (!$asn.MoveNext()) {throw "The data is invalid."}
        $Prime1 = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "Prime1 length: $($Prime1.Length)"

        # prime2 q
        if (!$asn.MoveNext()) {throw "The data is invalid."}
        $Prime2 = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "Prime2 length: $($Prime2.Length)"

        # exponent1 d mod (p-1)
        if (!$asn.MoveNext()) {throw "The data is invalid."}
        $Exponent1 = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "Exponent1 length: $($Exponent1.Length)"

        # exponent2 d mod (q-1)
        if (!$asn.MoveNext()) {throw "The data is invalid."}
        $Exponent2 = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "Exponent2 length: $($Exponent2.Length)"

        # coefficient (inverse of q) mod p
        if (!$asn.MoveNext()) {throw "The data is invalid."}
        $Coefficient = __normalizeAsnInteger $asn.GetPayload()
        Write-Debug "Coefficient length: $($Coefficient.Length)"

        # creating Private Key BLOB structure
        $PrivateKey = __composePRIVATEKEYBLOB $modulus $PublicExponent $PrivateExponent $Prime1 $Prime2 $Exponent1 $Exponent2 $Coefficient

        # Region key attach and export routine
        $rsaKey = __attachPrivateKey $Cert $PrivateKey

        $pfxBytes = $Cert.Export("pfx", $Password)

        [System.IO.File]::WriteAllBytes($PfxFileName, $pfxBytes)

        $rsaKey.Dispose()
        [System.IO.FileInfo]$PfxFileName

        "[{0}] Created PFX certificate: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PfxFileName | Write-Verbose

    }

    End    
    {


    }

}

function Remove-HPOVScmbCertificate
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' appliance connection (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.count | Write-Verbose

            Try
            {

                $_keys = Send-HPOVRequest -Uri $ApplianceRabbitMQKeyPairUri -Hostname $_appliance

            }

            Catch [HPOneview.ResourceNotFoundException]
            {

                $ExceptionMessage = 'The SCMB certificate key pair has not bee generated on the appliance "{0}". Please use Get-HPOVScmbCertificates to generate a new certificate key pair.' -f $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneview.ResourceNotFoundException ResourceNotFound ObjectNotFound "ScmbCertifcateKeyPait" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSCmdlet.ShouldProcess($_appliance.Name, "Remove SCMB (RabbitMQ) rabbit_readonly user certificates"))
            {   
             
                Try
                {

                    Send-HPOVRequest -Uri $ApplianceRabbitMQKeyPairCertUri -Method DELETE -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Finally
                {


                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Import-HPOVSslCertificate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]

    Param 
    (
    
        [Parameter (ValueFromPipeline, Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['ApplianceConnection'])) 
        { 
            
            $PipelineInput = $True 
        
        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($_appliance -is [HPOneView.Appliance.Connection])
            {

                $_appliance = $_appliance.Name

            }

            "[{0}] Processing Appliance '{1}' (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance, $ApplianceConnection.Count | Write-Verbose

            try 
            {

                "[{0}] Getting response" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [System.Net.HttpWebRequest]$WebRequest = [System.Net.HttpWebRequest]::Create("https://$_appliance")

                $WebRequest.ServerCertificateValidationCallback = { $True }
                
                $Response = $WebRequest.GetResponse()
            
            }
            
            catch [Net.WebException] 
            { 

                if (-not($WebRequest.Connection) -and ([Int]$Response.StatusCode -eq 0)) 
                {

                    Write-Error $_.Exception.Message -Category ObjectNotFound -ErrorAction Stop

                } 

            }

            finally
            {

                # Close the response connection, as it is no longer needed, and will cause problems if left open.
                if ($Response) 
                {
                    
                    "[{0}] Closing response connection" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $Response.Close() 
                
                }

                $Response.Dispose()

            }        

            if ($null -ne $WebRequest.ServicePoint.Certificate) 
            {

                # Get certificate
                $Cert = [Security.Cryptography.X509Certificates.X509Certificate2]$WebRequest.ServicePoint.Certificate

                $StoreScope = "CurrentUser"
                $StoreName  = "Root" 

                # Save to users Trusted Root Authentication Hosts store
                $store = New-Object System.Security.Cryptography.X509Certificates.X509Store $StoreName, $StoreScope

                $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)

                try 
                {

                    "[{0}] Attempting to add cert to store" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $store.Add($cert)
                    $store.Close()

                    "[{0}] Cert added successfully" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                catch 
                {

                    $store.Close()
                    # Write-Error $_.Exception.Message -Category InvalidResult -ErrorAction Stop
                    $PSCmdlet.ThrowTerminatingError($_.Exception)

                }

            }

        }

    }
    
    End    
    { 
        
        Write-Warning "Please note that the Subject Alternate Name (SAN) must match that of the Appliance hostname you use to connect to your appliance. If it does not, an SSL connection failure will occur. When creating a CSR on the appliance, make sure to include the additional FQDN and IP address(es) in the Alternative Name field." 
    
    }

}

function Restart-HPOVAppliance 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
    
        [Parameter (ValueFromPipeline, Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['ApplianceConnection'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if (-not($ApplianceConnection))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance '$($_appliance.Name)' (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Appliance Restart being request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Presenting confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($PSCmdlet.ShouldProcess(("Restart appliance {0}" -f $_appliance.Name),"WARNING: Restarting the appliance will cause all users to be disconnected and all ongoing tasks to be interrupted.",('Perform operation "Restart appliance" on target "{0}"?' -f $_appliance.Name)))
            {

                "[{0}] User confirmed appliance shutdown." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose    
                
                Try
                {

            
                    $_resp = Send-HPOVRequest -uri $script:applianceRebootUri -method POST -Hostname $_appliance

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
            elseif ($PSBoundParameters['Whatif'])
            {

                "[{0}] User passed -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled shutdown request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
        
        }
        
    }

    End
    {

        Return $TaskCollection

    }

}

function Stop-HPOVAppliance 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
    
        [Parameter (ValueFromPipeline, Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['ApplianceConnection']) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
                
        $TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance '$($_appliance.Name)' (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Appliance SHUTDOWN being requested..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Presenting confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($PSCmdlet.ShouldProcess(("Shutdown appliance {0}" -f $_appliance.Name),"WARNING: Shutdown of the appliance will cause all users to be disconnected and all ongoing tasks to be interrupted.",('Perform operation "Shutdown appliance" on target "{0}"?' -f $_appliance.Name)))
            {

                "[{0}] User confirmed appliance shutdown." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose    
                
                Try
                {

                    $_resp = Send-HPOVRequest -uri $applianceShutDownUri POST -Hostname $_appliance

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [void]$TaskCollection.Add($_resp)

            }

            elseif ($PSBoundParameters['Whatif'])
            {

                "[{0}] User passed -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled shutdown request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
        
        }
        
    }

    End
    {

        Return $TaskCollection

    }

}

#######################################################
# Facilities:
#

function Get-HPOVRack
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_RackCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $uri = $DataCenterRacksUri.Clone()

        if ($Name)
        {

            $method = 'EQ'

            if ($Name.Contains('*'))
            {

                $method = 'matches'

            }

            $uri = "{0}?filter=name {1} '{2}'" -f $uri, $method, $Name.Replace('*','%25').Replace('?','%26')

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            try
            {

                $Resp = Send-HPOVRequest -Uri $uri -Hostname $_appliance

            }

            catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($Resp.count -eq 0 -and $Name)
            {

                $ExceptionMessage = 'The "{0}" rack was not found on {1}. Please check the name and try again.' -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ResourceNotFoundException ObjectNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

             $resp.members | ForEach-Object {

                 $_.PSObject.TypeNames.Insert(0,'HPOneView.Facilities.Rack')

                [void]$_RackCol.Add($_)

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $_RackCol

    }

}

function New-HPOVRack
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$ThermalLimit,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$PartNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Model,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$Depth = 1000,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$Height = 2004,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$UHeight = 40,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$Width = 600,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_RackCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $_Rack = NewObject -Rack
        $_Rack.name          = $Name
        $_Rack.thermalLimit  = $ThermalLimit
        $_Rack.serialNumber  = $SerialNumber
        $_Rack.partNumber    = $PartNumber
        $_Rack.model         = $Model
        $_Rack.depth         = $Depth
        $_Rack.height        = $Height
        $_Rack.uHeight       = $UHeight
        $_Rack.width         = $Width

        Try
        {

            Send-HPOVRequest -Uri $DataCenterRacksUri -Method POST -Body $_Rack -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

Function Add-HPOVResourceToRack
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
      
    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$Rack,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Int]$ULocation,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $InputObject)
        {

            $PipelineInput - $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_Collection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($Rack.category -ne 'racks')
        {

            $ExceptionMessage = 'The Rack is not a valid Rack object.'
            $ErrorRecord = New-ErrorRecord HPOneview.RackResourceException InvalidParameter InvalidArgument 'Rack' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Get the most current version of the object
        Try
        {

            $Rack = Send-HPOVRequest -Uri $Rack.uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        switch ($InputObject.category)
        {

            'server-hardware'
            {

                $_RelativeOrder = 0
                [Int]$_UHeight = $InputObject.formFactor.Replace('U',$null)

            }

            'unmanaged-devices'
            {

                $_RelativeOrder = 0
                [Int]$_UHeight = $InputObject.height

            }

            'enclosures'
            {

                $_RelativeOrder = -1
                [Int]$_UHeight = 10

            }

            # Unsupported type
            default
            {

                $ExceptionMessage = 'The resource {0} you are attempting to associate with the Rack {1} is not a supported object.' -f $InputObject.name, $Rack.name
                $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidParameter InvalidArgument 'InputObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        if (($ULocation + $_UHeight - 1) -le 0)
        {

            $ExceptionMessage = 'The resource {0} you are attempting to associate with the Rack {1} at {2} U location is not valid. The device is {3} Rack Units in size and cannot fit at {2} U rack position.' -f $InputObject.name, $Rack.name, $_UHeight, $ULocation
            $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidParameter InvalidArgument 'Rack' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_RackItem = NewObject -RackItem
        $_RackItem.mountUri      = $InputObject.uri
        $_RackItem.relativeOrder = $_RelativeOrder
        $_RackItem.topUSlot      = $ULocation + $_UHeight - 1
        $_RackItem.uHeight       = $_UHeight

        $_OriginalRackContents = [Array]$Rack.rackMounts.Clone()
        $Rack.rackMounts = [System.Collections.ArrayList]::new()

        $_OriginalRackContents | ForEach-Object { [void]$Rack.rackMounts.Add($_) }
        [void]$Rack.rackMounts.Add($_RackItem)

        Try
        {

            Send-HPOVRequest -Uri $Rack.uri -Method PUT -Body $Rack -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVRackMember
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_RackCol        = [System.Collections.ArrayList]::new()
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Rack Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

            If ('racks' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'racks'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Get most current Rack object version" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

            Try
            {

                $InputObject = Send-HPOVRequest -Uri $InputObject.uri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else 
        {

            "[{0}] Processing Rack Name {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

            Try
            {

                $InputObject = Get-HPOVRack -Name $InputObject -ApplianceConnection $ApplianceConnection -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Get list of rack mounted objects to then either return to the caller or search for specific resource name
        ForEach ($_RackItem in $InputObject.rackMounts)
        {

            Try
            {

                $_RackItemObject = Send-HPOVRequest -Uri $_RackItem.mountUri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            switch ($_RackItemObject.category)
            {

                'server-hardware'
                {

                    $_Model = $_RackItemObject.model
                    [Int]$_UHeight = $_RackItemObject.formFactor.Replace('U',$null)

                }

                'unmanaged-devices'
                {

                    $_Model = $_RackItemObject.model
                    [Int]$_UHeight = $_RackItemObject.height

                }

                'enclosures'
                {

                    $_Model = $_RackItemObject.enclosureModel
                    [Int]$_UHeight = 10

                }

            }

            $_RackULocation = $_RackItem.topUSlot - $_UHeight + 1

            Try
            {

                $_RackMember = New-Object HPOneView.Facilities.RackMember($_RackItemObject.name, $_Model, $_UHeight, $_RackULocation, $_RackItemObject.uri, $InputObject.name, $InputObject.uri, $_RackItemObject.ApplianceConnection)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [void]$_RackCol.Add($_RackMember)

        }

        if ($Name)
        {

            $_RackCol = $_RackCol | Where-Object { $_.Name -match $Name }

            if (-not $_RackCol)
            {

                $ExceptionMessage = 'The "{0}" rack member was not found in {1}. Please check the name and try again.' -f $Name, $InputObject.name
                $ErrorRecord = New-ErrorRecord HPOneView.ResourceNotFoundException ObjectNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

        }

        $_RackCol

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVRackMemberLocation
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Facilities.RackMember]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Int]$ULocation,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_RackCol        = [System.Collections.ArrayList]::new()
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        "[{0}] RackMember Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        If (-not($InputObject.ApplianceConnection))
        {

            $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Get Rack from member
        Try
        {

            $Rack = Send-HPOVRequest -Uri $InputObject.RackUri -Hostname $InputObject.ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        ($Rack.rackMounts | Where-Object mountUri -eq $InputObject.Uri).topUSlot = ($ULocation + $InputObject.UHeight - 1)

        Try
        {

            Send-HPOVRequest -Uri $Rack.uri -Method PUT -Body $Rack -Hostname $Rack.ApplianceConnection | Out-Null

            Get-HPOVRackMember -InputObject $Rack -Name $InputObject.Name -ErrorAction Stop

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVRackMember
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [HPOneView.Facilities.RackMember]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_RackCol        = [System.Collections.ArrayList]::new()
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $RemoveMessage = "Remove Rack member '{0}'" -f $InputObject.Name

        if ($PSCmdlet.ShouldProcess($InputObject.RackName, $RemoveMessage))
        {   
                        
            Try
            {
                
                # Get Rack resource object, which is what needs to be modified.
                $Rack = Send-HPOVRequest -Uri $InputObject.RackUri -Hostname $InputObject.ApplianceConnection

                [Array]$Rack.rackMounts = $Rack.rackMounts | Where-Object mountUri -ne $InputObject.Uri
                
                Send-HPOVRequest -Uri $Rack.uri -Method PUT -Body $Rack -Hostname $Rack.ApplianceConnection -addHeader @{'If-Match' = $Rack.eTag}

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVRack
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_RackCol        = [System.Collections.ArrayList]::new()
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Rack Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('racks' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_RackCol.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.RackResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'racks'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            For ($c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceConnection[$c].Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Processing DataCenter Name {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

                Try
                {

                    $_Racks = Get-HPOVRack -Name $InputObject -ApplianceConnection $ApplianceConnection[$c]

                    $_Racks | ForEach-Object {

                        [void]$_RackCol.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_rack in $_RackCol) 
        {

            $RemoveMessage = "Remove Rack '{0}'" -f $_rack.Name

            if ($PSCmdlet.ShouldProcess($_rack.ApplianceConnection,$RemoveMessage))
            {   
                            
                Try
                {
                
                    Send-HPOVRequest -Uri $_rack.uri -Method DELETE -Hostname $_rack.ApplianceConnection -addHeader @{'If-Match' = $_rack.eTag}

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
                        
        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVDataCenter
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        $Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_DCCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $uri = $DataCentersUri.Clone()

        if ($Name)
        {

            $method = 'EQ'

            if ($Name.Contains('*'))
            {

                $method = 'matches'

            }

            $uri = "{0}?filter=name {1} '{2}'" -f $uri, $method, $Name.Replace('*','%25').Replace('?','%26')

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            '[{0}] Processing "{1}" appliance connection.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            try
            {

                $Resp = Send-HPOVRequest -Uri $uri -Hostname $_appliance

            }

            catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($Resp.count -eq 0 -and $Name)
            {

                $ExceptionMessage = 'The "{0}" datacenter was not found on {1}. Please check the name and try again.' -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ResourceNotFoundException ObjectNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                Try
                {

                    $RemoteSupportConfigured = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $_appliance.Name

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($RemoteSupportConfigured.enableRemoteSupport)
                {

                    '[{0}] Appliance has Remote Support enabled. Collecting DataCenter location and contact information.' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                    ForEach ($member in $resp.members)
                    {

                        Try
                        {

                            $_DCRemoteSupportLocation = Send-HPOVRequest -uri $member.remoteSupportUri -Hostname $_appliance.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $member | Add-Member -NotePropertyName RemoteSupportLocation -NotePropertyValue ([HPOneView.Facilities.RemoteSupportLocation]$_DCRemoteSupportLocation)

                        $member.PSObject.TypeNames.Insert(0,'HPOneView.Facilities.DataCenter')

                        [void]$_DCCol.Add($member)

                    }

                }

                else
                {

                    $resp.members | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,'HPOneView.DataCenter')

                        [void]$_DCCol.Add($_)

                    }

                }

            }

        }

    }

    End
    {

        Return $_DCCol

    }

}

function New-HPOVDataCenter
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Float]$Width,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Float]$Depth,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [Switch]$Millimeters,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Int]$ElectricalDerating = 20,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateSet ('NaJp', 'Custom', 'None')]
        [String]$ElectricalDeratingType = 'NaJp',

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Int]$DefaultVoltage = 220,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$Currency = 'USD',

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Float]$PowerCosts,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Int]$CoolingCapacity,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Float]$CoolingMultiplier = 1.5,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Object]$PrimaryContact,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [Object]$SecondaryContact,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$Address1,

        [Parameter (Mandatory = $False, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$Address2,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$PostCode,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$Country,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullOrEmpty()]
        [String]$TimeZone,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RemoteSupport')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ApplianceRemoteSupportCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $RemoteSupportStatus = $null

        if ($PSCmdlet.ParameterSetName -eq 'RemoteSupport')
        {

            "[{0}] Validate Remote Support is configured on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $RemoteSupportStatus = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $RemoteSupportStatus.enableRemoteSupport)
            {

                "[{0}] Remote Support is not enabled and configured on the appliance. Generate non-terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = 'Remote Support is not configured on the appliance, {0}. In order to set the Remote Support location for the DataCenter, Remote SUpport must be enabledon the appliance. Either enable Remote Support or do not attempt to set the Data Center location until Remote Support has been anabled on the appliance.' -f $ApplianceConnection.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportException RemoteSupportNotEnabled InvalidOperation 'ApplianceConnect' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                "[{0}] Remote Support is enabled and configured on the appliance. Will set Data Center RS location." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_DataCenterAddressPatchOp = [System.Collections.ArrayList]::new()

                switch ($PSBoundParameters.Keys)
                {

                    'Address1'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/streetAddress1'
                        $_PatchOperation.value = $Address1

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'Address2'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/streetAddress2'
                        $_PatchOperation.value = $Address2

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'City'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/city'
                        $_PatchOperation.value = $City

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'State'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/provinceState'
                        $_PatchOperation.value = $State

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'PostCode'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/postalCode'
                        $_PatchOperation.value = $PostCode

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'Country'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/countryCode'
                        $_PatchOperation.value = $Country

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'TimeZone'
                    {

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/timeZone'
                        $_PatchOperation.value = $TimeZone

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'PrimaryContact'
                    {

                        if ($PrimaryContact.Type -ne 'Contact')
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "PrimaryContact" -TargetType PSObject -Message "The PrimaryContact object resource provided is not a Remote Support Contact. Please use the Get-HPOVRemoteSupportContact Cmdlet to get a valid contact object."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/primaryContactUri'
                        $_PatchOperation.value = $PrimaryContact.uri

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                    'SecondaryContact'
                    {

                        if ($SecondaryContact.Type -ne 'Contact')
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "SecondaryContact" -TargetType PSObject -Message "The SecondaryContact object resource provided is not a Remote Support Contact. Please use the Get-HPOVRemoteSupportContact Cmdlet to get a valid contact object."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_PatchOperation = NewObject -PatchOperation
                        $_PatchOperation.op    = 'replace'
                        $_PatchOperation.path  = '/secondaryContactUri'
                        $_PatchOperation.value = $SecondaryContact.uri

                        [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                    }

                }

                if ($PrimaryContact.uri -eq $SecondaryContact.uri)
                {

                    "[{0}] Primary and Secondary Contact are the same. Must be uniquel; generating terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ExceptionMessage =  "Both the PrimaryContact and SecondaryContact objects are the same. Please specify unique Primary and Secondary contacts." 
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "PrimaryContact" -TargetType PSObject -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        if (-not $Millimeters.IsPresent)
        {

            # Convert from Feet to Millimeters
            $Width = [Math]::Round($Width * .3048 * 1000, 2)
            $Depth = [Math]::Round($Depth * .3048 * 1000, 2)

        }    

        $NewDataCenter = NewObject -DataCenter
        $NewDataCenter.name                    = $Name
        $NewDataCenter.coolingCapacity         = $CoolingCapacity
        $NewDataCenter.costPerKilowattHour     = $PowerCosts
        $NewDataCenter.currency                = $Currency
        $NewDataCenter.deratingType            = $ElectricalDeratingType
        $NewDataCenter.deratingPercentage      = $ElectricalDerating
        $NewDataCenter.defaultPowerLineVoltage = $DefaultVoltage
        $NewDataCenter.coolingMultiplier       = $CoolingMultiplier
        $NewDataCenter.width                   = $Width
        $NewDataCenter.depth                   = $Depth

        # Create DC
        Try
        {

            $Resp = Send-HPOVRequest -Uri $DataCentersUri -Method POST -Body $NewDataCenter -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Update Remote Support DC if needed
        if ($_DataCenterAddressPatchOp.Count -gt 0)
        {

            "[{0}] Modifying datacenter Remote Support location to the specified value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_UpdateDCLocationResults = Send-HPOVRequest -Uri $Resp.remoteSupportUri -Method PATCH -Body $_DataCenterAddressPatchOp -Hostname $ApplianceConnection | Wait-HPOVTaskComplete

                if ($_UpdateDCLocationResults.taskState -ne 'Completed')
                {

                    $ExceptionMessage = 'Updating the datacenter with the specified location did not complete successfully with: {0}' -f [String]::Join(' ', $_UpdateDCLocationResults.taskErrors)
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportException InvalidOperation InvalidOperation 'ApplianceConnect' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Send-HPOVRequest -Uri $Resp.uri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            $Resp

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVRackToDataCenter
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
      
    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$DataCenter,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Int]$X,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Int]$Y,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Millimeters,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateRange(0,360)]
        [Int]$Rotate = 0,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $InputObject)
        {

            $PipelineInput - $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_Collection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($InputObject.category -ne 'racks')
        {

            $ExceptionMessage = 'The InputObject is not a valid Rack object.'
            $ErrorRecord = New-ErrorRecord HPOneview.RackResourceException InvalidParameter InvalidArgument 'InputObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($DataCenter.category -ne 'datacenters')
        {

            $ExceptionMessage = 'The DataCenter is not a valid data center object.'
            $ErrorRecord = New-ErrorRecord HPOneview.DatacenterResourceException InvalidParameter InvalidArgument 'DataCenter' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Get the most current version of the object
        Try
        {

            $DataCenter = Send-HPOVRequest -Uri $DataCenter.uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_DataCenterToUpdate = $DataCenter.PSObject.Copy()

        $_UpdatedAssociations = $_DataCenterToUpdate.contents
        
        $_DataCenterToUpdate.contents = [System.Collections.ArrayList]::new()
        $_UpdatedAssociations | ForEach-Object { [void]$_DataCenterToUpdate.contents.Add($_) }

        if (-not $Millimeters.IsPresent)
        {

            # Convert from Feet to Millimeters
            $X = [Math]::Round([Int]$X * .3048 * 1000, 2)
            $Y = [Math]::Round([Int]$Y * .3048 * 1000, 2)

        }        

        $_NewDCItem = NewObject -DataCenterItem
        $_NewDCItem.resourceUri = $InputObject.uri
        $_NewDCItem.rotation    = $Rotate
        $_NewDCItem.x           = $X
        $_NewDCItem.y           = $y

        [void]$_DataCenterToUpdate.contents.Add($_NewDCItem)

        Try
        {

            Send-HPOVRequest -Uri $DataCenter.uri -Method PUT -Body ($_DataCenterToUpdate | Select-Object * -Exclude RemoteSupportLocation) -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVDataCenterRemoteSupport
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$PrimaryContact,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$SecondaryContact,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Address1,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Address2,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$State,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$PostCode,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Country,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$TimeZone,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }    

        $_ApplianceRemoteSupportCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Remote Support Contact Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('datacenters' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.DataCenterResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.DataCenterResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'DataCenters'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else
        {

            Try
            {

                $InputObject = Get-HPOVDataCenter -Name $InputObject -ApplianceConnection $ApplianceConnection -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $RemoteSupportStatus = $null

        "[{0}] Validate Remote Support is configured on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $RemoteSupportStatus = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $RemoteSupportStatus.enableRemoteSupport)
        {

            "[{0}] Remote Support is not enabled and configured on the appliance. Generate non-terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ExceptionMessage = 'Remote Support is not configured on the appliance, {0}. In order to set the Remote Support location for the DataCenter, Remote SUpport must be enabledon the appliance. Either enable Remote Support or do not attempt to set the Data Center location until Remote Support has been anabled on the appliance.' -f $ApplianceConnection.Name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportException RemoteSupportNotEnabled InvalidOperation 'ApplianceConnect' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            "[{0}] Remote Support is enabled and configured on the appliance. Will set Data Center RS location." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_DataCenterAddressPatchOp = [System.Collections.ArrayList]::new()

            switch ($PSBoundParameters.Keys)
            {

                'Address1'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/streetAddress1'
                    $_PatchOperation.value = $Address1

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'Address2'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/streetAddress2'
                    $_PatchOperation.value = $Address2

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'City'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/city'
                    $_PatchOperation.value = $City

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'State'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/provinceState'
                    $_PatchOperation.value = $State

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'PostCode'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/postalCode'
                    $_PatchOperation.value = $PostCode

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'Country'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/countryCode'
                    $_PatchOperation.value = $Country

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'TimeZone'
                {

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/timeZone'
                    $_PatchOperation.value = $TimeZone

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'PrimaryContact'
                {

                    if ($PrimaryContact.Type -ne 'Contact')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "PrimaryContact" -TargetType PSObject -Message "The PrimaryContact object resource provided is not a Remote Support Contact. Please use the Get-HPOVRemoteSupportContact Cmdlet to get a valid contact object."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/primaryContactUri'
                    $_PatchOperation.value = $PrimaryContact.uri

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

                'SecondaryContact'
                {

                    if ($SecondaryContact.Type -ne 'Contact')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "SecondaryContact" -TargetType PSObject -Message "The SecondaryContact object resource provided is not a Remote Support Contact. Please use the Get-HPOVRemoteSupportContact Cmdlet to get a valid contact object."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_PatchOperation = NewObject -PatchOperation
                    $_PatchOperation.op    = 'replace'
                    $_PatchOperation.path  = '/secondaryContactUri'
                    $_PatchOperation.value = $SecondaryContact.uri

                    [void]$_DataCenterAddressPatchOp.Add($_PatchOperation)

                }

            }

            if (($PSBoundParameters['PrimaryContact'] -or $PSBoundParameters['SecondaryContact']) -and $PrimaryContact.uri -eq $SecondaryContact.uri)
            {

                "[{0}] Primary and Secondary Contact are the same. Must be unique; generating terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage =  "Both the PrimaryContact and SecondaryContact objects are the same. Please specify unique Primary and Secondary contacts." 
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportContactException InvalidArgumentValue InvalidArgument "PrimaryContact" -TargetType PSObject -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        # Update Remote Support DC if needed
        if ($_DataCenterAddressPatchOp.Count -gt 0)
        {

            "[{0}] Modifying datacenter Remote Support location to the specified value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_UpdateDCLocationResults = Send-HPOVRequest -Uri $InputObject.remoteSupportUri -Method PATCH -Body $_DataCenterAddressPatchOp -Hostname $ApplianceConnection

                if (-not $Async.IsPresent)
                {

                    $_UpdateDCLocationResults = $_UpdateDCLocationResults | Wait-HPOVTaskComplete

                    if ($_UpdateDCLocationResults.taskState -ne 'Completed')
                    {

                        $ExceptionMessage = 'Updating the datacenter with the specified location did not complete successfully with: {0}' -f [String]::Join(' ', $_UpdateDCLocationResults.taskErrors)
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportException InvalidOperation InvalidOperation 'ApplianceConnect' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                $_UpdateDCLocationResults

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            "[{0}] Nothing to do." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVDataCenter
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Float]$Width,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Float]$Depth,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Millimeters,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$ElectricalDerating,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('NaJp', 'Custom', 'None')]
        [String]$ElectricalDeratingType,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$DefaultVoltage,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Currency,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Float]$PowerCosts,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$CoolingCapacity,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Float]$CoolingMultiplier,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }    

        $_ApplianceRemoteSupportCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Remote Support Contact Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('datacenters' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.DataCenterResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.DataCenterResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'DataCenters'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else
        {

            Try
            {

                $InputObject = Get-HPOVDataCenter -Name $InputObject -ApplianceConnection $ApplianceConnection -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_DataCenterObject = $InputObject.PSObject.Copy()

        switch ($PSBoundParameters.Keys)
        {

            'Name'
            {

                $_DataCenterObject.name = $Name

            }

            'Width'
            {

                if (-not $Millimeters.IsPresent)
                {

                    # Convert from Feet to Millimeters
                    $Width = [Math]::Round($Width * .3048 * 1000, 2)

                }    

                $_DataCenterObject.width = $Width

            }

            'Depth'
            {

                if (-not $Millimeters.IsPresent)
                {

                    # Convert from Feet to Millimeters
                    $Depth = [Math]::Round($Depth * .3048 * 1000, 2)

                }

                $_DataCenterObject.depth = $Depth

            }

            'ElectricalDerating'
            {

                if ($PSBoundParameters['ElectricalDeratingType'] -ne 'Custom')
                {

                    $ExceptionMessage = 'The ElectricalDerating paraemter was used with a custom value, without providing the ElectricalDeratingType parameter. ElectricalDerating will not be set to the value.'
                    $ErrorRecord = New-ErrorRecord HPOneview.DataCenterResourceException InvalidParameter InvalidArgument 'ElectricalDerating' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else
                {

                    $_DataCenterObject.deratingPercentage = $ElectricalDerating

                }

            }

            'ElectricalDeratingType'
            {

                if ($PSBoundParameters['ElectricalDerating'] -eq 'Custom' -and (-not $PSBoundParameters['ElectricalDerating']))
                {

                    $ExceptionMessage = 'The ElectricalDeratingType paraemter is set to "Custom" without providing the ElectricalDerating parameter. ElectricalDeratingType will not be set to the value.'
                    $ErrorRecord = New-ErrorRecord HPOneview.DataCenterResourceException InvalidParameter InvalidArgument 'ElectricalDeratingType' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else
                {

                    $_DataCenterObject.deratingType = $ElectricalDeratingType

                    $NeedToUpdateTwice = $false

                    if ($ElectricalDeratingType -eq 'Custom')
                    {

                        $NeedToUpdateTwice = $true

                    }

                }

            }

            'DefaultVoltage'
            {

                $_DataCenterObject.defaultPowerLineVoltage = $DefaultVoltage

            }

            'Currency'
            {

                $_DataCenterObject.currency = $Currency

            }

            'PowerCosts'
            {

                $_DataCenterObject.costPerKilowattHour = $PowerCosts

            }

            'CoolingCapacity'
            {

                $_DataCenterObject.coolingCapacity = $CoolingCapacity

            }

            'CoolingMultiplier'
            {

                $_DataCenterObject.coolingMultiplier = $CoolingMultiplier

            }
            
        }

        Try
        {

            $Resp = Send-HPOVRequest -Uri $_DataCenterObject.uri -Method PUT -Body ($_DataCenterObject | Select-Object * -Exclude RemoteSupportLocation) -Hostname $_DataCenterObject.ApplianceConnection

            if ($NeedToUpdateTwice)
            {

                "[{0}] Need to update the DC object again in order to set deratingPercentage custom value" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $resp.deratingPercentage = $ElectricalDerating

                $Resp = Send-HPOVRequest -Uri $Resp.uri -Method PUT -Body ($Resp | Select-Object * -Exclude RemoteSupportLocation) -Hostname $Resp.ApplianceConnection

            }

            $Resp

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVDataCenter
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

       [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {
    
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

        $_DataCenterCol  = [System.Collections.ArrayList]::new()
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        if ($InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Datacenter Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('datacenters' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.DataCenterResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The InputObject object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_DataCenterCol.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.DataCenterResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message "The InputObject object resource is not an expected type. The allowed resource category type is 'DataCenters'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            For ($c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceConnection[$c].Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Processing DataCenter Name {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

                Try
                {

                    $_DataCenter = Get-HPOVDataCenter -Name $InputObject -ApplianceConnection $ApplianceConnection[$c]

                    $_DataCenter | ForEach-Object {

                        [void]$_DataCenterCol.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_dc in $_DataCenterCol) 
        {

            $RemoveMessage = "Remove DataCenter '{0}'" -f $_dc.Name

            if ($PSCmdlet.ShouldProcess($_dc.ApplianceConnection,$RemoveMessage))
            {   
                            
                Try
                {
                
                    $resp = Send-HPOVRequest $_dc.uri DELETE -Hostname $_dc.ApplianceConnection -addHeader @{'If-Match' = $_dc.eTag}
                    $resp | Add-Member -NotePropertyName ResourceName -NotePropertyValue $_dc.Name
                    $resp

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
                        
        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Server Hardware and Enclosures:
#

function Get-HPOVServer 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$ServerName,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('Critical', 'Warning', 'OK', 'Unknown', 'Disabled')]
        [string[]]$Status,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$NoProfile,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Default")]
        [Alias ('ServerHardwareType','ServerProfileTemplate')]
        [ValidateNotNullOrEmpty()]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Int]$Count,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($ServerName)
            {

                if ($ServerName.Contains('*'))
                {

                    [Void]$_Query.Add(("serverName%3A%2A{0}" -f $ServerName.Replace("*", "%2A").Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("serverName:'{0}'" -f $ServerName))

                }                
                
            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            if ($Status)
            {

                $_StatusQuery = [System.Collections.ArrayList]::new()

                ForEach ($_status in $Status)
                {

                    [Void]$_StatusQuery.Add(("status:'{0}'" -f $_status))

                }

                [void]$_Query.Add([String]::Join(' OR ', $_StatusQuery.ToArray()))

            }

            $_Category = 'category=server-hardware'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Filter collection for resources without profile assigned
            if ($PSBoundParameters['NoProfile']) 
            { 
                
                "[{0}] Filtering for server hardware with no assigned profiles." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object { $null -eq $_.serverProfileUri }
            
            }

            # Filter collection for resources that match the SHT of inputobject provided
            if ($InputObject)
            {

                switch ($InputObject.category)
                {

                    $ResourceCategoryEnum.ServerProfileTemplate
                    {

                        $_FilterProperty = "serverHardwareTypeUri"

                        $_FilterUri = $InputObject.serverHardwareTypeUri

                    }

                    $ResourceCategoryEnum.ServerProfile
                    {

                        $_FilterProperty = "serverProfileUri"

                        $_FilterUri = $InputObject.uri

                    }

                    $ResourceCategoryEnum.ServerHardwareType
                    {

                        $_FilterProperty = "serverHardwareTypeUri"

                        $_FilterUri = $InputObject.uri

                    }

                    default
                    {

                        if ($InputObject.PSObject.properties -match 'category')
                        {

                            $InputObjectName = $InputObject.name.Clone()

                        }

                        else
                        {

                            $InputObjectName = $InputObject.Clone()

                        }

                        $ExceptionMessage = "The provided InputObject parameter value, '{0}', is not a supported resource type. Only server profile template or server hardware type resources are supported. Please check the value, and try again." -f $InputObjectName
                        $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidInputObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                "FilterProperty: {0}" -f $_FilterProperty | Write-Verbose
                "FilterUri: {0}" -f $_FilterUri | Write-Verbose

                $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object { $_.$_FilterProperty -eq $_FilterUri }

            }

            if ($Count)
            {

                $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Select-Object -First $Count

            }


            if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
            {
                    
                $ExceptionMessage = "Server Hardware '{0}' not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException ServerHardwareResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            if ($_ResourcesFromIndexCol.count -eq 0 -and $ServerName) 
            {
                    
                $ExceptionMessage = "Server Hardware OS Server Name '{0}' not found on '{1}' appliance connection. Please check the name again, and try again." -f $ServerName, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException ServerHardwareResourceNotFound ObjectNotFound 'ServerName' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($s in ($_ResourcesFromIndexCol | Sort-Object name)) 
                {

                    $s.PSObject.TypeNames.Insert(0,'HPOneView.ServerHardare')

                    $s

                }

            }    

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVIloSso
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Default')]
        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'IloRestSession')]
        [ValidateNotNullOrEmpty()]
        [Alias('Server')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$RemoteConsoleOnly,        

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'IloRestSession')]
        [Switch]$IloRestSession,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "IloRestSession")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not($InputObject -is [PSCustomObject]) -or (-not($InputObject.ApplianceConnection)))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The specified 'InputObject' is not an object or is missing the 'ApplianceConnection' property. Please correct this value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                Try 
                {
    
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $InputObject.ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if (-not($PipelineInput) -and (-not($InputObject -is [PSCustomObject])))
        {

            $ExceptionMessage = "The specified 'InputObject' is not an object. Please correct this value and try again."
            $ErrorRecord = New-ErrorRecord HPOneview.ServerResourceException InvalidServerObject InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ('server-hardware',$ResourceCategoryEnum.ServerProfile  -notcontains $InputObject.category)
        {
            
            $ExceptionMessage = "The specified 'InputObject' is not a Server or Server Profile object. Please correct this value and try again."
            $ErrorRecord = New-ErrorRecord HPOneview.ServerResourceException InvalidObject InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.category -eq $ResourceCategoryEnum.ServerProfile )
        {

            "[{0}] Server Profile was provided." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            $_uri = $InputObject.serverHardwareUri

            # get server hardware from resource
            try
            {

                $_Server = Send-HPOVRequest -Uri $_uri -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            "[{0}] Server Hardware was provided." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            $_uri = $InputObject.uri

            $_Server = $InputObject

        }

        if ($PSBoundParameters['RemoteConsoleOnly'])
        {

            $_uri = $_uri + '/remoteConsoleUrl'

        }

        else
        {

            $_uri = $_uri + '/iloSsoUrl'

        }        

        "[{0}] Processing {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        Try
        {
        
            $_ssoresp = Send-HPOVRequest -URI $_uri -Hostname $InputObject.ApplianceConnection
        
        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['IloRestSession'])
        {

            "[{0}] Returning iLO SSO Session" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_ssoresp

        }

        else
        {

            "[{0}] Generating and returning iLO REST/RedFish SSO Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $CookieContainer = New-Object System.Net.CookieContainer
                
                [System.Net.HttpWebRequest]$WebRequest          = [System.Net.HttpWebRequest]::Create($_ssoresp.iloSsoUrl)
                $WebRequest.CookieContainer                     = $CookieContainer
                $WebRequest.Accept                              = 'application/json, *.*'
                $WebRequest.ServerCertificateValidationCallback = { $True }
                
                "[{0}] Getting Redfish SessionID token from iLO, {1}." -f $MyInvocation.InvocationName.ToString().ToUpper(), ([URI]$_ssoresp.iloSsoUrl).Host | Write-Verbose

                $Response = $WebRequest.GetResponse()
                $Response.Close()
                $Response.Dispose()

                "[{0}] Getting Redfish SessionID token from cookies." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $SessionID = $CookieContainer.GetCookieHeader($_ssoresp.iloSsoUrl)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Building iLO Session Object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            switch ($_Server.mpModel)
            {

                'iLO5'
                {

                    $_RootUri = "https://{0}/redfish/v1" -f ([URI]$_ssoresp.iloSsoUrl).Host

                }

                'iLO4'
                {

                    $_RootUri = "https://{0}/rest/v1" -f ([URI]$_ssoresp.iloSsoUrl).Host

                }

            }

            $IloSession                = NewObject -IloRestSession
            $IloSession.RootUri        = $_RootUri
            $IloSession.'X-Auth-Token' = $SessionID.Replace('sessionKey=',$null)

            $IloSession

        }
       
    }

    End 
    {
        
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVServer 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Managed", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = "Monitored")]
        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = "Managed")]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,
         
        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [ValidateSet ("OneView", "OneViewNoiLO")]
        [String]$LicensingIntent = 'OneView',

        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Switch]$Monitored,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $False, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $False, ParameterSetName = "Managed")]
        [Switch]$Async,

        [Parameter (Mandatory = $False, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $False, ParameterSetName = "Managed")]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if ($PSBoundParameters['Credential'])
        {

            $_Username = $Credential.Username
            $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        elseif ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username and -Password parameters are being deprecated. Please transition your scripts to using the -Credential parameter."

            $_Username = $Username.clone()

            if (-not $PSBoundParameters['Password'])
            {

                $ExceptionMessage = "The -Username parameter requires the -Password parameter. Or please use the -Credential parameter instead."
                $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredPasswordParameter InvalidOperation 'Password' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($Password -is [SecureString])
            {

                $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

            }

            else
            {

                $_Password = $Password.Clone()

            }

        }

        elseif (-not $PSBoundParameters['Credential'] -and -not $PSBoundParameters['Username'])
        {

            $ExceptionMessage = "This Cmdlet requires credentials to the target resource. Please provide either the -Username and -Password, or -Credential parameters."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredPasswordParameter InvalidOperation 'Authentication' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    Process 
    {

        # New Server Resource Object
        $_server = NewObject -ServerImport
        $_server.hostname        = $Hostname;
        $_server.username        = $_Username;
        $_server.password        = $_Password;
        $_server.licensingIntent = $LicensingIntent;        

        if ([Bool]$Monitored) 
        { 
        
            $_server.licensingIntent    = "OneViewStandard"
            $_server.configurationState = "Monitored"

        }

        else 
        { 
            
            $_server.configurationState = "Managed" 
        
        }

        if ($PSBoundParameters['Scope'])
        {

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_server.initialScopeUris.Add($_Scope.Uri)

            }

        }

        "[{0}] Sending request to add server resource {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname | Write-Verbose

        Try
        {
        
            $task = Send-HPOVRequest -Uri $ServerHardwareUri -Method POST -Body $_server -Hostname $ApplianceConnection.Name
        
        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        "[{0}] Initial task response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($resp | out-string) | Write-Verbose

        Try
        {
            
            $resp = Wait-HPOVTaskStart $task

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        "[{0}] Second task response: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($resp | out-string) | Write-Verbose

        # Check to see if the task errored, which should be in the Task Validation stage
        if ($resp.taskState -ne "Running") 
        {

            if (($resp.taskState -eq "Error") -and ($resp.stateReason -eq "ValidationError")) 
            {

                "[{0}] Task error found: {1}, {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $resp.taskState, $resp.stateReason | Write-Verbose
                
                # TaskErrors should contain only a single value, so we will force pick the first one.
                $errorMessage = $resp.taskerrors[0]
                
                switch ($errorMessage.errorCode) 
                {

                    {$_ -match "SERVER_ALREADY_*" }
                    { 

                        # Support different external manager process
                        if ([Uri]::IsWellFormedUriString($errorMessage.data.managementUrl, [System.UriKind]::Absolute))
                        {

                            $externalManagerType = $errorMessage.data.managementProduct

                            $externalManagerIP   = $errorMessage.data.managementUrl.Replace("https://","")

                            Try
                            {
                            
                                $externalManagerFQDN = [System.Net.DNS]::GetHostByAddress($externalManagerIP)
                            
                            }

                            Catch
                            {

                                "[{0}] Unable to resolve IP Address to DNS A Record." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                $externalManagerFQDN = [PSCustomObject]@{HostName = 'UnknownFqdn'; Aliases = @(); AddressList = @($externalManagerIP.Clone())}

                            }
                            
                            "[{0}] Found server '{1}' is already being managed by {2} at {3}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname, $externalManagerType, $externalManagerIP | Write-Verbose
                            "[{0}] {1} resolves to {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $externalManagerIP,  $($externalManagerFQDN | out-string) | Write-Verbose

                            write-warning ("Server '{0}' is already being managed by {1} at {2} ({3})." -f $hostname, $externalManagerType, $externalManagerIP,  $($externalManagerFQDN | out-string))

                            if ($PSCmdlet.ShouldProcess($hostname,("force add server that is already managed/monitored by {0} at {1} ({2})" -f $externalManagerType, $externalManagerIP, $externalManagerFQDN.HostName))) 
                            {
                        
                                "[{0}] Server was claimed and user chose YES to force add." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $_server | Add-Member -NotePropertyName force -NotePropertyValue $true -force | out-null
                                
                                Try
                                {

                                    $resp = Send-HPOVRequest -Uri $ServerHardwareUri -Method POST -BOdy $_server -Hostname $ApplianceConnection.Name

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }                            

                            }

                            else 
                            {

                                if ($PSBoundParameters['whatif'].ispresent) 
                                { 
                        
                                    write-warning "-WhatIf was passed, would have force added '$hostname' server to appliance."
                                    
                                    $resp = $null
                        
                                }

                                else 
                                {

                                    # If here, user chose "No", End Processing
                                    write-warning "Not importing server, $hostname."
                                    
                                    $resp = $Null

                                }

                            }

                        }

                        # Device is already added to appliance as Monitored or Managed resource
                        else
                        {

                            $_EmbeddedJson = ([Regex]::Match($errorMessage.message, "\{.*\}")).value | ConvertFrom-Json

                            if ($null -eq $_EmbeddedJson)
                            {

                                # Get the server hardware in $errorMessage.data.uri
                                Try
                                {

                                    $_Server = Send-HPOVRequest -Uri $errorMessage.data.uri -Hostname $ApplianceConnection

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                            }

                            else
                            {

                                $_Server = $_EmbeddedJson

                            }                            

                            # Throw exception that resource is already managed by the appliance as $Server.name
                            "[{0}] Generating error: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($errorMessage.message) | Write-Verbose

                            $ExceptionMessage = '"The server hardware has already been added as "{0}". {1} If the server is orphaned, use Remove-HPOVServer -Force Cmdlet, and then try your add again.' -f $_Server.name, $errorMessage.recommEndedActions
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException ServerResourceExists ResourceExists 'Hostname' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }
                    
                    }

                    "INVALID_ADDR" 
                    { 
                    
                        "[{0}] Generating error: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($errorMessage.message) | Write-Verbose
                        $ExceptionMessage = '{0} {1}' -f $errorMessage.message, $errorMessage.recommEndedActions
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException ServerResourceNotFound ObjectNotFound 'Hostname' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                }
                    
            }

        }

        if (-not($PSBoundParameters['Async']))
        {

            $resp | Wait-HPOVTaskComplete

        }

        else
        {

            $resp

        }        
       
    }

    End 
    {
        
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVServer 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name","Server")]
        [object]$InputObject,

        [Parameter (Mandatory = $false)] 
        [Switch]$Force,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_ServersToRemoveCol = [System.Collections.ArrayList]::new()
        $_TaskCollection     = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject])
        {

            "[{0}] Processing pipeline input objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # "[{0}] Received object: $($InputObject )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($InputObject.category -ne 'server-hardware')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException UnsupportedResourceCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided Server object {$($InputObject.name)} is an unsupported object category, '$($InputObject.category)'. Only 'server-hardware' category objects are supported. please check the Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Throw error that you cannot remove a BL server
            if ($null -ne $InputObject.locationUri -and [RegEx]::Match($InputObject.model,'BL|WS|SY').Success)
            {

                $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException CannotRemoveBLServerTypes InvalidOperation 'InputObject' -TargetType 'PSObject' -Message "The provided Server object {$($InputObject.name)} cannot be removed from the appliance, as it is a WS/BL server class. If you wish to remove a WS/BL server from the appliance, you either physically remove the server from the enclosure or remove the enclosure from the appliance. Please check the Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$_ServersToRemoveCol.Add($InputObject)

        }

        Else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing {1} appliance connection (of {2})." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                Try
                {

                    "[{0}] Getting '{1}' server from Get-HPOVServer." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

                    $_InputObject = Get-HPOVServer -Name $InputObject -ApplianceConnection $_appliance -ErrorAction SilentlyContinue

                    [void]$_ServersToRemoveCol.Add($_InputObject)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    End
    {

        "[{0}] Processing {1} Server object resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ServersToRemoveCol.count | Write-Verbose

        # Process Storage Resources
        ForEach ($_server in $_ServersToRemoveCol)
        {

            if ($PSCmdlet.ShouldProcess($_server.ApplianceConnection,"Remove Server resource '$($_server.name)' from appliance")) 
            {

                "[{0}] Removing Server resource '{1}' from appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_server.name, $_server.ApplianceConnection | Write-Verbose

                $_Uri = $_server.uri.Clone()

                if ($PSboundParameters['force'])
                {

                    $_Uri += "?force=true"

                }

                Try
                {

                    Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = $_server.eTag } -Hostname $_server.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

}

function Start-HPOVServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias('Server')]
        [object]$InputObject,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PowerControl = 'MomentaryPress'
        $_PowerState   = 'On'

        $_ServerPowerControlCol = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        # Checking if the input is PSCustomObject, and the category type is server-profiles, which could be passed via pipeline input
        if (($InputObject -is [System.Management.Automation.PSCustomObject]) -and $InputObject.category -ieq "server-hardware") 
        {

            "[{0}] Server is a Server Device object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $InputObject.uri
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-hardware, which would be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq $ResourceCategoryEnum.ServerProfile ) -and ($InputObject.serverHardwareUri)) 
        {
            
            "[{0}] Server is a Server Profile object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting server hardware device assigned to Server Profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $InputObject.serverHardwareUri
        
        }

        else 
        {

            if (-not($InputObject.serverHardwareUri))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerProfileUnassigned InvalidArgument 'InputObject' -TargetType $InputObjectServer.GetType().Name -Message "The Server Profile '$($InputObject.name)' is unassigned. This cmdlet only supports Server Profiles that are assigned to Server Hardware resources. Please check the input object and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "The Parameter 'InputObject' value is invalid. Please validate the 'Server' Parameter value you passed and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }            

        }

        # Validate the server power state and lock
        Try
        {

            $_serverObj = Send-HPOVRequest $_uri -appliance $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        # Need to add confirm prompt here.
        if (($_serverObj.powerState -ine $_PowerState -and (-not($_serverObj.powerLock)))) 
        {
        
            "[{0}] Set Server '{1}' to desired Power State '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_serverObj.name, $_PowerState | Write-Verbose
       
            $_uri = $_serverObj.uri + "/powerState"
                
            $body = [pscustomobject]@{
            
                powerState   = $_PowerState;
                powerControl = $_PowerControl
            
            }
        
            Try
            {

                $_resp = Send-HPOVRequest $_uri PUT $body -Hostname $_serverObj.ApplianceConnection
                
                if (-not($PSBoundParameters['Async']))
                {

                    $_resp = Wait-HPOVTaskComplete $_resp

                }

            }
        
            Catch
            {
        
                $PSCmdlet.ThrowTerminatingError($_)
        
            }

            [void]$_ServerPowerControlCol.Add($_resp)
                        
        }
    
        else 
        { 
        
            $_Message = $null

            if ($serverPowerState.powerState -ieq $_PowerState) 
            {
                
                 $_Message = "Requested Power State '{0}' is the same value as the current Server Power State '{0}'. "  -f $_PowerState
            
            }

            if ($serverPowerState.powerLock) 
            { 
                
                $_Message += "Server is currently under Power Lock."  
            
            }

            if ($errorMessage) 
            { 
            
                $_ErrorRecord = New-ErrorRecord HPOneView.InvalidServerPowerControlException InvalidServerPowerControlOpertion InvalidOperation 'Server' -TargetType 'PSObject' $_Message
                $PSCmdlet.WriteError($_ErrorRecord)
            
            }
        
        }
    
    }

    End
    {

        Return $_ServerPowerControlCol

    }

}

function Stop-HPOVServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Force')]
        [ValidateNotNullOrEmpty()]
        [Alias('Server')]
        [object]$InputObject,
        
        [Parameter (Mandatory, ParameterSetName = 'Force')]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Force')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Force')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PowerControl = if ($PSBoundParameters['Force'])
        {

             'PressAndHold'

        }

        else
        {

            'MomentaryPress'

        }
        
        $_PowerState   = 'Off'

        $_ServerPowerControlCol = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        # Checking if the input is PSCustomObject, and the category type is server-profiles, which could be passed via pipeline input
        if (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq "server-hardware")) 
        {

            "[{0}] Server is a Server Device object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $InputObject.uri
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-hardware, which would be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq $ResourceCategoryEnum.ServerProfile) -and ($InputObject.serverHardwareUri)) 
        {
            
            "[{0}] Server is a Server Profile object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting server hardware device assigned to Server Profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $InputObject.serverHardwareUri
        
        }

        else 
        {

            if (-not($InputObject.serverHardwareUri))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerProfileUnassigned InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "The Server Profile '$($InputObject.name)' is unassigned. This cmdlet only supports Server Profiles that are assigned to Server Hardware resources. Please check the input object and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "The Parameter 'InputObject' value is invalid. Please validate the 'Server' Parameter value you passed and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }            

        }

        # Validate the server power state and lock
        Try
        {

            $_serverObj = Send-HPOVRequest $_uri -appliance $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        # Need to add confirm prompt here.
        if (($_serverObj.powerState -ine $_PowerState -and (-not($_serverObj.powerLock)))) 
        {
        
            if ($PSCmdlet.ShouldProcess($_serverObj.name,'Poweroff server resource'))
            {

                "[{0}] Set Server '{1}' to desired Power State '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_serverObj.name, $_PowerState | Write-Verbose
       
                $_uri = $_serverObj.uri + "/powerState"
                
                $body = [pscustomobject]@{
            
                    powerState   = $_PowerState;
                    powerControl = $_PowerControl
            
                }
        
                Try
                {

                    $_resp = Send-HPOVRequest -uri $_uri -method PUT -body $body -Hostname $_serverObj.ApplianceConnection

                    if (-not($PSBoundParameters['Async']))
                    {

                        $_resp = Wait-HPOVTaskComplete -InputObject $_resp

                    }
        
                }
        
                Catch
                {
        
                    $PSCmdlet.ThrowTerminatingError($_)
        
                }

                $_resp

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] -WhatIf scenario." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled oepration by choosing No." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
                        
        }
    
        else 
        { 
        
            $_Message = $null

            if ($serverPowerState.powerState -ieq $_PowerState) 
            {
                
                 $_Message = "Requested Power State '{0}' is the same value as the current Server Power State '{0}'. "  -f $_PowerState
            
            }

            if ($serverPowerState.powerLock) 
            { 
                
                $_Message += "Server is currently under Power Lock."  
            
            }

            if ($errorMessage) 
            { 
            
                $_ErrorRecord = New-ErrorRecord HPOneView.InvalidServerPowerControlException InvalidServerPowerControlOpertion InvalidOperation 'Server' -TargetType 'PSObject' $_Message
                $PSCmdlet.WriteError($_ErrorRecord)
            
            }
        
        }
    
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Restart-HPOVServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'ColdBoot')]
        [ValidateNotNullOrEmpty()]
        [object]$Server,
        
        [Parameter (Mandatory, ParameterSetName = 'ColdBoot')]
        [Switch]$ColdBoot,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'ColdBoot')]
        [Switch]$Async,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'ColdBoot')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Server']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PowerControl = if ($PSBoundParameters['ColdBoot'])
        {

             'ColdBoot'

        }

        else
        {

            'Reset'

        }
        
        $_PowerState   = 'On'

        $_ServerPowerControlCol = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        # Checking if the input is PSCustomObject, and the category type is server-profiles, which could be passed via pipeline input
        if (($server -is [System.Management.Automation.PSCustomObject]) -and ($server.category -ieq "server-hardware")) 
        {

            "[{0}] Server is a Server Device object: $($server.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $server.uri
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-hardware, which would be passed via pipeline input
        elseif (($server -is [System.Management.Automation.PSCustomObject]) -and ($server.category -ieq $ResourceCategoryEnum.ServerProfile) -and ($server.serverHardwareUri)) 
        {
            
            "[{0}] Server is a Server Profile object: $($server.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting server hardware device assigned to Server Profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $server.serverHardwareUri
        
        }

        else 
        {

            if (-not($server.serverHardwareUri))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerProfileUnassigned InvalidArgument 'Server' -TargetType $Server.GetType().Name -Message "The Server Profile '$($Server.name)' is unassigned. This cmdlet only supports Server Profiles that are assigned to Server Hardware resources. Please check the input object and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Server' -TargetType $Server.GetType().Name -Message "The Parameter 'Server' value is invalid. Please validate the 'Server' Parameter value you passed and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }            

        }

        # Validate the server power state and lock
        Try
        {

            $_serverObj = Send-HPOVRequest $_uri -appliance $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        # Need to add confirm prompt here.
        if (($_serverObj.powerState -ine 'Off' -and (-not($_serverObj.powerLock)))) 
        {
        
            if ($PSCmdlet.ShouldProcess($_serverObj.name,'Restart server resource'))
            {

                "[{0}] Set Server '{1}' to desired Power State '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_serverObj.name, $_PowerState | Write-Verbose
       
                $_uri = $_serverObj.uri + "/powerState"
                
                $body = [pscustomobject]@{
            
                    powerState   = $_PowerState;
                    powerControl = $_PowerControl
            
                }
        
                Try
                {

                    $_resp = Send-HPOVRequest $_uri PUT $body -Hostname $_serverObj.ApplianceConnection
                    
                    if (-not($PSBoundParameters['Async']))
                    {

                        $_resp = Wait-HPOVTaskComplete $_resp

                    }

                }
        
                Catch
                {
        
                    $PSCmdlet.ThrowTerminatingError($_)
        
                }

                [void]$_ServerPowerControlCol.Add($_resp)

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] -WhatIf scenario." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled oepration by choosing No." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
                        
        }
    
        else 
        { 
        
            $_Message = $null

            if ($serverPowerState.powerState -ieq $_PowerState) 
            {
                
                 $_Message = "Requested Power State '{0}' is the same value as the current Server Power State '{0}'. "  -f $_PowerState
            
            }

            if ($serverPowerState.powerLock) 
            { 
                
                $_Message += "Server is currently under Power Lock."  
            
            }

            if ($errorMessage) 
            { 
            
                $_ErrorRecord = New-ErrorRecord HPOneView.InvalidServerPowerControlException InvalidServerPowerControlOpertion InvalidOperation 'Server' -TargetType 'PSObject' $_Message
                $PSCmdlet.WriteError($_ErrorRecord)
            
            }
        
        }
    
    }

    End
    {

        Return $_ServerPowerControlCol

    }

}

function Set-HPOVServerPower 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    [Obsolete()]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("name","uri","serverUri")]
        [object]$Server,

        [Parameter (Mandatory = $false)]
        [Alias ('PowerState')]
        [ValidateSet ("On", "Off")]
        [String]$State = "On",

        [Parameter (Mandatory = $false)]
        [ValidateSet ("PressAndHold", "MomentaryPress", "ColdBoot", "Reset")]
        [String]$powerControl = "MomentaryPress",

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        Write-Warning "This Cmdlet has been deprecated. Please use either Start-HPOVServer, Stop-HPOVServer or Restart-HPOVServer."

    }

}

function Get-HPOVServerOneTimeBoot
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("Server")]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
    
    Process 
    {

        if ($ResourceCategoryEnum.ServerProfile, $ResourceCategoryEnum.ServerHardware -notcontains $InputObject.category)
        {

            $ExceptionMessage = "The InputObject resource '{0}' is not a server hardware or server profile resource." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidInputObjectParameterValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($ResourceCategoryEnum.ServerProfile -eq $InputObject.category)
        {

            "[{0}] InputObject is a server profile resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            "[{0}] Resource assigned to server hardware: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::IsNullOrEmpty($InputObject.serverHardwareUri) | Write-Verbose

            if ([String]::IsNullOrEmpty($InputObject.serverHardwareUri))
            {

                $ExceptionMessage = "The InputObject server profile resource '{0}' is not assigned to a server hardware resource." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidInputObjectParameterValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                Try
                {
                    
                    $_ObjectToProcess = Send-HPOVRequest -Uri $InputObject.serverHardwareUri -Hostname $InputObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)
                    
                }

            }

        }

        else
        {

            $_ObjectToProcess = $InputObject.PSObject.Copy()

        }

        $_OneTimeBootSetting = $ServerHardwareOneTimeBootEnum.($_ObjectToProcess.oneTimeBoot)

        [HPOneView.Servers.ServerHardware+OneTimeBoot]::new($_ObjectToProcess.name,
                                                            [HPOneView.Servers.OneTimeBootEnum]::$_OneTimeBootSetting,
                                                            $_ObjectToProcess.uri,
                                                            $_ObjectToProcess.ApplianceConnection)
    
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVServerOneTimeBoot
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("Server")]
        [object]$InputObject,

        [Parameter (Mandatory)]
        [ValidateSet ('Normal', 'PXE', 'HardDisk', 'CD', 'USB')]
        [String]$Setting,

        [Parameter (Mandatory = $false)]
        [Alias ('PowerState')]
        [Switch]$PowerOn,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
    
    Process 
    {

        if ($ResourceCategoryEnum.ServerProfile, $ResourceCategoryEnum.ServerHardware -notcontains $InputObject.category)
        {

            $ExceptionMessage = "The InputObject resource '{0}' is not a server hardware or server profile resource." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidInputObjectParameterValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($ResourceCategoryEnum.ServerProfile -eq $InputObject.category)
        {

            "[{0}] InputObject is a server profile resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            "[{0}] Resource assigned to server hardware: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::IsNullOrEmpty($InputObject.serverHardwareUri) | Write-Verbose

            if ([String]::IsNullOrEmpty($InputObject.serverHardwareUri))
            {

                $ExceptionMessage = "The InputObject server profile resource '{0}' is not assigned to a server hardware resource." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidInputObjectParameterValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                Try
                {
                    
                    $_ObjectToProcess = Send-HPOVRequest -Uri $InputObject.serverHardwareUri -Hostname $InputObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)
                    
                }

            }

        }

        else
        {

            $_ObjectToProcess = $InputObject.PSObject.Copy()

        }

        $_PatchOperation = [System.Collections.ArrayList]::new()

        $_PatchOp = NewObject -PatchOperation
        $_PatchOp.op = 'replace'
        $_PatchOp.path = '/oneTimeBoot'
        $_PatchOp.value = $ServerHardwareOneTimeBootEnum.$Setting

        [void]$_PatchOperation.Add($_PatchOp)

        if ($PSBoundParameters['PowerOn'])
        {

            # Validate the server is powreed off
            if ($_ObjectToProcess.powerState -ne 'Off' -and -not $_ObjectToProcess.powerLock)
            {

                $ExceptionMessage = 'The server "{0}" is both not currently powered off and power control is locked. Please wait until the currently running task releases power lock status. In order to set the server to power on, it must first be powered off using Stop-HPOVServer.' -f $_ObjectToProcess.name
                $_ErrorRecord = New-ErrorRecord HPOneView.InvalidServerPowerControlException InvalidServerPowerControlOpertion InvalidOperation 'InputObject' -TargetType 'PSObject' $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($_ErrorRecord)

            }

            elseif ($_ObjectToProcess.powerState -ne 'Off')
            {

                $ExceptionMessage = 'The server "{0}" is not currently powered off. In order to set the server to power on, it must first be powered off using Stop-HPOVServer.' -f $_ObjectToProcess.name
                $_ErrorRecord = New-ErrorRecord HPOneView.InvalidServerPowerControlException InvalidServerPowerControlOpertion InvalidOperation 'InputObject' -TargetType 'PSObject' $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($_ErrorRecord)

            }

Get-HPOVApplianceTrustedCertificate            $_PatchOp = NewObject -PatchOperation
            $_PatchOp.op = 'replace'
            $_PatchOp.path = '/powerState'
            $_PatchOp.value = @{powerState = "On"; powerControl = "MomentaryPress"}

            [void]$_PatchOperation.Add($_PatchOp)

        }

        if ($PSCmdlet.ShouldProcess($_ObjectToProcess.name,'Restart server resource'))
        {

            "[{0}] Set Server '{1}' to desired Power State '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_serverObj.name, $_PowerState | Write-Verbose
    
            $_uri = $_ObjectToProcess.uri
            $_eTag = $_ObjectToProcess.eTag
    
            Try
            {

                $_resp = Send-HPOVRequest -Uri $_uri -Method PATCH -Body $_PatchOperation -Hostname $_ObjectToProcess.ApplianceConnection -AddHeader @{'If-Match' = $_eTag}
                
                if (-not $PSBoundParameters['Async'])
                {

                    $_resp = Wait-HPOVTaskComplete $_resp

                }

                $_resp

            }
    
            Catch
            {
    
                $PSCmdlet.ThrowTerminatingError($_)
    
            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] -WhatIf scenario." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] User cancelled oepration by choosing No." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        Return $_ServerPowerControlCol

    }

}

function Add-HPOVRackManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    param
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Alias("Name")]
        [String]$ComputerName,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [PSCredential]$Credential,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Switch]$Async,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("Appliance")]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        if ($PSBoundParameters["Scope"])
        {

            $_InitialScopeUris = New-Object "System.Collections.Generic.List[String]"

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                $_InitialScopeUris.Add($_Scope.Uri)

            }

        }

        $_Import = NewObject -AddRackManager

        $_Import.hostname = $ComputerName;
        $_Import.username = $Credential.Username;
        $_Import.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password));
        $_Import.force    = $Force.IsPresent        

        Try
        {

            $_resp = Send-HPOVRequest -Uri $RackManagerUri -Method POST -Body $_Import -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $Async.IsPresent)
        {

            $_resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_resp

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVRackManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Name,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_CollectionName = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.RackManager

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] Rack manager Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified Rack manager '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.RackManagerResourceException RackManagerResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage

                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    # Get Chassis subresource
                    Try
                    {

                        $_ChassisResources = Send-HPOVRequest -Uri $_member.subResources.chassis.uri -Hostname $ApplianceConnection

                        $_ChassisResourceCol = New-Object "System.Collections.Generic.List[HPOneView.Servers.Chassis]"

                        ForEach ($_chassis in $_ChassisResources.members)
                        {

                            $_ChassisResourceCol.Add((New-Object HPOneView.Servers.Chassis($_chassis.name,
                                                                                            $_chassis.model,
                                                                                            $_chassis.partNumber,
                                                                                            $_chassis.chassisType,
                                                                                            $_chassis.serialNumber,
                                                                                            $_chassis.uPosition,
                                                                                            $_chassis.status,
                                                                                            $_chassis.state,
                                                                                            ('/rest/rack-managers/{0}' -f $_chassis.rackManagerId),
                                                                                            $_chassis.partitionName,
                                                                                            $_chassis.physicalLocationString,
                                                                                            ('/rest/server-hardware/{0}' -f $_chassis.partitionUuid),
                                                                                            $_chassis.uri,
                                                                                            $_chassis.ApplianceConnection)))

                        }
        
                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Get Partition subresources
                    Try
                    {

                        $_PartitionResources = Send-HPOVRequest -Uri $_member.subResources.partitions.uri -Hostname $ApplianceConnection

                        $_PartitionResourcesCol = New-Object "System.Collections.Generic.List[HPOneView.Servers.Partition]"

                        ForEach ($_partition in $_PartitionResources.members)
                        {

                            $_PartitionResourcesCol.Add((New-Object HPOneView.Servers.Partition($_partition.name,
                                                                                                $_partition.powerState,
                                                                                                $_partition.state,
                                                                                                $_partition.status,
                                                                                                $_partition.partitionId,
                                                                                                $_partition.chassisCount,
                                                                                                $_partition.totalPartitionMemoryGB,
                                                                                                $_partition.totalProcessorCount,
                                                                                                $_partition.coreCountPerProcessor,
                                                                                                $_partition.redfishUri,
                                                                                                ('/rest/rack-managers/{0}' -f $_partition.rackManagerId),
                                                                                                $_partition.serverHardwareUri,
                                                                                                $_partition.uri,
                                                                                                $_partition.ApplianceConnection)))

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Get Managers subresources
                    Try
                    {

                        $_ChassisManagerResources = Send-HPOVRequest -Uri $_member.subResources.managers.uri -Hostname $ApplianceConnection

                        $_ChassisManagerResourcesCol = New-Object "System.Collections.Generic.List[HPOneView.Servers.Manager]"

                        ForEach ($_manager in $_ChassisManagerResources.members)
                        {

                            $_ChassisManagerResourcesCol.Add((New-Object HPOneView.Servers.Manager($_manager.name,
                                                                                                    $_manager.fwVersion,
                                                                                                    $_manager.ipv4Address,
                                                                                                    $_manager.ipv6Address,
                                                                                                    $_manager.hostname,
                                                                                                    $_manager.managerType,
                                                                                                    $_manager.model,
                                                                                                    $_manager.status,
                                                                                                    $_manager.state,
                                                                                                    $_manager.uPosition,
                                                                                                    ('/rest/rack-managers/{0}' -f $_manager.rackManagerId),
                                                                                                    $_manager.serialNumber,
                                                                                                    $_manager.partNumber,
                                                                                                    $_manager.uri,
                                                                                                    $_manager.ApplianceConnection)))

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)
                        
                    }

                    $_SubResources = New-Object HPOneView.Servers.SubResources($_ChassisResourceCol, $_PartitionResourcesCol, $_ChassisManagerResourcesCol)

                    New-Object HPOneView.Servers.RackManager($_member.name,
                                                             $_member.serialNumber,
                                                             $_member.partNumber,
                                                             $_member.licensingIntent,
                                                             $_member.etag,
                                                             $_member.state,
                                                             $_member.status,
                                                             $_member.model,
                                                             $_member.location,
                                                             $_member.refreshState,
                                                             $_member.remoteSupportUri,
                                                             $_member.uri,
                                                             $_member.created,
                                                             $_member.modified,
                                                             $_SubResources,
                                                             $_member.ApplianceConnection)

                }

            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}
function Update-HPOVRackManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'RefreshWithCredentials')]
        [ValidateNotNullOrEmpty()]
        [Alias ("name",'Server')]
        [HPOneView.Servers.RackManager[]]$InputObject,

        [Parameter (Mandatory, ParameterSetName = "RefreshWithCredentials")]
        [String]$Hostname,

        [Parameter (Mandatory, ParameterSetName = "RefreshWithCredentials")]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RefreshWithCredentials')]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RefreshWithCredentials')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'DefRefreshWithCredentialsault')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            "[{0}] Server object provided by pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
    
    Process 
    {

        "[{0}] Rackmanager: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Name, $InputObject.Uri | Write-Verbose

        "[{0}] Rackmanager State: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.State | Write-Verbose 
        "[{0}] Rackmanager Status: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Status | Write-Verbose 

        $_body = @{
            op       = "RefreshRackManagerOp";
            isforce  = $Force.IsPresent;
            hostname = $null;
            username = $null;
            password = $null;
        }
    
        if ($InputObject.State -ieq 'Unmanaged' -and $InputObject.refreshState -ieq 'RefreshFailed')
        {

            if (-not $PSBoundParameters['Credential'])
            {

                $ExceptionMessage = "The appliance can no longer communicate with '{0}' resource, and requires valid Credentials." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredUsernameParameter InvalidOperation 'Credential' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not $PSBoundParameters['Hostname'])
            {

                $ExceptionMessage = "The appliance can no longer communicate with '{0}' resource, and requires a Hostname/IPAddress." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredHostnameParameter InvalidOperation 'Hostname' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            $_body.hostname = $Hostname
            $_body.username = $Credential.Username
            $_body.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }
        
        Try
        {

            $_resp = Send-HPOVRequest -Uri $InputObject.Uri -Method PATCH -Body $_body -Hostname $InputObject.ApplianceConnection -AddHeader @{'If-Match' = $InputObject.ETag}
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }

        if ($PSBoundParameters['Async'])
        {

            $_resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }
    
    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVRackManager 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name","Server")]
        [HPOneView.Servers.RackManager]$InputObject,

        [Parameter (Mandatory = $false)] 
        [Switch]$Force,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
    }

    Process 
    {

        "[{0}] Processing RackManager: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Name, $InputObject.Uri | Write-Verbose

        $_RemoveMessage = "remove '{0}' rack manager resource" -f $InputObject.Name

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, $_RemoveMessage)) 
        {

            "[{0}] Removing rack manager resource '{1}' from appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.ApplianceConnection | Write-Verbose

            $_Uri = $InputObject.uri

            if ($PSboundParameters['Force'])
            {

                $_Uri += "?force=true"

            }

            Try
            {

                Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'RefreshWithCredentials')]
        [ValidateNotNullOrEmpty()]
        [Alias ("name",'Server')]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "RefreshWithCredentials")]
        [String]$Hostname,

        [Parameter (Mandatory, ParameterSetName = "RefreshWithCredentials")]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = "RefreshWithCredentials")]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RefreshWithCredentials')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'DefRefreshWithCredentialsault')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            "[{0}] Server object provided by pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
    
    Process 
    {

        # Validate input object type
        # Checking if the input is System.String and is NOT a URI
        if (($InputObject -is [String]) -and (-not($InputObject.StartsWith($ServerHardwareUri)))) 
        {
            
            "[{0}] Server is a Server Name: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting Server from Name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_InputObject = Get-HPOVServer -Name $InputObject -ErrorAction Stop -ApplianceConnection $ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Checking if the input is System.String and IS a URI
        elseif (($InputObject -is [String]) -and ($InputObject.StartsWith($ServerHardwareUri))) 
        {
            
            "[{0}] Server is a Server device URI: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_InputObject = Send-HPOVRequest -Uri $InputObject -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-profiles, which could be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq "server-hardware")) 
        {

            "[{0}] Server is a Server Device object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_InputObject = $InputObject.PSObject.Copy()
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-hardware, which would be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq $ResourceCategoryEnum.ServerProfile)) 
        {
            
            "[{0}] Server is a Server Profile object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting server hardware device assigned to Server Profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($InputObject.serverHardwareUri))
            {

                $ExceptionMessage = "The Server Profile '{0}' is unassigned. This cmdlet only supports Server Profiles that are assigned to Server Hardware resources. Please check the input object and try again." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerProfileUnassigned InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Try
            {

                $_InputObject = Send-HPOVRequest -Uri $InputObject.serverHardwareUri -Hostname $ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        }

        else 
        {

            $ExceptionMessage = "The Parameter 'InputObject' value is invalid. Please validate the 'InputObject' Parameter value you passed and try again."
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Refreshing Server Hardware device: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_InputObject.name | Write-Verbose 
        
        $_uri = $_InputObject.uri + "/refreshState"

        $_body = @{
            
            refreshState = 'RefreshPending'
            
        }

        if (($_InputObject.state -ieq 'Unmanaged' -and $_InputObject.stateReason -ieq 'Unconfigured') -or $Force)
        {

            if (-not $PSBoundParameters['Credential'])
            {

                $ExceptionMessage = "The appliance can no longer communicate with {0} server hardware, and requires valid Credentials." -f $_InputObject.name
                $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredUsernameParameter InvalidOperation 'Enclosure' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not $PSBoundParameters['Hostname'])
            {

                "[{0}] Caller did not supply Hostname. Will use server hardware mpHostInfo value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_InputObject.mpHostInfo.mpHostName | Write-Verbose

                $Hostname = $_InputObject.mpHostInfo.mpHostName

            }

            $_body.Add('hostname', $Hostname)
            $_body.Add('username', $Credential.Username)
            $_body.Add('password', [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password)))

        }
        
        Try
        {

            $_resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_body -Hostname $_InputObject.ApplianceConnection
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }

        if ($PSBoundParameters['Async'])
        {

            $_resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }
    
    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVServerHardwareLicenseIntent
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ("name",'Server')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            "[{0}] Server object provided by pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
    
    Process 
    {

        # Validate input object type
        # Checking if the input is System.String and is NOT a URI
        if (($InputObject -is [String]) -and (-not($InputObject.StartsWith($ServerHardwareUri)))) 
        {
            
            "[{0}] Server is a Server Name: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting Server from Name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_InputObject = Get-HPOVServer -Name $InputObject -ErrorAction Stop -ApplianceConnection $ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Checking if the input is System.String and IS a URI
        elseif (($InputObject -is [String]) -and ($InputObject.StartsWith($ServerHardwareUri))) 
        {
            
            "[{0}] Server is a Server device URI: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_InputObject = Send-HPOVRequest -Uri $InputObject -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-profiles, which could be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq $ResourceCategoryEnum.ServerHardware)) 
        {

            "[{0}] Server is a Server Device object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_InputObject = $InputObject.PSObject.Copy()
        
        }

        # Checking if the input is PSCustomObject, and the category type is server-hardware, which would be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq $ResourceCategoryEnum.ServerProfile)) 
        {
            
            "[{0}] Server is a Server Profile object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting server hardware device assigned to Server Profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($InputObject.serverHardwareUri))
            {

                $ExceptionMessage = "The Server Profile '{0}' is unassigned. This cmdlet only supports Server Profiles that are assigned to Server Hardware resources. Please check the input object and try again." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerProfileUnassigned InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Try
            {

                $_InputObject = Send-HPOVRequest -Uri $InputObject.serverHardwareUri -Hostname $ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        }

        else 
        {

            $ExceptionMessage = "The Parameter 'InputObject' value is invalid. Please validate the 'InputObject' Parameter value you passed and try again."
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # If server is not Managed, generate error
        if ($_InputObject.state -eq "Monitored")
        {

            $ExceptionMessage = "The provided server hardware resource {0} is a Monitored resource. This Cmdlet only supports Managed server hardware." -f $_InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException UnsupportedResourceState InvalidArgument 'InputObject' -TargetType $_InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Checking Server Hardware if it is licensed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

        $_Uri = "/rest/licenses?filter=nodeId EQ '{0}'" -f $_InputObject.uuid

        # The licensing intent of the server is changed, and if a license of the intended type is available,
        # it is applied to the server. Once licensed, the only permitted change is an upgrade from "OneViewNoiLO" to "OneView".
        # The server must be unlicensed and managed in order to be able to update the licensing intent.
        # [
        # { "op": "replace", "path": "/licensingIntent", "value": "OneView"}
        # ]


        Try
        {

            $_IsLicensed = Send-HPOVRequest -Uri $_uri -Hostname $_InputObject.ApplianceConnection
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }

        # server is already licensed. generate an error
        if ($_IsLicensed.members[0].licenseType -ne 'Unlicensedproduct' -and 
            $_IsLicensed.members[0].product -eq 'HPE OneView Advanced')
        {

            $ExceptionMessage = "The provided server hardware resource {0} is a Monitored resource. This Cmdlet only supports updating the license allocation policy (intent) from 'HPE OneView Advanced without iLO Advanced' to 'HPE OneView Advanced'." -f $_InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException UnsupportedLicenseStateChange InvalidOperation 'InputObject' -TargetType $_InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
    
        $_PatchOperation = NewObject -PatchOperation

        $_PatchOperation.op    = "replace"
        $_PatchOperation.path  =  "/licensingIntent"
        $_PatchOperation.value = "OneView"

        $_uri = $_InputObject.uri

        Try
        {

            $_resp = Send-HPOVRequest -Uri $_uri -Method PATCH -Body $_PatchOperation -Hostname $_InputObject.ApplianceConnection
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }

        if ($PSBoundParameters['Async'])
        {

            $_resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }
    
    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }
    
}

function Get-HPOVEnclosureGroup 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]    
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false)]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$exportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $EGCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSboundParameters['name']) 
            {

                "[{0}] Enclosure Group name provided: '$name'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                $name = $name -replace ("[*]","%25") -replace ("[&]","%26")
    
                $uri = $enclosureGroupsUri + "?filter=name matches '$name'"
    
            }
    
            else 
            {
    
                "[{0}] No Enclosure Group name provided. Looking for all Enclosure Group resources." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                $uri = $enclosureGroupsUri
    
            }
    
            Try
            {
    
                $enclGrps = Send-HPOVRequest $uri -Hostname $_appliance
    
            }
            
            Catch
            {
    
                "[{0}] API Error Caught: $($_.Exception.Message)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                $PSCmdlet.ThrowTerminatingError($_)
    
            }
    
            if ($enclGrps.count -eq 0 -and $name) 
            { 
    
                "[{0}] Enclosure Group '$name' resource not found. Generating error" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = "The specified Enclosure Group '{0}' was not found on '{1}'. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException EnclosureGroupNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)  
                
            }
    
            elseif ($enclGrps.count -eq 0) 
            { 
    
                "[{0}] No Enclosure Group resources found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
            }
    
            else 
            {
    
                "[{0}] Found $($enclGrps.count) Enclosure Group resources." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                $enclGrps.members | ForEach-Object { 
                    
                    $_.PSObject.TypeNames.Insert(0,'HPOneView.EnclosureGroup')    
    
                    [void]$EGCollection.Add($_) 
                    
                }
     
            }

        }

   
    }

    End 
    {

        "[{0}] Done. $($enclGrps.count) enclosure group(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose     

        if ($exportFile)
        { 
            
            $enclGrps.members | convertto-json -Depth 99 | Set-Content -Path $exportFile -force -encoding UTF8 
        
        }
                
        else 
        {
            
            Return $EGCollection
        
        }  

    }

}

function New-HPOVEnclosureGroup 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'C7000')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'C7000')]
        [Parameter (Mandatory, ParameterSetName = 'Synergy')]
        [Parameter (Mandatory, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateRange(1,5)]
        [Int]$EnclosureCount = 1,
         
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'C7000')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Synergy')]
        [ValidateNotNullOrEmpty()]
        [Alias ('logicalInterconnectGroupUri','logicalInterconnectGroup')]
        [object]$LogicalInterconnectGroupMapping,

        [Parameter (Mandatory = $false, ParameterSetName = 'C7000')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [Parameter (Mandatory = $false, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateSet ('RedundantPowerFeed','RedundantPowerSupply', IgnoreCase = $false)]
        [String]$PowerRedundantMode = "RedundantPowerFeed",

        [Parameter (Mandatory = $false, ParameterSetName = 'C7000')]
        [Parameter (Mandatory = $false, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullOrEmpty()]
        [String]$ConfigurationScript,      
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateSet ('AddressPool', 'DHCP', 'External')]
        [String]$IPv4AddressType = 'DHCP',
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [Alias ('AddressPool')]
        [ValidateNotNullOrEmpty()]
        [Object]$IPv4AddressRange,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateSet ('AddressPool', 'DHCP', 'External')]
        [String]$IPv6AddressType = 'DHCP',
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateNotNullOrEmpty()]
        [Object]$IPv6AddressRange,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateSet ('None', 'Internal', 'External')]
        [String]$DeploymentNetworkType = 'None',
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateNotNullOrEmpty()]
        [object]$DeploymentNetwork,

        [Parameter (Mandatory, ParameterSetName = 'DiscoverFromEnclosure')]
        [Switch]$DiscoverFromEnclosure,

        [Parameter (Mandatory, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullorEmpty()]
        [String]$OAAddress,

        [Parameter (Mandatory, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullorEmpty()]
        [String]$Username,

        [Parameter (Mandatory, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullorEmpty()]
        [String]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullorEmpty()]
        [String]$LigPrefix,

        [Parameter (Mandatory = $false, ParameterSetName = 'C7000')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [Parameter (Mandatory = $false, ParameterSetName = 'DiscoverFromEnclosure')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'ImportFile')]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'C7000')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'ImportFile')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Synergy')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'DiscoverFromEnclosure')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory, ParameterSetName = "ImportFile")]
        [ValidateNotNullOrEmpty()]
        [Alias ("i", "import")]
        [String]$ImportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Resolved Parameter Set Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSCmdlet.ParameterSetName | Write-Verbose

        if (-not($PSBoundParameters['LogicalInterconnectGroupMapping']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_EnclosureGroupCreateResults = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PSCmdlet.ParameterSetName -eq 'DiscoverFromEnclosure')
        {

            if ($ApplianceConnection.ApplianceType -eq 'Composer')
            {
                
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is a Synergy Composer, which does not support Enclosure Discovery to create an Enclosure Group.' -f $ApplianceConnection.Name)
                $PSCmdlet.WriteError($ErrorRecord)
                
            }

            else
            {

                $_EnclosureGroupPreview = NewObject -EnclosureGroupPreview

                $_EnclosureGroupPreview.username  = $Username
                $_EnclosureGroupPreview.password  = $Password
                $_EnclosureGroupPreview.hostname  = $OAAddress
                $_EnclosureGroupPreview.ligPrefix = $LigPrefix

                Try
                {

                    $_EnclosurePreview = Send-HPOVRequest $EnclosurePreviewUri POST $_EnclosureGroupPreview -Hostname $ApplianceConnection

                    if (-not($PSBoundParameters['LigPrefix']))
                    {

                        $_EnclosurePreview.logicalInterconnectGroup.name = $_EnclosurePreview.logicalInterconnectGroup.name.Replace('null',$Name)

                    }

                    $LigTaskResp = Send-HPOVRequest $LogicalInterconnectGroupsUri POST $_EnclosurePreview.logicalInterconnectGroup -Hostname $ApplianceConnection | Wait-HPOVTaskComplete

                    $LogicalInterconnectGroupMapping = Send-HPOVRequest $LigTaskResp.associatedResource.resourceUri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }    

            }                    

        }

        if ($PSCmdlet.ParameterSetName -eq 'importFile')
        {

            $_EnclosureGroup = (Get-Content $ImportFile).ToString()

            "[{0}] Enclosure Group object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_EnclosureGroup | Write-Verbose

            Try
            {

                $resp = Send-HPOVRequest -Uri $enclosureGroupsUri -Method POST -Body $_EnclosureGroup -Hostname $ApplianceConnection.Name

                $resp.PSObject.TypeNames.Insert(0,'HPOneView.EnclosureGroup')

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {    
            
            $_EnclosureGroup           = NewObject -EnclosureGroup
            $_EnclosureGroup.name      = $Name
            $_EnclosureGroup.powerMode = $PowerRedundantMode

            switch ($PSCmdlet.ParameterSetName)
            {

                'Synergy'
                {

                    $_EnclosureGroup           = NewObject -SynergyEnclosureGroup
                    $_EnclosureGroup.name      = $Name
                    $_EnclosureGroup.powerMode = $PowerRedundantMode

                    if ($ApplianceConnection.ApplianceType -ne 'Composer')
                    {
                
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. Creating an Enclosure Group with OSDeployment Settings is only supported with Synergy Composers and the HPE Synergy Image Streamer.' -f $ApplianceConnection.Name)
                        $PSCmdlet.WriteError($ErrorRecord)
                
                    }

                    else
                    {

                        "[{0}] Processing Synergy LIG(s)." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_c = 0

                        # Explicit Mapping with Hashtable
                        if ($LogicalInterconnectGroupMapping -is [System.Collections.IEnumerable] -and $LogicalInterconnectGroupMapping -isnot [String])
                        {
                    
                            # Loop through LIGs to build EG Interconnect Bay Mapping
                            # -LogicalInterConnectGroupMapping $MyMultiFrameVCEthLig,$MyVCFCLig
                            # -LogicalInterConnectGroupMapping @{Frame1=$MyMultiFrameVCEthLig,$MyVCFCLig;Frame2=$MyMultiFrameVCEthLig,$MyVCFCLig;Frame3=$MyMultiFrameVCEthLig}
                            foreach ($_FrameLig in $LogicalInterconnectGroupMapping.GetEnumerator())
                            {

                                if (($_FrameLig -is [System.Collections.IEnumerable] -and $_FrameLig -isnot [String] -and $_FrameLig -isnot [Array]) -or ($_FrameLig -is [System.Collections.DictionaryEntry]))
                                {

                                    $_FrameLigIndex = $_FrameLig.Key.ToLower().TrimStart('frameenclosure')

                                    $_FrameLig = $_FrameLig.Value

                                    '[{0}] Frame LIG Index ID: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_FrameLigIndex | Write-Verbose

                                }    

                                ForEach ($_LigEntry in $_FrameLig)
                                {

                                    '[{0}] Processing LIG: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LigEntry.name | Write-Verbose

                                    if (('sas-logical-interconnect-groups' -eq $_LigEntry.category) -or ('-1' -contains $_LigEntry.enclosureIndexes))
                                    {

                                        '[{0}] Frame LIG is either Natasha or Carbon, storing EnclosureIndexID from FrameLigIndex: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_FrameLigIndex | Write-Verbose

                                        $_EnclosureIndexID = $_FrameLigIndex

                                    }

                                    else
                                    {

                                        $_EnclosureIndexID = $null

                                    }

                                    if ('logical-interconnect-groups','sas-logical-interconnect-groups' -notcontains $_LigEntry.category)
                                    {

                                        $Message     = "The provided Logical Interconnect Group value for Bay {0} is not a valid Logical Interconnect Group Object {1}." -f $_LigEntry.Name, $_LigEntry.Value.category
                                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message $Message
                                    
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }                    

                                    if ($_LigEntry.enclosureType -NotMatch 'SY')
                                    {

                                        $Message     = "The provided Logical Interconnect Group {0} is modeled for the HPE BladeSystem C7000 enclosure type. Please provide a Synergy Logical Interconnect Grou presource, and try again." -f $_LigEntry.name
                                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message $Message
                                    
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }
                                    
                                    # Loop through InterconnectMapTemplate Entries
                                    ForEach ($_InterconnectMapTemplate in $_LigEntry.interconnectMapTemplate.interconnectMapEntryTemplates)
                                    {

                                        # Detect I3S setting in the Uplink Sets of the LIG
                                        if (-not $_I3SSettingsFound)
                                        {
                                            
                                            $_I3SSettingsFound = $_LigEntry.uplinkSets | Where-Object ethernetNetworkType -eq 'ImageStreamer'
                                        
                                        }

                                        $_InterconnectBayMapping = NewObject -InterconnectBayMapping

                                        $_InterconnectBayMapping.enclosureIndex              = if (-not $_EnclosureIndexID) { $_InterconnectMapTemplate.enclosureIndex } else { $_EnclosureIndexID }
                                        $_InterconnectBayMapping.interconnectBay             = ($_InterconnectMapTemplate.logicalLocation.locationEntries | Where-Object type -eq 'Bay').relativeValue
                                        $_InterconnectBayMapping.logicalInterconnectGroupUri = $_LigEntry.uri 

                                        # If LIG is not present in the EG interconnectBayMapping
                                        if ((Compare-Object $_EnclosureGroup.interconnectBayMappings -DifferenceObject $_InterconnectBayMapping -Property enclosureIndex,interconnectBay,logicalInterconnectGroupUri -IncludeEqual).SideIndicator -notcontains '==') 
                                        {

                                            '[{0}] Mapping Frame {1} Bay {2} -> {3} ({4})' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_InterconnectBayMapping.enclosureIndex, $_InterconnectBayMapping.interconnectBay, $_LigEntry.Name, $_LigEntry.uri | Write-Verbose

                                            [void]$_EnclosureGroup.interconnectBayMappings.Add($_InterconnectBayMapping)

                                            $_c++

                                        }
                                        
                                    }

                                }    

                            }

                        }

                        ElseIf ($LogicalInterconnectGroupMapping -is [PSCustomObject] -and ('logical-interconnect-groups','sas-logical-interconnect-groups' -contains $LogicalInterconnectGroupMapping.category))
                        {

                            if ($LogicalInterconnectGroupMapping.enclosureType -NotMatch 'SY')
                            {

                                $Message     = "The provided Logical Interconnect Group {0} is modeled for the HPE BladeSystem C7000 enclosure type. Please provide a Synergy Logical Interconnect Group resource, and try again." -f $LogicalInterconnectGroupMapping.name
                                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message $Message
                                
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            # Detect I3S setting in the Uplink Sets of the LIG
                            $_I3SSettingsFound = $LogicalInterconnectGroupMapping.uplinkSets | Where-Object ethernetNetworkType -eq 'ImageStreamer'

                            ForEach ($_InterconnectMapEntry in $LogicalInterconnectGroupMapping.interconnectMapTemplate.interconnectMapEntryTemplates)
                            {

                                ForEach ($_LocationEntry in ($_InterconnectMapEntry.logicalLocation.locationEntries | Where-Object type -eq 'Bay'))
                                {

                                    if (-not($_EnclosureGroup.interconnectBayMappings | Where-Object interconnectBay -eq $_LocationEntry.relativeValue))
                                    {

                                        $_InterconnectBayMapping = NewOBject -InterconnectBayMapping

                                        $_InterconnectBayMapping.interconnectBay             = ($_LocationEntry | Where-Object type -eq 'bay').relativeValue
                                        $_InterconnectBayMapping.logicalInterconnectGroupUri = $LogicalInterconnectGroupMapping.uri

                                        $_InterconnectBayMapping = $_InterconnectBayMapping | Select-Object * -ExcludeProperty enclosureIndex

                                        '[{0}] Mapping Interconnect Bay to LIG URI {1} --> {2}' -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_LocationEntry | Where-Object type -eq 'bay').relativeValue, $LogicalInterconnectGroupMapping.uri | Write-Verbose 

                                        "[{0}] Interconnect Bay Mapping Entry found in LIG resource: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LocationEntry | Write-Verbose 

                                        [void]$_EnclosureGroup.interconnectBayMappings.Add($_InterconnectBayMapping)

                                    } 

                                    $_c++

                                }

                            }

                        }

                        else
                        {

                            '[{0}] Invalid LIG Category value provided: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), ($LogicalInterconnectGroupMapping | Out-String) | Write-Verbose

                            $Message     = "Invalid LogicalInterconnectGroupMapping value provided '{0}'. Please check the value and try again." -f ($LogicalInterconnectGroupMapping )
                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType $LogicalInterconnectGroupMapping.GetType().Fullname -Message $Message
                                
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # $_EnclosureGroup.interconnectBayMappingCount = $_c

                        if (-not($PSBoundParameters['EnclosureCount']))
                        {

                            if ($LogicalInterconnectGroupMapping -is [System.Collections.IEnumerable])
                            {

                                $_EnclosureGroup.enclosureCount = $LogicalInterconnectGroupMapping.Count

                            }

                            else
                            {

                                $_EnclosureGroup.enclosureCount = $LogicalInterconnectGroupMapping.enclosureIndexes.Count

                            }

                        }

                        else
                        {

                            $_EnclosureGroup.enclosureCount = $EnclosureCount

                        }

                        $_DeploymentSettings                = NewObject -EnclosureGroupI3SDeploymentSettings
                        $_DeploymentSettings.deploymentMode = $DeploymentNetworkType

                        $_EnclosureGroup.osDeploymentSettings = NewObject -DeploymentModeSettings

                        # // Need to update error message that I3S Setting was detected in LIG but no DeploymentSetting defined in EG params.
                        if ($DeploymentNetworkType -eq 'None' -and $_I3SSettingsFound)
                        {

                            $Message     = "The provided LogicalInterconnectGroupMapping Parameter contains 1 or more LIGs with an ImageStreamer Uplink Set configured, but no DeploymentNetwork or DeploymentNetworkType Parameter were provided. You must specify a DeploymentNetwork and DeploymentNetworkType cannot be 'none'."
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidDeploymentNetworkSettings InvalidArgument 'DeploymentNetworkType' -TargetType 'PSObject' -Message $message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                        }

                        elseif ($DeploymentNetworkType -ne 'None')
                        {
                            
                            $_EnclosureGroup.osDeploymentSettings.manageOSDeployment = $true    

                            if ($DeploymentNetworkType -eq 'External')
                            {

                                if (-not $DeploymentNetwork)
                                {

                                    '[{0}] DeploymentNetworkType is set to "External", but no DeploymentNetwork value.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $Message     = "The DeploymentNetworkType was set to 'External', which requires the DeploymentNetwork parameter."
                                    $ErrorRecord = New-ErrorRecord InvalidOperationException NullDeploymentNetwork InvalidArgument 'DeploymentNetworkType' -TargetType 'SwitchParameter' -Message $Message

                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                switch ($DeploymentNetwork.GetType())
                                {

                                    'PSCustomObject'
                                    {

                                        if ($DeploymentNetworkType.category -ne 'ethernet-networks')
                                        {

                                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidEthernetNetworkResource InvalidArgument 'DeploymentNetworkType' -TargetType 'PSObject' -Message "The provided Deployment Network resource object is not an Ethernet Network. Please validate the Parameter value and try again."
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                                        }

                                        if ($DeploymentNetworkType.ethernetNetworkType -ne 'Tagged')
                                        {

                                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidEthernetNetworkResource InvalidArgument 'DeploymentNetworkType' -TargetType 'PSObject' -Message "The provided Deployment Network resource object is not a 'Tagged' Ethernet Network. Please validate the Parameter value and try again."
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                                        }

                                    }

                                    'String'
                                    {

                                        Try
                                        {

                                            $DeploymentNetwork = Get-HPOVNetwork -Name $DeploymentNetwork -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                                        }

                                        Catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                        if ($DeploymentNetwork.ethernetNetworkType -ne 'Tagged')
                                        {


                                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidEthernetNetworkResource InvalidArgument 'DeploymentNetwork' -Message "The provided Deployment Network resource object is not a 'Tagged' Ethernet Network. Please validate the Parameter value and try again."
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                                        }

                                    }

                                }
        
                                $_DeploymentSettings.deploymentNetworkUri = $DeploymentNetwork.uri            

                            }

                        }

                        $_EnclosureGroup.osDeploymentSettings.deploymentModeSettings = $_DeploymentSettings    

                        $_EnclosureGroup.ipAddressingMode = $EnclosureGroupIpAddressModeEnum[$IPv4AddressType]
                        $_EnclosureGroup.ipv6AddressingMode = $EnclosureGroupIpAddressModeEnum[$IPv6AddressType]

                        foreach ($_IPv4Range in $IPv4AddressRange)
                        {

                            "[{0}] IPv4 address range: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_IPv4Range.Name | Write-Verbose

                            if ($ResourceCategoryEnum.IPv4Range -ne $_IPv4Range.category)
                            {
                        
                                $ExceptionMessage = "An invalid Address Pool object was provided. Please check the value and try again."
                                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidAddressPoolResource InvalidArgument 'AddressPool' -TargetType 'PSObject' -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                            }

                            [void]$_EnclosureGroup.ipRangeUris.Add($_IPv4Range.uri)

                        }                    

                        foreach ($_IPv6Range in $IPv6AddressRange)
                        {

                            "[{0}] IPv6 address range: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_IPv6Range.Name | Write-Verbose

                            if ($ResourceCategoryEnum.IPv6Range -ne $_IPv6Range.category)
                            {
                        
                                $ExceptionMessage = "An invalid Address Pool object was provided. Please check the value and try again."
                                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidAddressPoolResource InvalidArgument 'AddressPool' -TargetType 'PSObject' -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                            }

                            [void]$_EnclosureGroup.ipv6RangeUris.Add($_IPv6Range.uri)

                        }                    

                    }

                }

                {'C7000','DiscoverFromEnclosure' -contains $_}
                {

                    # Process LIG Object here, and will be on a single Appliance Connection
                    if ($LogicalInterconnectGroupMapping -is [PSCustomObject]) 
                    { 
            
                        "[{0}] Single LIG Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnectGroupMapping.name | Write-Verbose

                        # Check to make sure the object is a LIG, generate error if not
                        if ($LogicalInterconnectGroupMapping.category -ne 'logical-interconnect-groups')
                        {

                            "[{0}] Invalid LIG Category value provided '$($LogicalInterconnectGroupMapping.category)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message "Invalid [Object] value provided '$LogicalInterconnectGroupMapping'. Logical Interconnect Group category must Begin with 'logical-interconnect-groups'. Please check the value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        "[{0}] Will Process {1} Interconnect Bay Logical Location Entries in LIG Object." -f $MyInvocation.InvocationName.ToString().ToUpper(), ($LogicalInterconnectGroupMapping.interconnectMapTemplate.interconnectMapEntryTemplates.logicalLocation | Measure-Object).Count | Write-Verbose

                        $_c = 1

                        # Process Interconnect Bay Mapping, which is 1 LIG
                        ForEach ($_LigBayMapping in $LogicalInterconnectGroupMapping.interconnectMapTemplate.interconnectMapEntryTemplates)
                        {

                            "[{0}] Processing {1} of {2} Bay Mappings" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_c, ($LogicalInterconnectGroupMapping.interconnectMapTemplate.interconnectMapEntryTemplates.logicalLocation | Measure-Object).Count | Write-Verbose

                            $_InterconnectBayMapping = NewOBject -InterconnectBayMapping

                            $_InterconnectBayMapping.interconnectBay             = ($_LigBayMapping.logicalLocation.locationEntries | Where-Object type -EQ 'bay').relativeValue
                            $_InterconnectBayMapping.logicalInterconnectGroupUri = $LogicalInterconnectGroupMapping.uri

                            "[{0}] Interconnect Bay '{1}' Mapping Entry found in LIG resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_LigBayMapping.logicalLocation.locationEntries | Where-Object type -EQ 'bay').relativeValue | Write-Verbose

                            [void]$_EnclosureGroup.interconnectBayMappings.Add($_InterconnectBayMapping)

                            $_c++

                        }

                    }

                    elseif ($LogicalInterconnectGroupMapping -is [System.Collections.IEnumerable] -and $LogicalInterconnectGroupMapping -isnot [String])
                    {

                        ForEach ($_key in $LogicalInterconnectGroupMapping.Keys)
                        {

                            "[{0}] Processing Hashtable key '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_key | Write-Verbose

                            $_InterconnectBayMapping = NewOBject -InterconnectBayMapping

                            switch (($LogicalInterconnectGroupMapping.$_key).GetType().Name)
                            {

                                'PSCustomObject'
                                {

                                    # Validate object is a LIG
                                    if (-not(($LogicalInterconnectGroupMapping.$_key).category -eq 'logical-interconnect-groups'))
                                    {

                                        "[{0}] Invalid [PSCustomObject] value provided '{1}' for '{2}' Hashtable entry." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnectGroupMapping.$_key.category, $_key | Write-Verbose
                                    
                                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupMappingObject InvalidArgument 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message "Invalid [PSCustomObject] value provided '$(($LogicalInterconnectGroupMapping.$_key).category)' for '$_key' Hashtable entry. Logical Interconnect Group object category must be 'logical-interconnect-groups'. Please check the value and try again."
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    $_InterconnectBayMapping.interconnectBay             = ((($LogicalInterconnectGroupMapping.$_key).interconnectMapTemplate.interconnectMapEntryTemplates.LogicalLocation.locationEntries) | Where-Object { $_.type -EQ 'bay' -and $_.relativeValue -EQ $_key}).relativeValue
                                    $_InterconnectBayMapping.logicalInterconnectGroupUri = ($LogicalInterconnectGroupMapping.$_key).uri

                                    "[{0}] Interconnect Bay Mapping Entry: $($_InterconnectBayMapping)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                }

                                'String'
                                {

                                    # Value is an Objects URI
                                    if (($LogicalInterconnectGroupMapping.$_key).StartsWith($logicalInterconnectGroupUri))
                                    {

                                        $_InterconnectBayMapping.interconnectBay             = $_key
                                        $_InterconnectBayMapping.logicalInterconnectGroupUri = $LogicalInterconnectGroupMapping.$_key

                                        "[{0}] Interconnect Bay Mapping Entry: $($_InterconnectBayMapping)"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    }

                                    # Object Name value
                                    else
                                    {

                                        Try
                                        {
                                    
                                            $_LogicalInterconnectGroupObject = Get-HPOVLogicalInterconnectGroup $LogicalInterconnectGroupMapping.$_key -ApplianceConnection $ApplianceConnection.Name

                                            $_InterconnectBayMapping.interconnectBay             = $_key
                                            $_InterconnectBayMapping.logicalInterconnectGroupUri = $_LogicalInterconnectGroupObject.uri
                                    
                                        }
                                    
                                        Catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                    }

                                }

                            }

                            [void]$_EnclosureGroup.interconnectBayMappings.Add($_InterconnectBayMapping)

                        }

                    }

                    else
                    {

                        '[{0}] Invalid LIG Category value provided: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), ($LogicalInterconnectGroupMapping | Out-String) | Write-Verbose

                        $Message     = "Invalid LogicalInterconnectGroupMapping value provided '{0}'. Please check the value and try again." -f ($LogicalInterconnectGroupMapping.ToString())
                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType $LogicalInterconnectGroupMapping.GetType().Fullname -Message $Message
                            
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if (($_EnclosureGroup.interconnectBayMappings | Measure-Object).count -lt 8)
                    {

                        "[{0}] Adding null interconnectBayMapping entries."  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        for ($b = 8 - $_EnclosureGroup.interconnectBayMappings.count; $b -ne 0; $b--)
                        {

                            $_InterconnectBayMapping = NewObject -InterconnectBayMapping

                            $n = 1

                            do
                            {

                                $_bayId = $null

                                if (-not($_EnclosureGroup.interconnectBayMappings | Where-Object interconnectBay -eq $n))
                                {

                                    $_bayId = $n

                                }

                                # ERROR, we should never get more than the number of $_EnclosureGroup.interconnectBayMappingCount
                                if ($n -gt 8)
                                {

                                    $ErrorRecord = New-ErrorRecord System.InvalidOperationException InvalidOperation InvalidOperation 'InterconnectBayMappingCount' -TargetType 'Int' -Message "Could not determine Enclosure Group interconnectBay ID (`$_bayId). (`$n = $n)"

                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                $n++

                            }
                            until ($_bayId)

                            $_InterconnectBayMapping.interconnectBay = $_bayId

                            [void]$_EnclosureGroup.interconnectBayMappings.Add($_InterconnectBayMapping)

                        }
            
                    }

                    $_EnclosureGroup.configurationScript = $ConfigurationScript

                }

            }

            # "[$($MyInvocation.InvocationName.ToString().ToUpper())] Enclosure Group object: $($_EnclosureGroup | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Creating '{1}' Enclosure Group" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_EnclosureGroup.name | Write-Verbose

            Try
            {

                $resp = Send-HPOVRequest -Uri $EnclosureGroupsUri -Method POST -Body $_EnclosureGroup -Hostname $ApplianceConnection.Name

                $resp.PSObject.TypeNames.Insert(0,'HPOneView.EnclosureGroup')

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        [void]$_EnclosureGroupCreateResults.Add($resp)

    }

    End 
    {

        return $_EnclosureGroupCreateResults

    }

}

function Set-HPOVEnclosureGroup
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Alias('EnclosureGroup')]
        [Object]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$ConfigurationScript,
         
        # [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        # [ValidateNotNullOrEmpty()]
        # [Alias ('LogicalInterconnectGroupUri','LogicalInterconnectGroup')]
        # [object]$LogicalInterconnectGroupMapping,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        # [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        [ValidateSet ('RedundantPowerFeed','RedundantPowerSupply', IgnoreCase = $false)]
        [String]$PowerRedundantMode = "RedundantPowerFeed",

        # [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        # [ValidateSet ('AddressPool', 'DHCP', 'External')]
        # [String]$IPv4AddressType,
        
        # [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        # [ValidateNotNullOrEmpty()]
        # [object]$AddressPool,
        
        # [Parameter (Mandatory = $false, ParameterSetName = 'Synergy')]
        # [ValidateSet ('None', 'Internal', 'External')]
        # [String]$DeploymentNetworkType,
        
        # [Parameter (Mandatory = $false)]
        # [ValidateNotNullOrEmpty()]
        # [object]$DeploymentNetwork,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        # [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Synergy')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        # Validate InputObject
        if ($InputObject.category -ne $ResourceCategoryEnum['EnclosureGroup'])
        {

            $ExceptionMessage = "The provided -InputObject value is not an {0} resource. Please correct the input object and try again." -f $ResourceCategoryEnum['EnclosureGroup']
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidResourceObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_EnclosureGroupToUpdate = $null

        try
        {

            $_EnclosureGroupToUpdate = $InputObject.PSObject.Copy()

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Determine operations that need to be performed
        switch ($PSBoundParameters.Keys)
        {

            'Name'
            {

                "[{0}] Updating Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_EnclosureGroupToUpdate.name = $Name

            }

            'ConfigurationScript'
            {

                # Validate the enclosure group is for c-Class not Synergy
                if (-not $InputObject.enclosureTypeUri.StartsWith($CClassEnclosureTypeUri))
                {

                    $ExceptionMessage = "The provided -InputObject resource object is not a c-Class enclosure. Please correct the input object and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidResourceObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Updating configuration script" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Uri = $InputObject.Uri + "/script"

                $_EnclosureGroupToUpdate | Add-Member -NotePropertyName configurationScript -NotePropertyValue $ConfigurationScript

            }

            'PowerRedundantMode'
            {

                "[{0}] Updating PowerRedundantMode." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_EnclosureGroupToUpdate.powerMode = $PowerRedundantMode

            }

            'LogicalInterconnectGroupMapping'
            {

                "[{0}] Updating PowerRedunLogicalInterconnectGroupMappingdantMode." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                foreach ($_FrameLig in $LogicalInterconnectGroupMapping.GetEnumerator())
                {

                    if (($_FrameLig -is [System.Collections.IEnumerable] -and $_FrameLig -isnot [String] -and $_FrameLig -isnot [Array]) -or ($_FrameLig -is [System.Collections.DictionaryEntry]))
                    {

                        $_FrameLigIndex = $_FrameLig.Key.ToLower().TrimStart('frameenclosure')

                        $_FrameLig = $_FrameLig.Value

                        '[{0}] Frame LIG Index ID: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_FrameLigIndex | Write-Verbose

                    }    

                    ForEach ($_LigEntry in $_FrameLig)
                    {

                        '[{0}] Processing LIG: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LigEntry.name | Write-Verbose

                        if (('sas-logical-interconnect-groups' -eq $_LigEntry.category) -or ('-1' -contains $_LigEntry.enclosureIndexes))
                        {

                            '[{0}] Frame LIG is either Natasha or Carbon, storing EnclosureIndexID from FrameLigIndex: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_FrameLigIndex | Write-Verbose

                            $_EnclosureIndexID = $_FrameLigIndex

                        }

                        else
                        {

                            $_EnclosureIndexID = $null

                        }

                        if ('logical-interconnect-groups','sas-logical-interconnect-groups' -notcontains $_LigEntry.category)
                        {

                            $Message     = "The provided Logical Interconnect Group value for Bay {0} is not a valid Logical Interconnect Group Object {1}." -f $_LigEntry.Name, $_LigEntry.Value.category
                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message $Message
                        
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }                    

                        if ($_LigEntry.enclosureType -NotMatch 'SY')
                        {

                            $Message     = "The provided Logical Interconnect Group {0} is modeled for the HPE BladeSystem C7000 enclosure type. Please provide a Synergy Logical Interconnect Grou presource, and try again." -f $_LigEntry.name
                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectGroupCategory InvalidType 'LogicalInterconnectGroupMapping' -TargetType 'PSObject' -Message $Message
                        
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }
                        
                        # Loop through InterconnectMapTemplate Entries
                        ForEach ($_InterconnectMapTemplate in $_LigEntry.interconnectMapTemplate.interconnectMapEntryTemplates)
                        {

                            # Detect I3S setting in the Uplink Sets of the LIG
                            if (-not $_I3SSettingsFound)
                            {
                                
                                $_I3SSettingsFound = $_LigEntry.uplinkSets | Where-Object ethernetNetworkType -eq 'ImageStreamer'
                            
                            }

                            $_InterconnectBayMapping = NewObject -InterconnectBayMapping

                            $_InterconnectBayMapping.enclosureIndex              = if (-not $_EnclosureIndexID) { $_InterconnectMapTemplate.enclosureIndex } else { $_EnclosureIndexID }
                            $_InterconnectBayMapping.interconnectBay             = ($_InterconnectMapTemplate.logicalLocation.locationEntries | Where-Object type -eq 'Bay').relativeValue
                            $_InterconnectBayMapping.logicalInterconnectGroupUri = $_LigEntry.uri 

                            # If LIG is not present in the EG interconnectBayMapping
                            if ((Compare-Object $_EnclosureGroup.interconnectBayMappings -DifferenceObject $_InterconnectBayMapping -Property enclosureIndex,interconnectBay,logicalInterconnectGroupUri -IncludeEqual).SideIndicator -notcontains '==') 
                            {

                                '[{0}] Mapping Frame {1} Bay {2} -> {3} ({4})' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_InterconnectBayMapping.enclosureIndex, $_InterconnectBayMapping.interconnectBay, $_LigEntry.Name, $_LigEntry.uri | Write-Verbose

                                [void]$_EnclosureGroup.interconnectBayMappings.Add($_InterconnectBayMapping)

                                $_c++

                            }
                            
                        }

                    }    

                }

            }

        }

        "[{0}] Updating enclosure group configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        try
        {

            Send-HPOVRequest -Uri $_EnclosureGroupToUpdate.Uri -Method PUT -Body $_EnclosureGroupToUpdate -Hostname $InputObject.ApplianceConnection

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVEnclosureGroup 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri", "name", "EnclosureGroup",'Resource')]
        [object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Enclosure'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection           = [System.Collections.ArrayList]::new()
        $_EnclosureGroupCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if  ($ApplianceConnection.Count -eq 0)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoAuthSessionFound InvalidArgument 'ApplianceConnection' -Message 'No ApplianceConnections were found. Please use Connect-HPOVMgmt to establish an appliance connection.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Enclosure Group Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ($InputObject.category -eq 'enclosure-groups')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType PSObject -Message "The Enclosure Group resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_EnclosureGroupCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType PSObject -Message "The Enclosure Group resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'enclosure-groups'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($enclosuregroup in $InputObject) 
            {

                # Enclosure passed is a URI
                if (($enclosuregroup -is [String]) -and [System.Uri]::IsWellFormedUriString($enclosure,'Relative')) 
                {

                    "[{0}] Received URI: $($enclosuregroup)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Enclosure Group Object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # // NEED APPLIANCE NAME HERE with If Condition
                    Try
                    {
                        
                        $enclosuregroup = Send-HPOVRequest -Uri $enclosuregroup -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Enclosure passed is the Name
                elseif (($enclosuregroup -is [String]) -and (-not($enclosuregroup.startsWith("/rest")))) 
                {

                    "[{0}] Received Enclosure Group Name $($enclosuregroup)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Enclosure Group object from Get-HPOVEnclosureGroup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    # // NEED APPLIANCE NAME HERE with If Condition
                    Try
                    {

                        $enclosuregroup = Get-HPOVEnclosureGroup -Name $enclosuregroup -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                    }
                    

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Enclosure passed is an object
                elseif ($enclosuregroup -is [PSCustomObject] -and ($enclosuregroup.category -ieq 'enclosure-groups')) 
                {
                    
                    "[{0}] Enclosure Group Object provided: $($enclosuregroup )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Resource' -TargetType 'PSObject' -Message "Invalid Resource Parameter: $($enclosuregroup )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                [void]$_EnclosureGroupCollection.Add($enclosuregroup)

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_EnclosureGroupCollection.count) Enclosure Group resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Enclosure Resources
        ForEach ($_enclosuregroup in $_EnclosureGroupCollection)
        {

            if ($PSCmdlet.ShouldProcess($_enclosuregroup.name,"Remove Enclosure Group from appliance '$($_enclosuregroup.ApplianceConnection)'?")) 
            {

                "[{0}] Removing Enclosure Group '$($_enclosuregroup.name)' from appliance '$($_enclosuregroup.ApplianceConnection)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($PSBoundParameters['Force'])
                    {

                        $_enclosuregroup.uri += "?force=true"

                    }

                    $_resp = Send-HPOVRequest -Uri $_enclosuregroup.Uri -Method DELETE -AddHeader @{'If-Match' = $_enclosuregroup.eTag } -Hostname $_enclosuregroup.ApplianceConnection

                    [void]$_TaskCollection.Add($_resp)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function Add-HPOVEnclosure 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Managed", SupportsShouldProcess, ConfirmImpact = "High")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredCredential")]
        [Parameter (Mandatory, ParameterSetName = "ManagedCredential")]
        [ValidateNotNullOrEmpty()]
        [Alias ("oa")]
        [String]$Hostname,
         
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ManagedCredential")]
        [ValidateNotNullOrEmpty()]
        [Alias ("eg",'EnclGroupName')]
        [object]$EnclosureGroup,

        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [Alias ("u", "user")]
        [String]$Username,

        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [Alias ("p", "pw")]
        [Object]$Password,

        [Parameter (Mandatory, ParameterSetName = "MonitoredCredential")]
        [Parameter (Mandatory, ParameterSetName = "ManagedCredential")]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "ManagedCredential")]
        [ValidateSet ('OneView', 'OneViewNoiLO', IgnoreCase = $False)]
        [Alias ("license", "l")]
        [String]$LicensingIntent = 'OneView',

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "ManagedCredential")]
        [Alias ("fwIso","fwBaselineIsoFilename")]
        [object]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "ManagedCredential")]
        [Alias ('forceFw','forceInstall')]
        [Switch]$ForceInstallFirmware,

        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredCredential")]
        [Switch]$Monitored,

        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredCredential")]
        [Parameter (Mandatory = $false, ParameterSetName = "ManagedCredential")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $False, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $False, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $False, ParameterSetName = "MonitoredCredential")]
        [Parameter (Mandatory = $False, ParameterSetName = "ManagedCredential")]
        [Switch]$Async,

        [Parameter (Mandatory = $False, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $False, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $False, ParameterSetName = "MonitoredCredential")]
        [Parameter (Mandatory = $False, ParameterSetName = "ManagedCredential")]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['EnclosureGroup']) -and ($PSCmdlet.ParameterSetName -ne 'Monitored'))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif  ($ApplianceConnection.Count -gt 1)
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {

                Try 
                {
    
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

        if ($PSBoundParameters['Credential'])
        {

            $_Username = $Credential.Username
            $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        elseif ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username and -Password parameters are being deprecated. Please transition your scripts to using the -Credential parameter."

            $_Username = $Username.clone()

            if ($Password -is [SecureString])
            {

                $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

            }

            else
            {

                $_Password = $Password.Clone()

            }

        }    

        elseif (-not $PSBoundParameters['Credential'] -and -not $PSBoundParameters['Username'])
        {

            $ExceptionMessage = "This Cmdlet requires credentials to the target resource. Please provide either the -Username and -Password, or -Credential parameters."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredPasswordParameter InvalidOperation 'Authentication' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }    

    }

    Process 
    {

        # Build the import object
        "[{0}] - Starting" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $_import          = NewObject -EnclosureImport
        $_import.hostname = $hostname
        $_import.username = $_Username
        $_import.password = $_Password

        if ($PSBoundParameters['Scope'])
        {

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_import.initialScopeUris.Add($_Scope.Uri)

            }

        }

        If ('MonitoredCredential', 'Monitored' -contains $PSCmdlet.ParameterSetName)
        {

            "[{0}] - Building Monitored Enclosure request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_import.licensingIntent = "OneViewStandard"
            $_import.state           = "Monitored"

        }

        else
        {

            "[{0}] - Building Managed Enclosure request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            switch ($EnclosureGroup.GetType().Name)
            {

                'PSCustomObject'
                {

                    "[{0}] - EnclosureGroup Parameter is 'PSCustomObject'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] - EnclosureGroup object category: '$($EnclosureGroup.category)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] - EnclosureGroup object name: '$($EnclosureGroup.name)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($EnclosureGroup.category -ne $ResourceCategoryEnum['EnclosureGroup'])
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.EnclosureGroupResourceException InvalidEnclosureGroupObject InvalidArgument 'EnclosureGroup' -TargetType 'PSObject' -Message "The EnclosureGroup Parameter value contains an invalid or unsupported resource category, '$($EnclosureGroup.category)'. The object category must be 'enclosure-groups'. Please correct the value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    else
                    {

                        $_enclosuregroup = $EnclosureGroup.PSObject.Copy()

                    }

                }

                'String'
                {

                    if ($EnclosureGroup.StartsWith($enclosureGroupsUri))
                    {

                        Try
                        {

                            $_enclosuregroup = Get-HPOVEnclosureGroup -Name $EnclosureGroup -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                        }

                        catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    else
                    {

                        Try
                        {

                            $_enclosuregroup = Get-HPOVEnclosureGroup -Name $EnclosureGroup -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                        }
                            
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }
                        
                    "[{0}] - Found Enclosure Group: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_enclosuregroup.name, $_enclosuregroup.uri | Write-Verbose

                }

            }

            $_import.licensingIntent      = $licensingIntent
            $_import.enclosureGroupUri    = $_enclosuregroup.uri
            $_import.forceInstallFirmware = [Bool]$forceInstallFirmware
            $_import.updateFirmwareOn     = "EnclosureOnly" 
            
            if ($PSBoundParameters['Baseline']) 
            {
                    
                "[{0}] - Firmware Baseline is to be configured" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                switch ($baseline.Gettype().Name) 
                {

                    "String" 
                    {
                            
                        if ($Baseline.StartsWith($ApplianceFwDriversUri)) 
                        {
                                
                            "[{0}] - Firmware Baseline URI Provided '$Baseline'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                
                            Try
                            {

                                $fwBaseLine = Send-HPOVRequest -Uri $Baseline -Hostname $ApplianceConnection.Name

                            }
                                
                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                        
                            
                        }
                            
                        elseif ((-not ($baseline.StartsWith($ApplianceFwDriversUri)) -and ($baseline.StartsWith('/rest/')))) 
                        {

                            "[{0}] - Invalid Firmware Baseline URI Provided '$Baseline'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                
                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InavlideBaselineUri InvalidArgument 'Baseline' -Message "The Baseline URI '$baseline' provided does not Begin with '$ApplianceFwDriversUri'. Please correct the value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                        }

                        else 
                        {

                            "[{0}] - Firmware Baseline Name Provided '$Baseline'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                
                            if ($Baseline -match ".iso") 
                            {

                                "[{0}] - Getting Baseline based on isoFileName." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                Try
                                {

                                    $FirmwareBaslineName = $Baseline.Clone()

                                    $fwBaseLine = Get-HPOVBaseline -isoFileName $Baseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                                    If (-not $fwBaseLine)
                                    {

                                        $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }
                                                                
                            }

                            else 
                            {

                                "[{0}] - Getting Baseline based on Baseline Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                Try
                                {

                                    $FirmwareBaslineName = $Baseline.Clone()

                                    $fwBaseLine = Get-HPOVBaseline -SppName $Baseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                                    If (-not $fwBaseLine)
                                    {

                                        $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }
                                
                            }

                        }

                        $_import.firmwareBaselineUri = $fwBaseLine.uri
                        
                    }

                    "PSCustomObject" 
                    {

                        if ($Baseline.category -eq $ResourceCategoryEnum['Baseline'] -and $baseline.ApplianceConnection -eq $ApplianceConnection.Name) 
                        {

                            "[{0}] - Firmware Baseline Object Provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.FileName, $Baseline.uri | Write-Verbose
                                
                            $_import.firmwareBaselineUri = $Baseline.uri    

                        }

                        else 
                        {

                            "[{0}] - Invalid Firmware Baseline Object Provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.name, $Baseline.uri | Write-Verbose

                            if ($Baseline.category -ne $ResourceCategoryEnum['Baseline'] -and $baseline.ApplianceConnection -eq $ApplianceConnection.Name) 
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalideBaselineObject InvalidArgument 'Baseline' -TargetType 'PSObject' -Message "The Baseline Category '$($baseline.category)' provided does not match the required value 'firmware-drivers'. Please correct the value and try again."

                            }
                                
                            elseif ($Baseline.category -eq $ResourceCategoryEnum['Baseline'] -and $baseline.ApplianceConnection -ne $ApplianceConnection.Name) 
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalidBaselineOrigin InvalidArgument 'Baseline' -TargetType 'PSObject' -Message "The Baseline '$($baseline.name)' provided does not originate from the same ApplianceConnection you have specified. Please correct the value and try again."

                            }
                                
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                }

            }       

        }

        "[{0}] - Sending request to claim enclosure" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $resp = Send-HPOVRequest -uri $EnclosuresUri -Method POST -Body $_import -Hostname $ApplianceConnection.Name | Wait-HPOVTaskStart

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # "[{0}] - task response: $($resp | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Check to see if the task errored, which should be in the Task Validation stage
        if ($resp.taskState -ne "Running") 
        {

            if ($resp.taskState -eq "Error")
            {

                "[{0}] - Task error found $($resp.taskState) $($resp.stateReason) " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($resp.taskerrors | Where-Object { ($_.errorCode -eq "ENCLOSURE_ALREADY_MANAGED") -or ($_.errorCode -eq "ENCLOSURE_MANAGED_BY_VCM") }) 
                {
                
                    $errorMessage = $resp.taskerrors | Where-Object { ($_.errorCode -eq "ENCLOSURE_ALREADY_MANAGED") -or ($_.errorCode -eq "ENCLOSURE_MANAGED_BY_VCM") }

                    $externalManagerType = $errorMessage.data.managementProduct
                    $externalManagerIP   = $errorMessage.data.managementUrl.Replace("https://","")
                    
                    Try
                    {

                         $externalManagerFQDN = [System.Net.DNS]::GetHostByAddress($externalManagerIP)

                    }

                    Catch
                    {

                        "[{0}] Unable to resolve IP Address to DNS A Record." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        $externalManagerFQDN = [PSCustomObject]@{HostName = 'UnknownFqdn'; Aliases = @(); AddressList = @($externalManagerIP.Clone())}

                    }

                    "[{0}] - Found enclosure '$hostname' is already being managed by $externalManagerType at $externalManagerIP." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] - $externalManagerIP resolves to $externalManagerFQDN" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    write-warning "Enclosure '$hostname' is already being managed by $externalManagerType at $externalManagerIP ($($externalManagerFQDN.HostName))."

                    if ($PSCmdlet.ShouldProcess($hostname,"Enclosure '$hostname' is already being managed by $externalManagerType at $externalManagerIP ($($externalManagerFQDN.HostName)). Force add?")) 
                    {
                    
                        "[{0}] - Server was claimed and user chose YES to force add." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_import.force = $true
                        
                        Try
                        {
                        
                            $resp = Send-HPOVRequest $EnclosuresUri POST $_import -Hostname $ApplianceConnection.Name
                        
                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }                        

                    }

                    else 
                    {

                        if ($PSBoundParameters['whatif'].ispresent) 
                        {     
                    
                            write-warning "-WhatIf was passed, would have force added '$hostname' enclosure to appliance."

                            $resp = $null
                    
                        }

                        else 
                        {

                            # If here, user chose "No", End Processing
                            write-warning "Not importing enclosure, $hostname."

                            $resp = $Null

                        }

                    }

                }

                else 
                {

                    $errorMessage = $resp.taskerrors

                    if ($errorMessage -is [Array]) 
                    { 
                
                        # Loop to find a Message value that is not blank.
                        $displayMessage = $errorMessage | Where-Object { $_.message }

                        $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException $displayMessage.errorCode InvalidResult 'New-HPOVEnclosure' -Message $displayMessage.message 
                    
                    }
                
                    else 
                    { 
                        
                        $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException $errorMessage.errorCode InvalidResult 'New-HPOVEnclosure' -Message ($errorMessage.details + " " + $errorMessage.message) 
                    
                    }

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        if (-not($PSBoundParameters['Async']))
        {

            Try
            {

                $resp = Wait-HPOVTaskComplete -InputObject $resp

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }        

        [void]$colStatus.Add($resp)

    }

    End 
    {
        
        Return $colStatus

    }

}

function Add-HPOVRemoteFrame
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Async,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command
        
        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
        {
            
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
        }

        elseif  ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
        }

        else
        {

            Try 
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        # Locate the Enclosure Group specified
        "[{0}] - Starting" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        if (-not $Hostname.StartsWith('fe80:'))
        {

            $ExceptionMessage = 'The value provided for Hostname, {0}, is not a valid IPv6 Link Local Address.' -f $Hostname
            $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidIPv6LinkLocalAddress InvalidArgument 'Hostname' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_RemoteFrameAdd = @{hostname = $Hostname}

        "[{0}] - Sending request to claim remote frame: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname | Write-Verbose
        
        Try
        {

            $resp = Send-HPOVRequest -uri $EnclosuresUri -Method POST -Body $_RemoteFrameAdd -Hostname $ApplianceConnection | Wait-HPOVTaskStart

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {
            
            Try
            {

                $resp | Wait-HPOVTaskComplete

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            $resp

        }    

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVEnclosure 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Refresh", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (ValueFromPipeline, Mandatory = $false, ParameterSetName = "Reapply")]
        [Parameter (ValueFromPipeline, Mandatory = $false, ParameterSetName = "Refresh")]
        [ValidateNotNullOrEmpty()]
        [Alias('Enclosure')]
        [object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Reapply")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Refresh")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory, ParameterSetName = "Refresh")]
        [Switch]$Refresh,

        [Parameter (Mandatory = $false, ParameterSetName = "Refresh")]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "Refresh")]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = "Refresh")]
        [Object]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = "Refresh")]
        [PSCredential]$Credential,

        [Parameter (Mandatory, ParameterSetName = "Reapply")]
        [Switch]$Reapply,

        [Parameter (Mandatory = $false, ParameterSetName = "Reapply")]
        [Parameter (Mandatory = $false, ParameterSetName = "Refresh")]
        [Switch]$Async

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection           = [System.Collections.ArrayList]::new()
        $_EnclosureCollection      = [System.Collections.ArrayList]::new()
        $_RefreshOptionsCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomobject]) 
        {
        
            "[{0}] Processing Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Error if the input value is not a PSObject
            if (-not $InputObject -is [PSCustomObject])
            {

                $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidEnclosureObjectType InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided InputObject value is not a valid PSObject ($($InputObject.GetType().Name)). Please correct your input value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Enclosure PSObject: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | out-string) | Write-Verbose

            # Validate the Input object is the allowed category
            if ($InputObject.category -ne $ResourceCategoryEnum['Enclosure'])
            {

                $ExceptionMessage = "The provided InputObject object ({0}) category '{1}' is not an allowed value. Expected category value is 'enclosures'. Please correct your input value." -f $InputObject.name, $InputObject.category
                $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidEnclosureCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if(-not $InputObject.ApplianceConnection)
            {

                $ExceptionMessage = "The provided InputObject object ({0}) does not contain the required 'ApplianceConnection' object property. Please correct your input value." -f $InputObject.name
                $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidEnclosureObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$_EnclosureCollection.Add($InputObject)
        
        }

        # Not Pipeline input, and support Array of Enclosure Name or PSObject
        else
        {

            "[{0}] Processing Enclosure Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($_encl in $InputObject)
            {
                    
                "[{0}] Enclosure value: {1}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_encl | Write-Verbose

                "[{0}] Looking for Enclosure Name on connected sessions provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Loop through all Appliance Connections
                ForEach ($_appliance in $ApplianceConnection)
                {

                    "[{0}] Processing '{1}' Session." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                    Try
                    {

                        $_resp = Get-HPOVLogicalEnclosure $_encl -ApplianceConnection $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [void]$_EnclosureCollection.Add($_resp)

                }
                    
            }

        }

    }

    End
    {
        # Perform the work
        ForEach ($_enclosure in $_EnclosureCollection) 
        {

            "[{0}] Processing Enclosure: '$($_enclosure.name) [$($_enclosure.uri)]'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            switch ($PSCmdlet.ParameterSetName) 
            {

                "Reapply" 
                { 

                    "[{0}] Reapply Enclosure configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Params = @{ uri = $_enclosure.uri + "/configuration"; method = 'PUT' }
                        
                }
                        
                "Refresh"
                { 

                    "[{0}] Refreshing Enclosure data." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_RefreshOptions = NewObject -EnclosureRefresh

                    $_uri = $_enclosure.uri + "/refreshState"

                    if ($_enclosure.state -ieq 'unmanaged' -and $_enclosure.stateReason -ieq 'unowned')
                    {

                        $_RefreshOptions.refreshForceOptions = NewObject -EnclosureRefreshForceOptions

                        if (-not $PSBoundParameters['Username'] -and -not $PSBoundParameters['Credential'])
                        {

                            $ExceptionMessage = "The appliance can no longer communicate with {0} Enclosure, and requires a valid Username, Password and Hostname/IPAddress. Please provide the correct parameters." -f $_enclosure.name
                            $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredUsernameParameter InvalidOperation 'Enclosure' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        if (-not $PSBoundParameters['Password'] -and -not $PSBoundParameters['Credential'])
                        {

                            $ExceptionMessage = "The appliance can no longer communicate with {0} Enclosure, and requires a valid Username, Password and Hostname/IPAddress. Please provide the correct parameters." -f $_enclosure.name
                            $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredPasswordParameter InvalidOperation 'Password' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        if (-not $PSBoundParameters['Hostname'])
                        {

                            $ExceptionMessage = "The appliance can no longer communicate with {0} Enclosure, and requires a valid Username, Password and Hostname/IPAddress. Please provide the correct parameters." -f $_enclosure.name
                            $ErrorRecord = New-ErrorRecord HPOneView.Library.UnsupportedArgumentException MissingRequiredHostnameParameter InvalidOperation 'Hostname' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        if ($PSBoundParameters['Credential'])
                        {

                            $_Username = $Credential.Username
                            $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

                        }

                        elseif ($PSBoundParameters['Username'])
                        {

                            Write-Warning "The -Username and -Password parameters are being deprecated. Please transition your scripts to using the -Credential parameter."

                            $_Username = $Username.clone()

                            if ($Password -is [SecureString])
                            {

                                $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

                            }

                            else
                            {

                                $_Password = $Password.Clone()

                            }

                        }

                        $_RefreshOptions.refreshForceOptions.address  = $Hostname
                        $_RefreshOptions.refreshForceOptions.username = $_Username
                        $_RefreshOptions.refreshForceOptions.password = $_Password

                    }

                    $_Params = @{ uri = $_uri; method = 'PUT'; body = $_RefreshOptions }
                        
                }
                
            }
            
            if ($PSCmdlet.ShouldProcess($_enclosure.name,"$($PSCmdlet.ParameterSetName) Enclosure configuration. WARNING: Depending on this action, there might be a brief outage."))
            { 

                "[{0}] Sending request to $($PSCmdlet.ParameterSetName) Enclosure configuration" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    $_task = Send-HPOVRequest @_Params -Hostname $_enclosure.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $PSBoundParameters['Async'])
                {
                    
                     $_task | Wait-HPOVTaskComplete
                
                }

                else
                {

                    $_task

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {
                
                "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            }

            else
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }           

        }

    }

}

function Get-HPOVLogicalEnclosure 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
  
    [CmdletBinding (DefaultParameterSetName = "default")]    
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [validateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "default")]
        [validateNotNullorEmpty()]
        [Object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$NonCompliant,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [validateNotNullorEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_LogicalEnclosureCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            # Handle pipeline input for connection object
            if ($_appliance -isnot [HPOneView.Appliance.Connection])
            {

                $_appliance = $ConnectedSessions | Where-Object ConnectionId -eq $_appliance.ConnectionId

            }

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($PSBoundParameters['NonCompliant'])
            {

                "[{0}] Filtering for non-compliant logical enclosures." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Void]$_Query.Add("state:'Inconsistent'")

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            # Build the final URI
            $_uri = '{0}?category=logical-enclosures&sort=name:asc&query={1}' -f $IndexUri, [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($EnclosureGroup)
            {

                "[{0}] Filtering Logical Enclosures for parent Enclosure Group '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup.name | Write-Verbose

                [Array]$_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object enclosureGroupUri -eq $EnclosureGroup.uri

            }
    
            if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
            { 
    
                "[{0}] Logical Enclosure '{1}' resource not found. Generating error" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                $ExceptionMessage = "The specified Logical Enclosure '{0}' was not found on '{1}' appliance. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.LogicalEnclosureResourceException LogicalEnclosureNotFound ObjectNotFound 'Name' -Message $ExceptionMessage  
                $PSCmdlet.WriteError($ErrorRecord)  
                
            }
    
            elseif ($_ResourcesFromIndexCol.count -eq 0) 
            { 
    
                "[{0}] No Logical Enclosure resources found on {1}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.name | Write-Verbose
    
            }
    
            else 
            {
    
                "[{0}] Found {1} Enclosure Group resources." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ResourcesFromIndexCol.count | Write-Verbose
    
                $_ResourcesFromIndexCol | ForEach-Object { 
                    
                    $_.PSObject.TypeNames.Insert(0,'HPOneView.LogicalEnclosure')    
    
                    [void]$_LogicalEnclosureCollection.Add($_) 
                    
                }
     
            }

        }

    }

    End 
    {
                
        "[{0}] Done. {1} total Logical Enclosure(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LogicalEnclosureCollection.count | Write-Verbose
                
        # Export results to exportfile
        if ($exportFile) 
        { 
            
            $_LogicalEnclosureCollection | convertto-json -depth 99 > $exportFile 
        
        }
        
        # else Return Logical Enclosure object(s)
        else 
        { 

            Return $_LogicalEnclosureCollection
        
        }

    }

}

function New-HPOVLogicalEnclosure
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,
         
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [object]$Enclosure,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('eg')]
        [object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$FirmwareBaseline,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Bool]$ForceFirmwareBaseline,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Enclosure']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskResourceCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {
                
            "[{0}] Synergy Frame object was passed via pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        # Error when target appliance is not a Synergy Composer or the Enclosure object is not a Synergy Frame
        if ((${Global:ConnectedSessions} | Where-Object Name -EQ $ApplianceConnection.Name).ApplianceType -ne 'Composer')
        {

            $Message = 'The Appliance {0} is not a Synergy Composer, and this operation is not supported. Only Synergy managed resources are supported with this Cmdlet.' -f $ApplianceConnection.Name

            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ComposerNodeException UnsupportedMethod InvalidOperation 'ApplianceConnection' -TargetType 'HPOneView.Appliance.Connection' -Message $Message

            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_LogicalEnclosure      = NewObject -LogicalEnclosure
        $_LogicalEnclosure.name = $Name

        # Get Frame object type
        switch ($Enclosure.GetType().Name)
        {

            'PSCustomObject'
            {

                "[{0}] Synergy Frame object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Enclosure | Out-String) | Write-Verbose 

                if ($Enclosure.category -ne $ResourceCategoryEnum['Enclosure'])
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidResourceObject InvalidArgument 'Enclosure' -TargetType 'PSObject' -Message "The provided -Enclosure resource object is not an Enclosure or Synergy Frame. Please correct the input object and try again."

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }

                # Validate Frame resource object
                if ($Enclosure.enclosureType -ne 'SY12000')
                {

                    # Throw error, wrong resource
                    $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException UnsupportedEnclosureType InvalidArgument 'Enclosure' -TargetType 'PSObject' -Message "The provided input object is not a Synergy Frame resource object. Only Synergy Frames are supported with this Cmdlet."

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                if ($Enclosure.state -ne 'Monitored')
                {

                    $ExceptionMessage = "The provided Synergy Frame resource '{0}' is already managed. Please select another Synergy Frame resource object." -f $Enclosure.name
                    $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidConfigurationState InvalidArgument -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            'String'
            {

                "[{0}] Synergy Frame Name provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Enclosure | Write-Verbose 

                Try
                {

                    $Enclosure = Get-HPOVEnclosure -Name $Enclosure -ApplianceConnection $ApplianceConnection

                    # Validate Frame resource object
                    if ($Enclosure.enclosureType -ne 'SY12000')
                    {

                        # Throw error, wrong resource
                        $ExceptionMessage = "The provided input object is not a Synergy Frame resource object. Only Synergy Frames are supported with this Cmdlet."
                        $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException UnsupportedEnclosureType InvalidArgument -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($Enclosure.state -ne 'Monitored')
                    {

                        $ExceptionMessage = "The provided Synergy Frame resource '{0}' is already managed. Please select another Synergy Frame resource object." -f $Enclosure.name
                        $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidConfigurationState InvalidArgument -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        # Get list of logical Frame members fro ILT
        Try
        {

            $_LinkedSynergyFrames = Send-HPOVRequest -Uri $InterconnectLinkTopologies -Hostname $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_IltGroup = $_LinkedSynergyFrames.members | Where-Object { $_.enclosureMembers.enclosureUri -contains $Enclosure.uri }
        
        foreach ($_member in $_IltGroup.enclosureMembers)
        {

            "[{0}] Processing Enclosure URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.enclosureUri | Write-Verbose

            if ($_member.errorFlag)
            {

                Try
                {

                    $_EnclosureObject = Send-HPOVRequest $_member.enclosureUri -Hostname $ApplianceConnection.Name

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                "[{0}] Synergy Frame is in an Error State: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_EnclosureObject.state, $_EnclosureObject.stateReason | Write-Verbose 

                $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException InvalidConfigurationState InvalidArgument -TargetType 'PSObject' -Message ("The provided or linked Synergy Frame resource '{0}' is in an Error State: {1} ({2}) Please select another Synergy Frame resource object." -f $_EnclosureObject.name, $_EnclosureObject.state, $_EnclosureObject.stateReason)

                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$_LogicalEnclosure.enclosureUris.Add($_member.enclosureUri)

        }

        # Validate EG
        switch ($EnclosureGroup.GetType().Name)
        {

            'PSCustomObject'
            {

                "[{0}] Enclosure Group object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($EnclosureGroup | ConvertTo-Json -Depth 99 | Out-String) | Write-Verbose 

                if ($EnclosureGroup.category -ne $ResourceCategoryEnum['EnclosureGroup'])
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.EnclosureGroupResourceException InvalidResourceObject InvalidArgument -TargetType 'PSObject' -Message "The provided -EnclosureGroup resource object is not an Enclosure Group. Please correct the input object and try again."

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }

            }

            'String'
            {

                "[{0}] Enclosure Group Name provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup | Write-Verbose 

                Try
                {

                    $EnclosureGroup = Get-HPOVEnclosureGroup -Name $EnclosureGroup -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_LogicalEnclosure.enclosureGroupUri = $EnclosureGroup.uri
        
        if ($PSBoundParameters['FirmwareBasline'])
        {

            # Validate Firmware Baseline
            switch ($FirmwareBasline.GetType().Name)
            {
                
                'PSCustomObject'
                {

                    "[{0}] FirmwareBasline object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($FirmwareBasline | Out-String) | Write-Verbose 

                    if ($FirmwareBasline.category -ne $ResourceCategoryEnum['Baseline'])
                    {
                    
                        $ErrorRecord = New-ErrorRecord HPOneView.FirmwareBaselineResourceException InvalidResourceObject InvalidArgument -TargetType 'PSObject' -Message "The provided -FirmwareBasline resource object is not a Firmwaer Baseline. Please correct the input object and try again."

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                }

                'String'
                {

                    "[{0}] Firmware Baseline Name provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $FirmwareBasline | Write-Verbose 

                    Try
                    {

                        $FirmwareBaslineName = $FirmwareBasline.Clone()
                        $FirmwareBasline = Get-HPOVBaseline  -File $FirmwareBasline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                        If (-not $FirmwareBasline)
                        {

                            $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'FirmwareBasline' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            $_LogicalEnclosure.firmwareBaselineUri  = $FirmwareBaseline.uri
            $_LogicalEnclosure.forceInstallFirmware = $ForceFirmwareBaseline

        }

        # "[{0}] Logical Enclosure object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_LogicalEnclosure | out-string) | Write-Verbose

        "[{0}] Creating {1} Logical Enclosure" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LogicalEnclosure.name | Write-Verbose

        if ($PSBoundParameters['Scope'])
        {

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_LogicalEnclosure.initialScopeUris.Add($_Scope.Uri)

            }

        }

        Try
        {

            $resp = Send-HPOVRequest -URI $LogicalEnclosuresUri -Method 'POST' -Body $_LogicalEnclosure -ApplianceConnection $ApplianceConnection
            
            if (-not $PSBoundParameters['Async'])
            {
                
                $resp = $resp | Wait-HPOVTaskComplete 
                
            }

            else
            {

                $resp

            }

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVLogicalEnclosure
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'cClass')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String[]]$ConfigurationScript,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'cClass')]
        [ValidateNotNullOrEmpty()]
        [Alias ('eg')]
        [Object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('RedundantPowerFeed', 'RedundantPowerSupply')]
        [String]$PowerMode,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('ASHRAE_A3', 'ASHRAE_A4', 'Standard', 'Telco')]
        [String]$AmbientTemperatureSetting,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'cClass')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'cClass')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskResources = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($InputObject.enclosureModel -match 'Synergy' -and $PSBoundParameters['ConfigurationScript'])
        {

            $ExceptionMessage = 'The InputObject {0} is not a supported resource to set the Enclosure ConfigurationScript.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'ConfigurationScript' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }
        
        elseif ((${Global:ConnectedSessions} | Where-Object Name -EQ $ApplianceConnection.Name).ApplianceType -ne 'Composer')
        {

            $Message = 'The Appliance {0} is not a Synergy Composer, and this operation is not supported. Only Synergy managed resources are supported with this Cmdlet.' -f $ApplianceConnection.Name
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ComposerNodeException UnsupportedMethod InvalidOperation 'ApplianceConnection' -TargetType 'HPOneView.Appliance.Connection' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }    

        if ($PipelineInput) 
        {
                
            "[{0}] Resource object was passed via pipeline."  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }        

        # Get type
        switch ($InputObject.GetType().Name)
        {

            'PSCustomObject'
            {

                "[{0}] Synergy Frame object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Out-String) | Write-Verbose 

                if ($InputObject.category -ne $ResourceCategoryEnum['LogicalEnclosure'])
                {
                
                    $ExceptionMessage = "The provided -Enclosure resource object is not an Enclosure or Synergy Frame. Please correct the input object and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidResourceObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }

                Try
                {

                    "[{0}] Getting associated Enclosure Group to identify enclosure type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                    
                    $_EnclosureGroup = Send-HPOVRequest -Uri $InputObject.enclosureGroupUri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                if ($_EnclosureGroup.enclosureTypeUri -NotMatch 'SY12000')
                {

                    # Throw error, wrong resource
                    $ExceptionMessage = "The provided input object is not a Synergy Frame resource object. Only Synergy Frames and associated Logical Enclosures are supported with this Cmdlet."
                    $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException UnsupportedEnclosureType InvalidArgument -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_UpdatedLogicalEnclosure = $InputObject.PSObject.Copy()

            }

            'String'
            {

                "[{0}] Synergy Frame name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose 

                Try
                {

                    $_UpdatedLogicalEnclosure = Get-HPOVLogicalEnclosure -Name $InputObject -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Try
                {

                    "[{0}] Getting associated Enclosure Group to identify enclosure type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                    
                    $_EnclosureGroup = Send-HPOVRequest -Uri $InputObject.enclosureGroupUri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                if ($_EnclosureGroup.enclosureTypeUri -NotMatch 'SY12000')
                {

                    # Throw error, wrong resource
                    $ExceptionMessage = "The provided input object is not a Synergy Frame resource object. Only Synergy Frames and associated Logical Enclosures are supported with this Cmdlet."
                    $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException UnsupportedEnclosureType InvalidArgument -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        switch ($PSBoundParameters.Keys)
        {

            'Name'
            {

                $_UpdatedLogicalEnclosure.name = $Name

            }

            'EnclosureGroup'
            {

                # Validate EG
                switch ($EnclosureGroup.GetType().Name)
                {

                    'PSCustomObject'
                    {

                        "[{0}] Enclosure Group object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($EnclosureGroup | ConvertTo-Json -Depth 99 | Out-String) | Write-Verbose 

                        if ($EnclosureGroup.category -ne $ResourceCategoryEnum['EnclosureGroup'])
                        {
                        
                            $ExceptionMessage = "The provided -EnclosureGroup resource object is not an Enclosure Group. Please correct the input object and try again."
                            $ErrorRecord = New-ErrorRecord HPOneView.EnclosureGroupResourceException InvalidResourceObject InvalidArgument -TargetType 'PSObject' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                        }

                    }

                    'String'
                    {

                        "[{0}] Enclosure Group Name provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup | Write-Verbose 

                        Try
                        {

                            $EnclosureGroup = Get-HPOVEnclosureGroup -Name $EnclosureGroup -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

                $_UpdatedLogicalEnclosure.enclosureGroupUri = $EnclosureGroup.uri

            }

            'PowerMode'
            {

                $_UpdatedLogicalEnclosure.powerMode = $FramePowerModeEnum[$PowerMode]

            }

            'AmbientTemperatureSetting'
            {

                $_UpdatedLogicalEnclosure.ambientTemperatureMode = $FrameAmbientTemperatureEnum[$AmbientTemperatureSetting]

            }

        }

        Try
        {

            $resp = Send-HPOVRequest -Uri $InputObject.uri -Method PUT $_UpdatedLogicalEnclosure -Hostname $ApplianceConnection.Name
            
            if (-not $PSBoundParameters['Async'])
            {
                
                $resp = $resp | Wait-HPOVTaskComplete -TimeOut (New-TimeSpan -Minutes 45)
                
            }

            [void]$_TaskResources.Add($resp)

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['ConfigurationScript'])
        {

            # Need to test this if true.
            # if ($PSBoundParameters['Async'])
            # {

            # "[{0}] Async it not supported while also needing to update the Logical Enclosure configuration script." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # $resp | Wait-HPOVTaskComplete -TimeOut (New-TimeSpan -Minutes 45)

            # }

            "[{0}] Setting Logical Enclosure configuration script." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_Uri = '{0}/script' -f $InputObject.uri

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_Uri -Method PUT -Body $ConfigurationScript -Hostname $InputObject.ApplianceConnection

                if (-not $PSBoundParameters['Async'])
                {
                    
                    $_resp = $_resp | Wait-HPOVTaskComplete
                    
                }

                [void]$_TaskResources.Add($_resp)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }    

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        return $_TaskResources

    }

}

function Update-HPOVLogicalEnclosure 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Reapply", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (ValueFromPipeline, Mandatory = $false, ParameterSetName = "Update")]
        [Parameter (ValueFromPipeline, Mandatory = $false, ParameterSetName = "Reapply")]
        [ValidateNotNullOrEmpty()]
        [Alias ('le','LogicalEnclosure')]
        [object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Update")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Reapply")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory, ParameterSetName = "Update")]
        [Alias ('UpdateFromGroup')]
        [Switch]$Update,

        [Parameter (Mandatory, ParameterSetName = "Reapply")]
        [Switch]$Reapply,

        [Parameter (Mandatory = $false, ParameterSetName = "Update")]
        [Parameter (Mandatory = $false, ParameterSetName = "Reapply")]
        [Switch]$Async

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection             = [System.Collections.ArrayList]::new()
        $_LogicalEnclosureCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if ($PipelineInput -or $InputObject) 
        {
        
            "[{0}] Processing Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Error if the input value is not a PSObject
            if (-not $InputObject -is [PSCustomObject])
            {

                $ErrorRecord = New-ErrorRecord HPOneView.LogicalEnclosureResourceException InvalidLogicalEnclosureObjectType InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided LogicalEnclosure value is not a valid PSObject ($($LogicalEnclosure.GetType().Name)). Please correct your input value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] LogicalEnclosure PSObject: $($InputObject | Out-String)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Validate the Input object is the allowed category
            if ($InputObject.category -ne $ResourceCategoryEnum['LogicalEnclosure'])
            {

                $ErrorRecord = New-ErrorRecord HPOneView.LogicalEnclosureResourceException InvalidLogicalEnclosureCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided LogicalEnclosure object ($($LogicalEnclosure.name)) category '$($LogicalEnclosure.category)' is not an allowed value. Expected category value is 'logical-enclosures'. Please correct your input value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if(-not $InputObject.ApplianceConnection)
            {

                $ErrorRecord = New-ErrorRecord HPOneView.LogicalEnclosureResourceException InvalidLogicalEnclosureObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided LogicalEnclosure object ($($LogicalEnclosure.name)) does not contain the required 'ApplianceConnection' object property. Please correct your input value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$_LogicalEnclosureCollection.Add($InputObject)
        
        }

        # Not Pipeline input, and support Array of Logical Enclosure Name or PSObject
        else
        {

            "[{0}] Processing InputObject Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] InputObject is [$($InputObject.GetType().Name)]." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($_le in $InputObject)
            {
                    
                "[{0}] InputObject value: $($_le)." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Looking for Logical Enclosure Name on connected sessions provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Loop through all Appliance Connections
                ForEach ($_appliance in $ApplianceConnection)
                {

                    "[{0}] Processing '$($_appliance.Name)' Session." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_resp = Get-HPOVLogicalEnclosure $_le -ApplianceConnection $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [void]$_LogicalEnclosureCollection.Add($_resp)

                }

            }

        }

    }

    End
    {
        # Perform the work
        ForEach ($_leObject in $_LogicalEnclosureCollection) 
        {

            "[{0}] Processing Logical Enclosure: '$($_leObject.name) [$($_leObject.uri)]'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $NothingToDo = $false
            
            switch ($PSCmdlet.ParameterSetName) 
            {

                "Reapply" 
                { 

                    "[{0}] Reapply configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $uri = $_leObject.uri + "/configuration" 
                
                }
                
                "Update"
                { 

                    "[{0}] Update from Group." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $uri = $_leObject.uri + "/updateFromGroup" 

                    if ($_leObject.state -eq 'Consistent')
                    {

                        $NothingToDo = $true

                    }
                
                }
                
            }

            if ((-not $NothingToDo) -and $PSCmdlet.ShouldProcess($_leObject.name,"$($PSCmdlet.ParameterSetName) Logical Enclosure configuration. WARNING: Depending on this action, there might be a brief outage."))
            { 

                "[{0}] Sending request to $($PSCmdlet.ParameterSetName) configuration" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_task = Send-HPOVRequest $uri PUT -Hostname $_leObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not($PSBoundParameters['Async']))
                {
                    
                    $_task | Wait-HPOVTaskComplete
                
                }

                else
                {

                    $_task

                }

            }

            elseif ($NothingToDo)
            {

                Write-Warning ("The {0} Logical Enclosure is already consistent. There is nothing to do." -f $_leObject.Name)

            }

            elseif ($PSBoundParameters['WhatIf'])
            {
                
                "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($PSCmdlet.ParameterSetName -eq 'Update')
                {

                    Try
                    {

                        Compare-LogicalInterconnect -InputObject $_leObject

                    } 

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }
            
            }

            else
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }           

        }

    }

}

function Update-HPOVLogicalEnclosureFirmware 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('le','LogicalEnclosure')]
        [object]$InputObject,
        
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [object]$Baseline,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateSet('EnclosureOnly', 'SharedInfrastructureOnly', 'SharedInfrastructureAndServerProfiles')]
        [String]$FirmwareUpdateProcess,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet('Orchestrated','Parallel')]
        [String]$InterconnectActivationMode = 'Orchestrated',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$ForceInstallation,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection             = [System.Collections.ArrayList]::new()
        $_LogicalEnclosureCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        ForEach ($_InputObject in $InputObject)
        {

            # Resource Validations

            # Validate the Input object is the allowed category
            if ($_InputObject.category -ne $ResourceCategoryEnum.LogicalEnclosure)
            {

                $ExceptionMessage = "The provided LogicalEnclosure object {0} category '{1}' is not an allowed value. Expected category value is 'logical-enclosures'. Please correct your input value." -f $_InputObject.name, $_InputObject.category
                $ErrorRecord = New-ErrorRecord HPOneView.LogicalEnclosureResourceException InvalidLogicalEnclosureCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($Baseline.category -ne $ResourceCategoryEnum.Baseline -or $Baseline.bundleType -ne 'SPP')
            {

                $ExceptionMessage = "The provided Baseline object {0} is not a valid resource object. Only an SPP can be used to update firmware. Please correct your input value." -f $Baseline.name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalidBaselineObject InvalidArgument 'Baseline' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not $baseline.ApplianceConnection.Equals($_InputObject.ApplianceConnection))
            {

                $ExceptionMessage = "The provided LogicalEnclosure object {0} and baseline object {1} are not from the same HPE OneViwe appliance." -f $_InputObject.name, $Baseline.name
                $ErrorRecord = New-ErrorRecord HPOneView.LogicalEnclosureResourceException InvalidLogicalEnclosureCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Processing Logical Enclosure: {0} [{1}]'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_InputObject.name, $_InputObject.uri | Write-Verbose

            $_FirmwareUpdate = NewObject -LogicalEnclosureFirmareUpdate

            $_FirmwareUpdate.firmwareBaselineUri           = $Baseline.uri
            $_FirmwareUpdate.firmwareUpdateOn              = $LogicalEnclosureFirmwareUpdateMethodEnum[$FirmwareUpdateProcess]
            $_FirmwareUpdate.forceInstallFirmware          = $ForceInstallation.IsPresent
            $_FirmwareUpdate.logicalInterconnectUpdateMode = $LogicalInterconnectUpdateModeEnum[$InterconnectActivationMode]

            $_PatchOperation = NewObject -PatchOperation

            $_PatchOperation.op = "replace"
            $_PatchOperation.path = "/firmware"
            $_PatchOperation.value = $_FirmwareUpdate

            Switch ($LogicalEnclosureFirmwareUpdateMethodEnum[$FirmwareUpdateProcess])
            {

                'EnclosureOnly'
                {

                    $_ShouldProcessMessage = 'update enclosure controller (Onboard Administrator or Frame Link Module(s)) only'

                }

                'SharedInfrastructureOnly'
                {

                    if ($LogicalInterconnectUpdateModeEnum[$InterconnectActivationMode] -eq $LogicalInterconnectUpdateModeEnum['Parallel'])
                    {

                        Write-Warning "Parallel activation is optimized for faster updates and will cause service outages. Firmware updates using parallel activation should be performed within a maintenance window."

                    }

                    $_ShouldProcessMessage = 'update all infrastructure components, enclosure controller (Onboard Administrator or Frame Link Module(s)) and Virtual Connect. Servers without assigned Server Profiles will also be updated.'

                }

                'SharedInfrastructureAndServerProfiles'
                {

                    if ($LogicalInterconnectUpdateModeEnum[$InterconnectActivationMode] -eq $LogicalInterconnectUpdateModeEnum['Parallel'])
                    {

                        Write-Warning "Parallel activation is optimized for faster updates and will cause service outages. Firmware updates using parallel activation should be performed within a maintenance window."

                    }

                    $_ShouldProcessMessage = 'update all components within the logical enclosure, including enclosure controller, Virtual Connect and servers'

                }

            }            

            if ($ForceInstallation.IsPresent)
            {

                Write-Warning "Downgrading the firmware can result in the installation of unsupported firmware and cause hardware to cease operation."

            }            

            if ($PSCmdlet.ShouldProcess($_InputObject.name, $_ShouldProcessMessage))
            { 

                "[{0}] Sending request to update firmware on the Logical Enclosure with {1} mode" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalEnclosureFirmwareUpdateMethodEnum[$FirmwareUpdateProcess] | Write-Verbose

                Try
                {

                    $_task = Send-HPOVRequest -Uri $_InputObject.uri -Method PATCH -Body $_PatchOperation -AddHeader @{'If-Match' = $_InputObject.eTag} -Hostname $_InputObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not($PSBoundParameters['Async']))
                {
                    
                    $_task | Wait-HPOVTaskComplete
                
                }

                else
                {

                    $_task

                }

            }


            elseif ($PSBoundParameters['WhatIf'])
            {
                
                "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # // TODO: Need to get API calls to supply the report
                # if ($PSCmdlet.ParameterSetName -eq 'Update')
                # {

                # Try
                # {

                # Compare-LogicalInterconnect -InputObject $_leObject

                # }

                # Catch
                # {

                # $PSCmdlet.ThrowTerminatingError($_)

                # }

                # }
            
            }

            else
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }    

        }

    }

    End
    {
        
        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVLogicalEnclosure 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri", "name", "le",'Resource')]
        [object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_LECollection   = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Logical Enclosure Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ($InputObject.category -eq 'logical-enclosures')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType PSObject -Message "The Network resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_LECollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType PSObject -Message "The Enclosure resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'enclosures'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($enclosure in $InputObject) 
            {

                # Enclosure passed is a URI
                if (($enclosure -is [String]) -and [System.Uri]::IsWellFormedUriString($enclosure,'Relative')) 
                {

                    "[{0}] Received URI: $($enclosures)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Enclosure Object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # // NEED APPLIANCE NAME HERE with If Condition
                    Try
                    {

                        $enclosure = Send-HPOVRequest -Uri $enclosure -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                
                }

                # Enclosure passed is the Name
                elseif (($enclosure -is [String]) -and (-not($enclosure.startsWith("/rest")))) 
                {

                    "[{0}] Received Enclosure Name $($enclosure)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Enclosure object from Get-HPOVEnclosure" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    # // NEED APPLIANCE NAME HERE with If Condition
                    Try
                    {

                        $enclosure = Get-HPOVLogicalEnclosure -Name $enclosure -ApplianceConnection $ApplianceConnection

                    }
                    

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Enclosure passed is an object
                elseif ($enclosure -is [PSCustomObject] -and ($enclosure.category -ieq 'enclosures')) 
                {
                    
                    "[{0}] Enclosure Object provided: $($enclosure )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Resource' -TargetType 'PSObject' -Message "Invalid Resource Parameter: $($enclosure )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                [void]$_LECollection.Add($enclosure)

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_LECollection.count) Logical Enclosure resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Enclosure Resources
        ForEach ($_enclosure in $_LECollection)
        {

            if ($PSCmdlet.ShouldProcess($_enclosure.name,"Remove Logical Enclosure from appliance '$($_enclosure.ApplianceConnection)'")) 
            {

                "[{0}] Removing Logical Enclosure '$($_enclosure.name)' from appliance '$($_enclosure.ApplianceConnection)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($PSBoundParameters['Force'])
                    {

                        $_enclosure.uri += "?force=true"

                    }

                    $_resp = Send-HPOVRequest -Uri $_enclosure.Uri -Method DELETE -AddHeader @{'If-Match' = $_enclosure.eTag } -Hostname $_enclosure.ApplianceConnection

                    [void]$_TaskCollection.Add($_resp)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function Invoke-HPOVVcmMigration 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = "High")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Report")]    
        [Parameter (Mandatory, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Alias ('oip')]
        [ValidateNotNullOrEmpty()]
        [System.String]$OAIPAddress,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('ou')]
        [ValidateNotNullOrEmpty()]
        [System.String]$OAUserName,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('op')]
        [ValidateNotNullOrEmpty()]
        [System.Object]$OAPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [PSCredential]$OACredential,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('vu')]
        [ValidateNotNullOrEmpty()]
        [System.String]$VCMUserName,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('vp')]
        [ValidateNotNullOrEmpty()]
        [System.Object]$VCMPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [PSCredential]$VCMCredential,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Default")]
        [Alias ('eg')]
        [ValidateScript({
            if (($_ -is [String]) -and ($_.StartsWith('/rest/')) -and (-not ($_.StartsWith('/rest/enclosure-groups')))) { Throw "'$_' is not an allowed resource URI. Enclosure Group Resource URI must start with '/rest/enclosure-groups'. Please check the value and try again." } 
            elseif ($_ -is [String] -and ($_.StartsWith('/rest/'))) { $True }
            elseif ($_ -is [String]) { $True }
            
            elseif (($_ -is [PSCustomObject]) -and (-not ($_.category -eq "enclosure-groups"))) { 
            
                if ($_.category) { Throw "'$_.category' is not an allowed resource category. The resource object category must be 'enclosure-groups'. Please check the value and try again." }
                else { Throw "The object provided does not contain an the allowed resource category 'enclosure-groups'. Please check the value and try again." }
            }
            else { $True } })]
        [Object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('lig')]
        [ValidateScript({
            if (($_ -is [String]) -and ($_.StartsWith('/rest/')) -and (-not ($_.StartsWith('/rest/logical-interconnect-groups')))) { Throw "'$_' is not an allowed resource URI. Logical Interconnect Group Resource URI must start with '/rest/logical-interconnect-groups'. Please check the value and try again." } 
            elseif ($_ -is [String] -and ($_.StartsWith('/rest/'))) { $True }
            elseif ($_ -is [String]) { $True }
            
            elseif (($_ -is [PSCustomObject]) -and (-not ($_.category -eq "logical-interconnect-groups"))) { 
            
                if ($_.category) { Throw "'$_.category' is not an allowed resource category. The resource object category must be 'logical-interconnect-groups'. Please check the value and try again." }
                else { Throw "The object provided does not contain an the allowed resource category 'logical-interconnect-groups'. Please check the value and try again." }
            }
            else { $True } })]
        [Object]$LogicalInterconnectGroup,

        [Parameter (Mandatory, ParameterSetName = "Report")]
        [Parameter (Mandatory, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateSet ("OneView", "OneViewNoiLO", IgnoreCase = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ("license", "l")]
        [System.String]$LicensingIntent,

        [Parameter (Mandatory, ParameterSetName = "VCEMMigration")]
        [String]$VCEMCMS,

        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [String]$VCEMUser,

        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [System.Object]$VCEMPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "VCEMMigration")]
        [PSCredential]$VCEMCredential,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('NoWait')]
        [Switch]$Async,

        [Parameter (Mandatory, ParameterSetName = "Report")]
        [Switch]$Report,

        [Parameter (Mandatory = $false, ParameterSetName = "Report")]
        [Alias ("Export")]
        [ValidateScript({
            if ({split-path $_ | Test-Path}) { $True } 
            else { Throw "'$(Split-Path $_)' is not a valid directory. Please verify $(Split-Path $_) exists and try again." } 
            })]
        [System.IO.FileInfo]$Path,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "VCEMMigration")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Report")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
        
    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        Switch ($PSBoundParameters.Keys)
        {

            'OAUsername'
            {

                Write-Warning "OAUsername paramter is being deprecated. Please upsate and use the -OACredential parameter."

            }

            'OAPassword'
            {

                Write-Warning "OAPassword paramter is being deprecated. Please upsate and use the -OACredential parameter."

            }

            'VCMUsername'
            {

                Write-Warning "VCMUsername paramter is being deprecated. Please upsate and use the -VCMCredential parameter."

            }

            'VCMPassword'
            {

                Write-Warning "VCMPassword paramter is being deprecated. Please upsate and use the -VCMCredential parameter."

            }

            'VCEMUsername'
            {

                Write-Warning "VCEMUsername paramter is being deprecated. Please upsate and use the -VCEMCredential parameter."

            }

            'VCEMPassword'
            {

                Write-Warning "VCEMPassword paramter is being deprecated. Please upsate and use the -VCEMCredential parameter."

            }

        }

        if ($OACredential)
        {

            $OAUsername  = $OACredential.Username
            $_OAPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($OACredential.Password))

        }

        else
        {

            if ($OAPassword -is [SecureString])
            {

                $_OAPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($OAPassword))
                
            }

            else
            {

                $_OAPassword = $OAPassword.clone()

            }

        }

        if ($VCMCredential)
        {

            $VCMUserName  = $VCMCredential.Username
            $_VCMPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($VCMCredential.Password))

        }

        else
        {

            if ($VCMPassword -is [SecureString])
            {

                $_VCMPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($VCMPassword))

            }

            else
            {

                $_VCMPassword = $VCMPassword.clone()

            }

        }

        if ($VCEMCredential)
        {

            $VCEMUsername  = $VCEMCredential.Username
            $_VCEMPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($VCEMCredential.Password))

        }

        elseif ($VCEMUser)
        {

            if ($VCEMPassword -is [SecureString])
            {

                $_VCEMPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($VCEMPassword))

            }

            else
            {

                $_VCEMPassword = $VCEMPassword.clone()

            }

        }

    }
    
    Process 
    {

        $VcMigrationObject = NewObject -vcMigration
        
        $VcMigrationObject.iloLicenseType          = $LicensingIntent
        $VcMigrationObject.credentials.oaIpAddress = $OAIPAddress
        $VcMigrationObject.credentials.oaUsername  = $OAUserName
        $VcMigrationObject.credentials.oaPassword  = $_OAPassword
        $VcMigrationObject.credentials.vcmUsername = $VCMUserName
        $VcMigrationObject.credentials.vcmPassword = $_VCMPassword

        # Check to see if EnclosureGroup was provided
        if ($PSBoundParameters['EnclosureGroup']) 
        {
        
            switch ($EnclosureGroup.Gettype().Name) 
            {

                # Validate the String value
                "String" 
                { 
                
                    # The value is an Enclosure Group URI
                    if ($EnclosureGroup.startswith('/rest/enclosure-groups')) 
                    {

                        "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Enclosure Group URI provided: $EnclosureGroup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                       
                        $VcMigrationObject.enclosureGroupUri = $EnclosureGroup

                    }

                    # The value is an enclosure group name
                    else 
                    {
                        
                        # Enclosure group name provided. Check if this is for a custom EG and LIG (LIG name also provided), or existing EG
                        "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Enclosure Group Name provided: $EnclosureGroup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        try 
                        { 
                            
                            $eg = (Get-HPOVEnclosureGroup -Name $EnclosureGroup -ErrorAction Stop -appliance $ApplianceConnection).uri 
                                
                            # Add the URI property to the migration object
                            $VcMigrationObject.enclosureGroupUri = $eg
                                
                        }

                        catch 
                        {

                            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Enclosure Group '$EnclosureGroup' not found. Specifying custom Enclosure Group Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $VcMigrationObject | Add-Member -NotePropertyName "enclosureGroupName" -NotePropertyValue $EnclosureGroup -force

                        }

                    }
                    
                }

                "PSCustomObject" 
                {
            
                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Enclosure Group resource object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup.name, $EnclosureGroup.uri | Write-Verbose
                    $VcMigrationObject.enclosureGroupUri = $EnclosureGroup.uri
            
                }

            }# SWITCH

        }# If EG provided

        # Check to see if LogicalInterconnectGroup was provided
        if ($PSBoundParameters['LogicalInterconnectGroup']) 
        {
        
            switch ($LogicalInterconnectGroup.Gettype().Name) 
            {

                # Validate the String value
                "String" 
                { 
                
                    # The value is an Enclosure Group URI
                    if ($LogicalInterconnectGroup.startswith('/rest/logical-interconnect-groups')) 
                    {

                        "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Logical Interconnect Group URI provided: $LogicalInterconnectGroup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        $VcMigrationObject.logicalInterconnectGroupUri = $LogicalInterconnectGroup

                    }

                    # The value is an Logical Interconnect group name
                    else 
                    {
                        
                        # Enclosure group name provided. Check if this is for a custom EG and LIG (LIG name also provided), or existing EG
                        "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Logical Interconnect Group Name provided: $LogicalInterconnectGroup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        try 
                        { 
                            
                            $lig = (Get-HPOVLogicalInterconnectGroup -Name $LogicalInterconnectGroup -ErrorAction Stop -appliance $ApplianceConnection).uri 
                                
                            # Add the URI property to the migration object
                            $VcMigrationObject.logicalInterconnectGroupUri = $lig
                                
                        }

                        catch 
                        {

                            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Logical Interconnect Group '$LogicalInterconnectGroup' not found. Specifying custom Logical Interconnect Group Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $VcMigrationObject | Add-Member -NotePropertyName logicalInterconnectGroupName -NotePropertyValue $LogicalInterconnectGroup -force

                        }

                    }
                    
                }

                "PSCustomObject" 
                {
            
                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Logical Interconnect Group resource object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnectGroup.name, $LogicalInterconnectGroup.uri | Write-Verbose
                    $VcMigrationObject.logicalInterconnectGroupUri  = $LogicalInterconnectGroup.uri
            
                }

            }# SWITCH

        }# If EG provided

        # Send the POST and retrieve the Uri for the MigratableVcDomain resource

        Try
        {

            $thisTask = Send-HPOVRequest -method POST -uri $VCMigratorUri -body $VcMigrationObject -appliance $ApplianceConnection | Wait-HPOVTaskComplete

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        if ($thisTask.taskState -ieq "Error") 
        {

            $ErrorRecord = New-ErrorRecord HPOneView.EnclosureResourceException $thisTask.taskErrors.errorCode InvalidArgument 'Invoke-HPOVVcMigration' -Message "$($thisTask.taskErrors.message)"
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # If we get here, task was successful. Get the migration resource
        $vcMigrationReport = MigrationReport $thisTask

        $EnclosureName = $vcMigrationReport.apiVcMigrationReport.enclosureName

        if ($Path) 
        {

            [Array]$Output = @()

            $Output += $vcMigrationReport.apiVcMigrationReport | Format-Table $a -AutoSize -wrap
            $Output += $vcMigrationReport.apiVcMigrationReport| Format-Table $b -AutoSize -wrap
            $Output += $vcMigrationReport.outReport | Sort-Object severity | Format-List $i

            $outFile = "$Path\$($vcMigrationReport.apiVcMigrationReport.enclosureName)_$(get-date -uformat %Y%m%d).report"

            $vcMigrationReport.outReport += "Generated on $(get-date -uformat %c)"

            Out-File -InputObject $Output -FilePath $outFile -Encoding utf8 -force -confirm:$false

            write-host "Report saved to: " -nonewline -ForegroundColor Green
            write-host "$outFile" -ForegroundColor Yellow

        }

        else 
        {

            # Generate and return the report
            ""
            "Migration Compatibility Report"
            "------------------------------"
            ""
            $vcMigrationReport.apiVcMigrationReport | Format-Table $a -AutoSize -wrap
            $vcMigrationReport.apiVcMigrationReport| Format-Table $b -AutoSize -wrap
            $vcMigrationReport.outReport | Sort-Object severity | Format-List $i

        }

        # Generate terminating error if caller didn't include VCEMCMS Parameter and $vcMigrationReport.VcemManaged is True
        if (-not ($PSBoundParameters["vcemcms"]) -and $vcMigrationReport.VcemManaged) 
        {

            $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VCEMCMSParameterMissing InvalidArgument 'VCEMCMS' -Message "The Enclosure is currently managed by a Virtual Connect Enterprise Manager (VCEM) CMS, and the -VCEMCMS Parameter was not provided. Please provide the required Parameter and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
        }
        
        # $_ServicePointManagerOriginalState = [System.Net.ServicePointManager]::ServerCertificateValidationCallback # Workaround self-signed certificates on OA and VCEM CMS
        # [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

        if ($VCEMCMS -and $vcMigrationReport.VcemManaged -and ($vcMigrationReport.apiVcMigrationReport.criticalCount -le 1) -and (-not ($Report.IsPresent))) 
        {

            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Entering Eject VCM from VCEM DG Process" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
       
            $oaUrl = "https://{0}/xmldata?item=all" -f $OAIPAddress

            '[{0}] {1} - Building SOAP Request to OA: {2}' -f $MyInvocation.InvocationName.ToString().ToUpper(), (Get-Date -UFormat "%Y-%m-%d %T"), $oaUrl | Write-Verbose

            try 
            {

                $soapWebRequest        = [System.Net.WebRequest]::Create($oaUrl) 
                $soapWebRequest.Accept = "text/xml" 
                $soapWebRequest.Method = "GET" 
                $resp                  = $soapWebRequest.GetResponse() 
                $responseStream        = $resp.GetResponseStream() 
                $soapReader            = [System.IO.StreamReader]($responseStream) 
                $ReturnXml             = [Xml] $soapReader.ReadToEnd() 

                $responseStream.Close() 
                $resp.Close()

                $soapWebRequest = $Null
                
                "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Response received: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $returnXML.OuterXml | Write-Verbose
    
            }

            catch [Net.WebException]
            {

                if ($_.exception.InnerException -match "The remote name could not be resolved") 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException OnboardAdministratorUnavailable ResourceUnavailable 'OAIP' -Message "$($_.exception.InnerException)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException $_.FullyQualifiedErrorId ResourceUnavailable 'OAIP' -Message "$($_.exception.message)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                }

            }

            catch 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException $_.FullyQualifiedErrorId ResourceUnavailable 'OAIP' -Message "$($_.exception.message)"
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Received valid OA XML reply
            if ($ReturnXml.RIMP.INFRA2) 
            { 
    
                if ($ReturnXml.RIMP.INFRA2.VCM.vcmMode -eq "true") 
                {
            
                    $vcDomainName = $ReturnXml.RIMP.INFRA2.VCM.vcmDomainName
                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Found VC Domain from OA: '$vcDomainName'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException NoVCDomainFound ResourceUnavailable 'OAIP' -Message "Enclosure is not managed by VCM or no valid VC Domain Found."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
    
            }
    
            # Reply will not have any returned data beyond the RIMP XML node, so generate error
            else 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException NoVCDomainFound ResourceUnavailable 'OAIP' -Message "No data provided from XML Interface. Is it disabled?"
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # VCEM CodeBlock
            # Use the mvcd7_3 API Endpoint
            $XmlAuth = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v7="http://v7_3.api.mvcd.hp.com">
                            <soapenv:Header/>
                            <soapenv:Body>
                                <v7:login>
                                    <String_1>{0}</String_1>
                                    <String_2>{1}</String_2>
                                </v7:login>
                            </soapenv:Body>
                        </soapenv:Envelope>'
 -f $VCEMUser, $_VCEMPassword
            
            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") $(get-date -UFormat `"%Y-%m-%d %T`") Authenticating to VCEM CMS host: $VCEMCMS." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            try 
            {

                $Uri = "https://$($VCEMCMS):50000/mvcd7_3/SoapApi"
                $reply = Invoke-WebRequest -uri $Uri -Method POST -ContentType "text/xml" -Body $XmlAuth

            }

            catch [System.Net.WebException] 
            {

                if ($_.exception -match "The remote name could not be resolved") 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VcemHostUnavailable ResourceUnavailable 'VCEMCMS' -Message "The VCEM host '$VCEMCMS' remote name could not be resolved. Please check the name and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)    

                }
                
                else 
                { 

                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") [System.Net.WebException] Error Caught: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.Response | Write-Verbose

                    $ResponseCode = [Int]$_.Exception.response.statuscode
                    $ResponseMessage = $_.Exception.Message

                    # Get exception response from Web Service API.
                    if ($_.Exception.InnerException) { $HttpWebResponse = $_.Exception.InnerException.Response }
                    else { $HttpWebResponse = $_.Exception.Response }

                    $rs = $HttpWebResponse.GetResponseStream()
                    $reader = New-Object System.IO.StreamReader($rs)
                    
                    if ($HttpWebResponse.ContentType.Contains("text/xml")) { [XML]$ErrorBodyResponse = $reader.ReadToEnd() }
                    else { $ErrorBodyResponse = $reader.ReadToEnd() }

                    switch ([Int]$ResponseCode) 
                    {
                    
                        404 
                        {  

                            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") [System.Net.WebException] SOAP API Endpoint not found" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                            $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VCEMSoapAPIEndPointNotFound ResourceUnavailable 'VCEMCMS' -Message "The provided VCEM CMS host '$VCEMCMS' does not have the VCEM role of HP Insight Software installed. Please verify the VCEMCMS Parameter value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                        }

                        default 
                        {

                            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") [System.Net.WebException] Internal Server Error or auth exception" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            if ($ErrorBodyResponse -is [XML]) 
                            {

                                $ResponseMessage = $ErrorBodyResponse.Envelope.body.Fault.faultstring

                                "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Received XML Response FaultString: $ResponseMessage" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            }              
                            
                            $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VCEMSoapApiInternalError InvalidResult 'VCEMCMS' -Message "HTTP '$ResponseCode' Error. $ResponseMessage"
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                }

            }

            [XML]$ContentResponse = $reply.content
            $AuthToken = $ContentResponse.Envelope.Body.loginResponse.result

            # Check for new VCEM API Endpoint
            $getVcemApiVersion = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v7="http://v7_3.api.mvcd.hp.com">
                                    <soapenv:Header/>
                                    <soapenv:Body>
                                        <v7:getProductVersion>
                                            <String_1>{0}</String_1>
                                        </v7:getProductVersion>
                                    </soapenv:Body>
                                  </soapenv:Envelope>'
-f $AuthToken

            $Uri = "https://$($VCEMCMS):50000/mvcd7_3/SoapApi"

            Try
            {

                $reply = Invoke-WebRequest -uri $Uri -Method POST -ContentType "text/xml" -Body $getVcemApiVersion

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            [XML]$ContentResponse = $reply.content
            
            [version]$apiVersion = ($ContentResponse.Envelope.Body.getProductVersionResponse.result) -replace ("Virtual Connect Enterprise Manager v","")
            $apiVersionString = ($ContentResponse.Envelope.Body.getProductVersionResponse.result) -replace ("Virtual Connect Enterprise Manager v","") -replace ("\.","_")

            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") VCEM API Version found: $apiVersion" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose


            if ($apiVersion -lt 7.3) 
            {

                # Generate error that VCEM version is too old to support patch and instruct caller to upgrade to either 7.3+Patch or 7.4.1
                $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VcemVersionTooOld ResourceUnavailable 'VCEMCMS' -Message "The VCEM host '$VCEMCMS' version '$($apiVersion.ToString())' is not supported. Please upgrade your VCEM CMS to at least 7.3 and obtain the VCEM 7.3/7.4 Patch (ftp://ftp.hp.com/pub/softlib2/software1/pubsw-generic/p270829882/v106568) and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Locate VCM Domain within VCEM
            $FindVCDomainByNameRequest = '<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
                                            <s11:Body>
                                                <ns1:findVCDomainByName xmlns:ns1="http://v7_3.api.mvcd.hp.com">
                                                <String_1>{0}</String_1>
                                                <String_2>{1}</String_2>
                                                </ns1:findVCDomainByName>
                                            </s11:Body>
                                          </s11:Envelope>'
 -f $AuthToken, $VCDomainName

            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Looking for '$vcDomainName' VC Domain on VCEM host." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $reply = Invoke-WebRequest -uri $Uri -Method POST -ContentType "text/xml" -Body $FindVCDomainByNameRequest

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [xml]$findVCDomainByNameResponse = $reply.content

            if ($findVCDomainByNameResponse.Envelope.body.findVCDomainByNameResponse.result.nil) 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException NoVCDomainFound ResourceUnavailable 'OAIP' -Message "No data provided from XML Interface. Is it disabled?"
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Found VC Domain: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $findVCDomainByNameResponse.Envelope.body.findVCDomainByNameResponse.result | Write-Verbose

            if ($findVCDomainByNameResponse.Envelope.body.findVCDomainByNameResponse.result.status -eq "LICENSED_UNMANAGED") 
            {

                Write-Warning "'$vcDomainName' is not currently managed by the VCEM CMS host."
                Return

            }

            $vcemDomainId = $findVCDomainByNameResponse.Envelope.body.findVCDomainByNameResponse.result.vcDomainId

            "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Attempting to remove VC Domain from VCEM Domain Group" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($PSCmdlet.ShouldProcess($vcDomainName,"Remove VC Domain From VC Domain Group")) 
            {

                if ($apiVersion -ge "7.4.1") 
                { 
                
                    $uri = "https://$($VCEMCMS):50000/mvcd$($apiVersionString)/SoapApi" 
                    $nameSpaceVer = "v$($apiVersionString)"
                }

                else 
                { 
                
                    $uri = "https://$($VCEMCMS):50000/mvcdExtra/SoapApi" 
                    $nameSpaceVer = "vExtra"
                        
                }

                $removeVcDomainRequest = '<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
                                            <s11:Body>
                                            <ns1:removeVcDomainFromGroup xmlns:ns1="http://$nameSpaceVer.api.mvcd.hp.com">
                                                <String_1>{0}</String_1>
                                                <Long_2>{1}</Long_2>
                                            </ns1:removeVcDomainFromGroup>
                                            </s11:Body>
                                        </s11:Envelope>'
 -f $AuthToken, $vcemDomainId

                # Attempt removeVcDomainFromGroup request to API
                try 
                {

                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Attempting SOAP Call to '$uri'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $soapWebRequest               = [System.Net.HttpWebRequest]::Create($uri) 
                    $soapWebRequest.Accept        = "text/xml" 
                    $soapWebRequest.ContentType   = "text/xml"
                    $soapWebRequest.Method        = "POST" 
                    $bytes                        = [System.Text.Encoding]::UTF8.GetBytes($removeVcDomainRequest) 
                    $soapWebRequest.ContentLength = $bytes.Length

                    [System.IO.Stream] $outputStream = [System.IO.Stream]$soapWebRequest.GetRequestStream()
                    $outputStream.Write($bytes,0,$bytes.Length)  
                    $outputStream.Close()

                    $resp           = $soapWebRequest.GetResponse() 
                    $responseStream = $resp.GetResponseStream() 
                    $soapReader     = [System.IO.StreamReader]($responseStream) 
                    $reply          = [Xml]$soapReader.ReadToEnd() 
                    $responseStream.Close() 
                    $resp.Close()
                    $soapWebRequest = $Null
                    
                    "[{0}] {1} Response received: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (get-date -UFormat "%Y-%m-%d %T"), $reply.OuterXml | Write-Verbose 
    
                }

                Catch [System.Net.WebException] 
                {

                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") [System.Net.WebException] exception caught: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.Response | Write-Verbose

                    $HttpWebResponse = $_.Exception.Response
                    $ResponseCode = [Int]$_.Exception.response.statuscode
                    $ResponseMessage = $_.Exception.Message

                    "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Getting error response stream." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $rs = $HttpWebResponse.GetResponseStream()
                    $reader = New-Object System.IO.StreamReader($rs)

                    if ($HttpWebResponse.ContentType.Contains("text/xml")) { [XML]$ErrorBodyResponse = $reader.ReadToEnd() }

                    else { [String]$ErrorBodyResponse = $reader.ReadToEnd() }

                    if ($ErrorBodyResponse -is [String] -and $ErrorBodyResponse.StartsWith("<script>") -and [Int]$ResponseCode -eq 404) 
                    { 
                    
                        "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") [System.Net.WebException] SOAP API Endpoint not found. Generating terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                        $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VCEMSoapAPIEndPointNotFound ResourceUnavailable 'VCEMCMS' -Message "The provided VCEM CMS host '$VCEMCMS' does not have the required VCEM patch installed. Please download the patch from (ftp://ftp.hp.com/pub/softlib2/software1/pubsw-generic/p270829882/v106568) and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($ErrorBodyResponse -is [XML] -and [Int]$HttpWebResponse.StatusCode -eq 500 -and $ErrorBodyResponse.Envelope.Body.Fault.faultstring -match "Failed to parse source: For input string: `"$vcemDomainId`"") 
                    {

                        "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") '$vcDomainName' was not found on the VCEM host '$VCEMCMS'. Generating terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VcDomainNotFound ResourceUnavailable 'VCEMCMS' -Message "The Virtual Connect Domain '$vcDomainName' not found on VCEM host '$VCEMCMS'. Please verify the Virtual Connect Domain is managed by the provided VCEM CMS host and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($ErrorBodyResponse -is [XML]) 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException $ErrorBodyResponse.Envelope.Body.Fault.faultcode InvalidResult 'VCEMCMS' -Message "$($ErrorBodyResponse.Envelope.Body.Fault.faultstring)"
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException VCEMApiCallGenericError InvalidResult 'VCEMCMS' -Message "HTTP '$ResponseCode ' Error. Message: $ResponseMessage"
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                }

                $jobId = $reply.Envelope.body.removeVcDomainFromGroupResponse.result

                if (-not ($jobId))
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.VCMigratorException InvalidJobIdResult InvalidResult 'VCEMCMS' -Message "A valid VCEM Job ID was not provided."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                }

                "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Monitoring VCEM Job ID '$jobId'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $Uri = "https://$($VCEMCMS):50000/mvcd7_3/SoapApi"

                $jobMonitorRequest = '<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
                                        <s11:Body>
                                            <ns1:listStatusForMvcdJob xmlns:ns1="http://v7_3.api.mvcd.hp.com">
                                            <String_1>{0}</String_1>
                                            <Long_2>{1}</Long_2>
                                            </ns1:listStatusForMvcdJob>
                                        </s11:Body>
                                      </s11:Envelope>'
 -f $AuthToken, $jobId

                do 
                {

                    # Hide the progress display of Invoke-WebRequest, which adds unecessary tet to the Write-Progress output
                    $progressPreference = 'silentlyContinue' 
                    $reply = Invoke-WebRequest -uri $Uri -Method POST -ContentType "text/xml" -Body $jobMonitorRequest

                    # Reset hidding progress display prior to executing Write-Progress
                    $progressPreference = 'Continue'  

                    [xml]$jobStatus = $reply.Content

                    Write-Verbose $($jobStatus.Envelope.body.listStatusForMvcdJobResponse.result | out-string)
                    Write-Verbose $($jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobProgress[-1] | out-string)

                    if ($jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobProgress[-1].progressDescription) { $status = $jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobProgress[-1].progressDescription}
                    else { $status = "Waiting" }

                    if ($jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobProgress[-1].percentComplete) { $PrecentComplete = $jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobProgress[-1].percentComplete}
                    else { $PrecentComplete = 0 }

                    Write-Progress -id 2 -Activity $jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobName -Status $status -PercentComplete $PrecentComplete

                } Until ($jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.state -eq "COMPLETED" -or $jobStatus.Envelope.body.listStatusForMvcdJobResponse.result -eq "FAILED")
    
                
                # [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $_ServicePointManagerOriginalState # Restore certificate validation

                #Job Failed, terminate
                if ($jobStatus.Envelope.body.listStatusForMvcdJobResponse.result -eq "FAILED") 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.VCMigratorException $thisTask.taskErrors.errorCode InvalidArgument 'Invoke-HPOVVcMigration' -Message "$($thisTask.taskErrors.message)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }           
                
                Write-Progress -id 2 -Activity $jobStatus.Envelope.body.listStatusForMvcdJobResponse.result.jobName -Completed

                "[{0}] $(get-date -UFormat `"%Y-%m-%d %T`") Checking Compatibility again." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Check for report status now
                Try
                {

                    $thisTask = Send-HPOVRequest -method POST -uri $VCMigratorUri -body $VcMigrationObject -appliance $ApplianceConnection | Wait-HPOVTaskComplete

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

                if ($thisTask.taskState -ieq "Error") 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.VCMigratorException $thisTask.taskErrors.errorCode InvalidResult 'Invoke-HPOVVcMigration' -Message "$($thisTask.taskErrors.message)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # If we get here, task was successful. Generate new VCMMigrator report
                $vcMigrationReport = MigrationReport $thisTask

                if ($vcMigrationReport.apiVcMigrationReport.migrationState -eq "UnableToMigrate") 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.VCMigratorException UnableToMigrateVCDomain InvalidResult 'Invoke-HPOVVcMigration' -Message "The VC Domain in unable to be migrated due to $($vcMigrationReport.apiVcMigrationReport.highCount) Critical Issues. Please examine the VC Migration Report to identify what needs to be resolved before migration can continue."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Generate and return the report
                ""
                "Migration Compatibility Report"
                "------------------------------"
                ""
                $vcMigrationReport.apiVcMigrationReport | Format-Table $a -AutoSize -wrap
                $vcMigrationReport.apiVcMigrationReport| Format-Table $b -AutoSize -wrap
                $vcMigrationReport.outReport | Sort-Object severity | Format-List $i

            }

            Else 
            {

                if ($PSBoundParameters['whatif'].ispresent) 
                { 
                            
                    write-warning "-WhatIf was passed, would have proceeded with removing '$vcDomainName' from VCEM Domain Group."
                    $resp = $null
            
                }
                else 
                {

                    # If here, user chose "No", End Processing
                    write-host ""
                    write-warning "Not removing '$vcDomainName'from VCEM Domain Group and unable to proceed without removing the VC Domain from the VCEM Domain Group."
                    write-host ""
                    
                    $resp = $Null

                }

            }

        }

        # We are ready to migrate
        if ($vcMigrationReport.migrationState -eq "ReadyToMigrate" -and -not ($report.IsPresent)) 
        {
            
            if ($PSCmdlet.ShouldProcess("enclosure $EnclosureName at $($vcMigrationReport.apiVcMigrationReport.enclosureIp)","Process migration")) 
            {
                
                Try
                {

                    # Make the PUT call to migrate
                    $migrateTask = Send-HPOVRequest -method PUT -uri $vcMigrationReport.apiVcMigrationReport.uri -body @{acknowledgements = $vcMigrationReport.apiVcMigrationReport.acknowledgements; migrationState = "Migrated"; type = "MigratableVcDomainV300"}  -appliance $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                

                if (-Not($PSBoundParameters['Async']))
                {

                    $migrateTask = $migrateTask | Wait-HPOVTaskComplete -timeout (New-TimeSpan -Minutes 60)

                }

            }

            else 
            {

                if ($PSBoundParameters['whatif'].ispresent) 
                { 
                            
                    write-warning "-WhatIf was passed, would have proceeded with migration of $($vcMigrationReport.apiVcMigrationReport.enclosureName)."
                    $migrateTask = $null
            
                }

                else 
                {

                    # If here, user chose "No", End Processing
                    write-host ""
                    write-warning "Not migrating enclosure, $($vcMigrationReport.apiVcMigrationReport.enclosureName)."
                    write-host ""
                    
                    $migrateTask = $Null

                }

            }

        }# End if ReadyToMigrate

        # Handle error conditions that need to be resolved by the caller before migration can be performed.
        elseif ($vcMigrationReport.migrationState -eq "UnableToMigrate" -and $vcMigrationReport.apiVcMigrationReport.criticalCount -ge 1) 
        {
        
            $ErrorRecord = New-ErrorRecord HPOneView.VCMigratorException UnableToMigrateEnclosure InvalidResult 'Invoke-HPOVVcMigration' -Message "There are 1 or more critical issues preventing the enclosure from being eligible to migrate. Please run a compatibility report using the -report switch, then review and resolve the reported issues before continuing."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($vcMigrationReport.migrationState -eq "Migrated") 
        {
        
            $ErrorRecord = New-ErrorRecord HPOneView.VCMigratorException EnclosureMigrated OperationStopped 'OAIP' -Message "The enclosure '$EnclosureName' was already migrated. Not performing action again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($vcMigrationReport.migrationState -eq "Migrating") 
        {
        
            $ErrorRecord = New-ErrorRecord HPOneView.VCMigratorException MigratingEnclosure InvalidOperation 'OAIP' -Message "An asynchronOut task migrating enclosure '$EnclosureName' exists and is currently still running."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
           
    }# End Process
    
    End 
    {
         
        Return $migrateTask

    }

}

function MigrationReport
{

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory)]
        [Object]$task

    )

    Process
    {

        $vcMigrationReport = NewObject -VCMigratorReport

        Try
        {

            $vcMigrationReport.apiVcMigrationReport = Send-HPOVRequest $task.associatedResource.resourceUri

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $vcMigrationReport.migrationState = $vcMigrationReport.apiVcMigrationReport.migrationState

        $vcMigrationReport.issueCount = $vcMigrationReport.apiVcMigrationReport.highCount + $vcMigrationReport.apiVcMigrationReport.mediumCount + $vcMigrationReport.apiVcMigrationReport.lowCount
        
        if ($vcMigrationReport.migrationState -eq "UnableToMigrate" -or $vcMigrationReport.issueCount -gt 0) 
        {
            
            foreach ($itemCategory in $vcMigrationReport.apiVcMigrationReport.items) 
            {
            
                foreach ($issue in $itemCategory.issues) 
                {
            
                    $issue | ForEach-Object { 

                        if ($_.description -match "The specified enclosure is managed by Virtual Connect Enterprise Manager") 
                        {

                            Write-Warning "Enclosure is currently managed by Virtual Connect Enterprise Manager."
                                
                            $vcMigrationReport.VcemManaged = $True
                        
                        }

                        $_ | add-member -NotePropertyName name -NotePropertyValue $itemCategory.name -force 
                        $_ | add-member -NotePropertyName resourceName -NotePropertyValue $_.name -force 
                        
                        [void]$vcMigrationReport.outReport.Add($_)
                        
                    }
            
                }
            
                foreach ($item in $itemCategory.items) 
                { 
            
                    $items = $item | Where-Object severity -notmatch "OK"

                    $items | ForEach-Object { 
            
                        $_.issues | add-member -NotePropertyName name -NotePropertyValue $itemCategory.name -force 
                        $_.issues | add-member -NotePropertyName resourceName -NotePropertyValue $_.name -force 

                        [void]$vcMigrationReport.outReport.Add($_.issues)
            
                    }
                
                }
            
            }

        }

    }

    End
    {

        Return $vcMigrationReport

    }

}

function Get-HPOVEnclosure 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
  
    [CmdletBinding (DefaultParameterSetName = "default")]    
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "export")]
        [Parameter (Mandatory = $false, ParameterSetName = "report")]
        [validateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "export")]
        [Parameter (Mandatory = $false, ParameterSetName = "report")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "export")]
        [Parameter (Mandatory = $false, ParameterSetName = "report")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "export" )]
        [Parameter (Mandatory = $false, ParameterSetName = "report")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "export")]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$exportFile,
            
        [Parameter (Mandatory = $false, ParameterSetName = "report")]
        [Switch]$Report

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_EnclosureCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            # Build the final URI
            $_uri = '{0}?category=enclosures&sort=name:asc&query={1}' -f $IndexUri, [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
            { 
    
                "[{0}] Enclosure '{1}' resource not found. Generating error" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose 

                $ExceptionMessage = "The specified Enclosure '{0}' was not found on '{1}' appliance. Please check the name and try again." -f $Name, $_appliance.Name 
                $ErrorRecord = New-ErrorRecord InvalidOperationException EnclosureGroupNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)  
                
            }
    
            elseif ($_ResourcesFromIndexCol.count -eq 0) 
            { 
    
                "[{0}] No Enclosure resources found on {1}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.name | Write-Verbose 
    
            }

            ForEach ($_member in $_ResourcesFromIndexCol)
            {

                "[{0}] Adding Enclosure resource '{1}' to collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.name | Write-Verbose 

                $_member.PSObject.TypeNames.Insert(0,'HPOneView.Servers.Enclosure')    
    
                [void]$_EnclosureCollection.Add($_member) 

            }

        }

    }

    End 
    {
                
        "[{0}] Done. {1} enclosure(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_EnclosureCollection.count | Write-Verbose 
                
        # Display a report of an enclsosure
        if ($Report) 
        { 
            
            $_EnclosureCollection | ForEach-Object { Enclosure-Report $_ } 
        
        }
        
        # Display the JSON body of the enclosure
        elseif ($exportFile) 
        { 
            
            $_EnclosureCollection | convertto-json -depth 99 > $exportFile 
        
        }
        
        # else Return enclosure object
        else 
        { 

            "[{0}] Return collection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

            Return $_EnclosureCollection
        
        }

    }

}

function Reset-HPOVEnclosureDevice
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ManagerOrDeviceBay")]
        [ValidateNotNullOrEmpty()]
        [Object]$Enclosure,

        [Parameter (ParameterSetName = "default", Mandatory)]
        [Parameter (ParameterSetName = "ManagerOrDeviceBay", Mandatory)]
        [ValidateNotNullorEmpty()]
        [ValidateSet ('FLM','Appliance','ICM','Device')]
        [String]$Component,

        [Parameter (ParameterSetName = "default", Mandatory)]
        [Parameter (ParameterSetName = "ManagerOrDeviceBay", Mandatory)]
        [ValidateNotNullorEmpty()]
        [Int]$DeviceID,

        [Parameter (ParameterSetName = 'ManagerOrDeviceBay', Mandatory)]
        [Switch]$Reset,

        [Parameter (ParameterSetName = 'default', Mandatory = $False)]
        [Switch]$Efuse,

        [Parameter (ParameterSetName = 'default', Mandatory = $False)]
        [Parameter (ParameterSetName = 'ManagerOrDeviceBay', Mandatory = $False)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "ManagerOrDeviceBay")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        if (-not($PSBoundParameters['Enclosure'])) 
        { 
        
            $PipelineInput = $True 
            
        }

        else
        {

            if ($Enclosure -isnot [PSCustomObject])
            {

                $_Message = 'An invalid Enclosure object type was provided, {0}. This Cmdlet only support PSObject types from Get-HPOVEnclosure. Please check the value and try agin.'
                $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidObjectType InvalidArgument 'Enclosure' -TargetType $Enclosure.Gettype().Name -Message $_Message
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection      = [System.Collections.ArrayList]::new()
        $_EnclosureCollection = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        if ($Enclosure -isnot [PSCustomObject] -and $Enclosure.category -ne 'enclosures')
        {

            $_Message = 'An invalid Enclosure object type was provided, {0}. This Cmdlet only support PSObject types from Get-HPOVEnclosure. Please check the value and try agin.' -f $Enclosure.Gettype().Name
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidObjectType InvalidArgument 'Enclosure' -TargetType $Enclosure.Gettype().Name -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not($Enclosure.ApplianceConnection))
        {

            $_Message = 'The provided Enclosure resource object is missing the ApplianceConnection property. This Cmdlet only support PSObject types from Get-HPOVEnclosure. Please check the value and try agin.'
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidObjectType InvalidArgument 'Enclosure' -TargetType $Enclosure.Gettype().Name -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_Operation       = NewObject -PatchOperation
        $_Operation.op    = 'replace'
        $_Operation.value = 'E-Fuse'

        switch ($Component)
        {

            'FLM'
            {

                $_Operation.path = '/managerBays/{0}/bayPowerState' -f $DeviceID

                if ($PSBoundParameters['Reset'])
                {

                    $_Operation.value = 'Reset'

                }

            }

            'Device'
            {
                
                $_Operation.path = '/deviceBays/{0}/bayPowerState' -f $DeviceID

                if ($PSBoundParameters['Reset'])
                {

                    $_Operation.value = 'Reset'

                }

            }

            'ICM'
            {

                $_Operation.path = '/interconnectBays/{0}/bayPowerState' -f $DeviceID

            }

            'Appliance'
            {

                $_Operation.path = '/applianceBays/{0}/bayPowerState' -f $DeviceID

            }
        
        }

        "[{0}] Power Operation: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Operation | Out-String) | Write-Verbose

        if ($PSCmdlet.ShouldProcess(('{0} {1} within {2}' -f $Component, $DeviceID, $Enclosure.name),'Reset power for device'))
        {

            Try
            {

                $_resp = Send-HPOVRequest -Uri $Enclosure.Uri -Method PATCH -Body $_Operation -AddHeader @{'If-Match' = $Enclosure.eTag} -Hostname $Enclosure.ApplianceConnection | Wait-HPOVTaskStart

                if (-not($PSBoundParameters['Async']))
                {

                    $_resp = Wait-HPOVTaskComplete $_resp

                }

                [Void]$_TaskCollection.Add($_resp)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        elseif ($PSCmdlet.PSBoun['WhatIf'])
        {

            "[{0}] WhatIf operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] User cancelled operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        Return $_TaskCollection

    }

}

function Set-HPOVEnclosureActiveFLM
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess,ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [object]$Enclosure,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Int]$BayID,

        [Parameter (Mandatory = $false)]
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        if (-not($PSBoundParameters['Enclosure'])) 
        { 
        
            $PipelineInput = $True 
            
        }

        else
        {

            if ($Enclosure -isnot [PSCustomObject])
            {

                $_Message = 'An invalid Enclosure object type was provided, {0}. This Cmdlet only support PSObject types from Get-HPOVEnclosure. Please check the value and try agin.'
                $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidObjectType InvalidArgument 'Enclosure' -TargetType $Enclosure.Gettype().Name -Message $_Message
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }


        $_TaskCollection      = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        if ($Enclosure -isnot [PSCustomObject] -and $Enclosure.category -ne 'enclosures')
        {

            $_Message = 'An invalid Enclosure object type was provided, {0}. This Cmdlet only support PSObject types from Get-HPOVEnclosure. Please check the value and try agin.' -f $Enclosure.Gettype().Name
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidObjectType InvalidArgument 'Enclosure' -TargetType $Enclosure.Gettype().Name -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not($Enclosure.ApplianceConnection))
        {

            $_Message = 'The provided Enclosure resource object is missing the ApplianceConnection property. This Cmdlet only support PSObject types from Get-HPOVEnclosure. Please check the value and try agin.'
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidObjectType InvalidArgument 'Enclosure' -TargetType $Enclosure.Gettype().Name -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_Operation = NewObject -PatchOperation
        $_Operation.op    = 'replace'
        $_Operation.path  = '/managerBays/{0}/role' -f $BayID
        $_Operation.value = 'Active'
                
        "[{0}] Requesting to Activate FLM in Bay {1} within {2} Enclosure" -f $MyInvocation.InvocationName.ToString().ToUpper(), $BayID, $Enclosure.name | Write-Verbose
        
        if ($PSCmdlet.ShouldProcess(('FLM Bay {0} within {1} Enclosure' -f $BayID, $Enclosure.name),'Change FLM State to Active'))
        {

            Try
            {

                $_resp = Send-HPOVRequest $Enclosure.Uri PATCH $_Operation -Hostname $Enclosure.ApplianceConnection | Wait-HPOVTaskStart

                if (-not($PSBoundParameters['Async']))
                {

                    $_resp = Wait-HPOVTaskComplete $_resp

                }

                [Void]$_TaskCollection.Add($_resp)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        elseif ($PSCmdlet.PSBoun['WhatIf'])
        {

            "[{0}] WhatIf operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else
        {

            "[{0}] User cancelled operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        Return $_TaskCollection

    }

}

function Set-HPOVEnclosure
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias('Enclosure', 'Encl')]
        [object]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$RackName,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        # Support ApplianceConnection property value via pipeline from Enclosure Object
        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_RequestCollection = [System.Collections.ArrayList]::new()
        $_TaskCollection    = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        "[{0}] Processing Enclosure: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        if ($InputObject.enclosureModel -notmatch 'Synergy' -and ($PSBoundParameters['Name'] -or $PSBoundParameters['RackName']))
        {

            $ExceptionMessage = 'The InputObject {0} is not a supported resource to set the Enclosure Name. For C-Class, you must update the Enclosure or Rack Name within the Onboard Administrator.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        elseif ($PSBoundParameters['Name'])
        {

            "[{0}] Setting Enclosure Name to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

            $_PatchRequest = NewObject -PatchOperation

            $_PatchRequest.op = 'replace'
            $_PatchRequest.path  = '/name'
            $_PatchRequest.value = $Name

            [void]$_RequestCollection.Add($_PatchRequest)

            Try
            {

                $_resp = Send-HPOVRequest $InputObject.uri PATCH $_RequestCollection -AddHeader @{'If-Match' = $InputObject.eTag} -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }    
                
        if ($PSBoundParameters['RackName'])
        {

            "[{0}] Setting Enclosure RackName to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $RackName | Write-Verbose

            if ($PSBoundParameters['Name'])
            {

                Try
                {

                    $_resp = Wait-HPOVTaskComplete -InputObject $_resp

                    [void]$_TaskCollection.Add($_resp)

                    "[{0}] Getting updated object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $InputObject = Send-HPOVRequest -Uri $InputObject.uri -Hostname $InputObject.ApplianceConnection

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
            
            }

            $_RequestCollection = [System.Collections.ArrayList]::new()

            $_PatchRequest = NewObject -PatchOperation

            $_PatchRequest.op = 'replace'
            $_PatchRequest.path  = '/rackName'
            $_PatchRequest.value = $RackName

            [void]$_RequestCollection.Add($_PatchRequest)

            Try
            {

                $_resp = Send-HPOVRequest $InputObject.uri PATCH $_RequestCollection -AddHeader @{'If-Match' = $InputObject.eTag} -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        [void]$_TaskCollection.Add($_resp)

    }

    End
    {

        Return $_TaskCollection

    }

}

function Start-HPOVEnclosureAppliance
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("Encl")]
        [Object]$Enclosure,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateRange(1,2)]
        [Int]$BayID,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        if (-not($PSBoundParameters['Enclosure'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            if ($Enclosure -isnot [PSCustomObject] -or ($Enclosure -is [PSCustomObject] -and $Enclosure.category -ne 'enclosures') -or ($Enclosure.model -notmatch 'Synergy'))
            {

                $Message = '{0} is an unsupported resource object ({1}). This Cmdlet only supports Synergy Frame resource objects.' -f $Enclosure.name, $Enclosure.category
                $ErrorRecord = New-ErrorRecord HPOneview.EnclosureResourceException InvalidResoureObject InvalidArgument 'Enclosure' -Message $Message
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_TaskCollection  = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Processing Enclosure: {0}" -f $Enclosure.name | Write-Verbose

        if ($PipelineInput)
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $Enclosure.ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        Try
        {

            # Validate to make sure the Appliance bay is not already powered on.
            $Enclosure = Send-HPOVRequest $Enclosure.uri -ApplianceConnection $ApplianceConnection

            if (($Enclosure.applianceBays | Where-Object bayNumber -eq $BayID).poweredOn)
            {
            
                'Appliance Bay {0} in {1} Enclosure is already powered on. Not Processing.' -f $BayID, $Enclosure.name | Write-Warning 
            
            }

            else
            {

                'Appliance Bay {0} in {1} Enclosure is already powered off. Processing.' -f $BayID, $Enclosure.name | Write-Verbose

                $_PatchRequest = NewObject -PatchOperation

                $_PatchRequest.path  = '/applianceBays/{0}/power' -f $BayID
                $_PatchRequest.value = 'on'

                $_resp = Send-HPOVRequest $Enclosure.uri PATCH $_PatchRequest -ApplianceConnection $ApplianceConnection

            }

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
                
        [void]$_TaskCollection.Add($_resp)

    }

    End
    {

        Return $_TaskCollection

    }

}

function Get-HPOVComposerNode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory = $False)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ComposerNodeCollection = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($_appliance.ApplianceType -ne 'Composer')
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. This Cmdlet is only supported with Synergy Composers.' -f $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                "[{0}] Processing Appliance Connection {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                Try
                {

                    $_ComposerNodes = Send-HPOVRequest -Uri $ApplianceHANodesUri -Hostname $_appliance

                    $_ComposerNodes.members | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,'HPOneView.ComposerNode')

                        [void]$_ComposerNodeCollection.Add($_)

                    }
                
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }        

        }
        
    }

    End
    {

        Return $_ComposerNodeCollection

    }

}

function Enable-HPOVComposerHANode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $False)]
        [Switch]$Async,

        [Parameter (Mandatory = $False)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ComposerNodeTaskCollection = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance Connection {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            if ($_appliance.ApplianceType -ne 'Composer')
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. This Cmdlet is only supported with Synergy Composers.' -f $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                Try
                {

                    $_ComposerNodes = Send-HPOVRequest -Uri $ApplianceHANodesUri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_StandbyComposer = $_ComposerNodes.members | Where-Object role -eq 'Standby'

                if ($_StandbyComposer)
                {

                    if ($PSCmdlet.ShouldProcess($_StandbyComposer.name,"transition from Standby to Active"))
                    {

                        $_operation       = NewObject -PatchOperation
                        $_operation.op    = 'replace'
                        $_operation.path  = '/role'
                        $_operation.value = 'Standby'

                        Try
                        {

                            $_resp = Send-HPOVRequest $_StandbyComposer.uri PATCH $_operation -Hostname $_appliance -AddHeader @{'If-Match' = $_StandbyComposer.eTag}

                        }
                        
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        if (-not($PSBoundParameters['Async']))
                        {

                            Try
                            {

                                $_resp = Wait-HPOVTaskComplete $_resp

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }                            

                        }

                        [void]$_ComposerNodeTaskCollection.Add($_resp)

                    }

                    elseif ($PSBoundParameters['Whatif'])
                    {

                        "[{0}] -Whatif scenario." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else
                    {

                        "[{0}] User cancelled operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                }

                else
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException NoStandbyComposerFound ObjectNotFound 'Composer' -Message ('No standby Composers were found in {0} ApplianceConnection.' -f $_connection.Name)
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }                

            }

        }
        
    }

    End
    {

        Return $_ComposerNodeTaskCollection

    }

}

function Remove-HPOVStandbyComposerNode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $False)]
        [Switch]$Async,

        [Parameter (Mandatory = $False)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ComposerNodeTaskCollection = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance Connection {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            if ($_appliance.ApplianceType -ne 'Composer')
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. This Cmdlet is only supported with Synergy Composers.' -f $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                Try
                {

                    $_ComposerNodes = Send-HPOVRequest -Uri $ApplianceHANodesUri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_StandbyComposer = $_ComposerNodes.members | Where-Object role -eq 'Standby'

                if ($_StandbyComposer)
                {

                    if ($PSCmdlet.ShouldProcess($_StandbyComposer.name,"Remove Standby from Cluster, factory reset and power off"))
                    {

                        $_operation       = NewObject -PatchOperation
                        $_operation.op    = 'replace'
                        $_operation.path  = '/role'
                        $_operation.value = 'Unused'

                        Try
                        {

                            $_resp = Send-HPOVRequest -Uri $_StandbyComposer.uri -Method PATCH -BOdy $_operation -Hostname $_appliance -AddHeader @{'If-Match' = $_StandbyComposer.eTag}

                        }
                        
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        if (-not($PSBoundParameters['Async']))
                        {

                            Try
                            {

                                $_resp = Wait-HPOVTaskComplete $_resp

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }                            

                        }

                        [void]$_ComposerNodeTaskCollection.Add($_resp)

                    }

                    elseif ($PSBoundParameters['Whatif'])
                    {

                        "[{0}] -Whatif scenario." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else
                    {

                        "[{0}] User cancelled operation." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                }

                else
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException NoStandbyComposerFound ObjectNotFound 'Composer' -Message ('No standby Composers were found in {0} ApplianceConnection.' -f $_connection.Name)
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }                

            }

        }
        
    }

    End
    {

        Return $_ComposerNodeTaskCollection

    }

}

function Enclosure-Report 
{

    <#
        .DESCRIPTION
        Internal helper function to display the report of an enclosure
 
        .Parameter Enclosure
        The enclosure object.
     
        .Parameter file
        File to save the report to.
     
        .INPUTS
        Enclosure object.
 
        .OUTPUTS
        Enclosure report.
 
        .LINK
        Get-HPOVEnclosure
 
        .LINK
        Send-HPOVRequest
 
        .EXAMPLE
        PS C:\> $enclosures = Get-HPOVEnclosure
        Return all the enclosure hardware managed by this appliance.
 
    #>

    
    [CmdletBinding ()]    
    Param 
    (

        [Parameter (Mandatory,ValueFromPipeline)]
        [object]$Enclosure,
    
        [Parameter (Mandatory = $false,ValueFromPipeline = $false)]
        [object]$file,
    
        [Parameter (Mandatory = $false)]
        [Switch]$fwreport
    )

    Process 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        Write-Verbose "ENCLOSURE OBJECT: $($enclosure)"
        Write-Verbose "ENCLOSURE UUID: $($Enclosure.uuid)"
    
    # ENCLOSURE REPORT DATA
        $a = @{Expression={$_.name};Label="Enclosure Name";width=15},
             @{Expression={$_.serialNumber};Label="Serial Number";width=15},
             @{Expression={$_.enclosureType};Label="Enclosure Model";width=30},
             @{Expression={$_.rackName};Label="Rack Name";width=12},
             @{Expression={$_.isFwManaged};Label="FW Managed";width=10},
             @{Expression={$_.fwBaseLineName};Label="Baseline Name";width=30}

        # Generate Report
        $Enclosure | format-table $a -AutoSize
        
        # License Intent Report
        $a = @{Expression={$_.licensingIntent};Label="Licensing";width=15}

        $Enclosure | format-table $a -AutoSize
        
    # ONBOARD ADMINISTRATOR REPORT DATA
        $a = @{Expression={$_.bayNumber};Label="OA Bay";width=10},
             @{Expression={$_.role};Label="Role";width=15},
             @{Expression={$_.ipAddress};Label="IP Address";width=15},
             @{Expression={($_.fwVersion + " " + $_.fwBuildDate)};Label="Firmware Version";width=20}
        
        $Enclosure.oa | Format-Table $a -AutoSize
        
    # DEVICE BAY REPORT DATA
        # Looking for servers related to the requested enclosure
        $serversCol = [System.Collections.ArrayList]::new()
        
        # Loop through populated device bays
        ForEach ($_DeviceBay in ($Enclosure.deviceBays | Where-Object { $_.devicePresence -eq 'Present' -and $_.deviceUri } ))
        {
            
            # Loop through index association results
            Try
            {
                
                $_server = Send-HPOVRequest $_DeviceBay.deviceUri -Hostname $Enclosure.ApplianceConnection

                [void]$serversCol.Add($_server)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
    
        }
        
        $serversCol | out-string | Write-Verbose
        
        $a = @{Expression={$_.name};Label="Server Name";width=20},
             @{Expression={$_.serialNumber};Label="Serial Number";width=15},
             @{Expression={$_.shortModel};Label="Model";width=12},
             @{Expression={$_.romVersion};Label="System ROM";width=15},
             @{Expression={($_.mpModel + " " + $_.mpFirmwareVersion)};Label="iLO Firmware Version";width=22},
             @{Expression={

                 if (-not($_.serverProfileUri))
                { 
                    
                    'No Profile' 
                
                }

                 else 
                { 
                 
                    Try
                    {

                        (Send-HPOVRequest $_.serverProfileUri -Hostname $Enclosure.ApplianceConnection).name 

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                
                }

             };Label="Server Profile";width=30},
             @{Expression={$_.licensingIntent};Label="Licensing";width=15}
        
        $serversCol | Sort-Object name | format-table $a -AutoSize
        
    # INTERCONNECT BAY REPORT DATA
        # Loop through interconnect bays
        $interconnectsCol = [System.Collections.ArrayList]::new()

        foreach ($interconnect in $enclosure.interconnectBays)
        {

            Write-Verbose "INTERCONNECT: $($interconnect)"

            if ($interconnect.interconnectUri)
            {

                Try
                {

                    # Get the Interconnect object to read properties
                    $tempInterconnect = Send-HPOVRequest $interconnect.interconnectUri -Hostname $Enclosure.ApplianceConnection

                    # Get Logical Interconnect associated with the Interconnect to report its Name
                    $li = Send-HPOVRequest $interconnect.logicalInterconnectUri -Hostname $Enclosure.ApplianceConnection

                    $tempInterconnect | Add-Member -type NoteProperty -name liName -value $li.name
                    $tempInterconnect | out-string | Write-Verbose
                
                    [void]$interconnectsCol.Add($tempInterconnect)

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        # Display Interconnect information (Name, Model, Serial Number, FW Ver)
        $a = @{Expression={$_.name};Label="Interconnect Name";width=22},
             @{Expression={$_.model};Label="Module";width=38},
             @{Expression={$_.serialNumber};Label="Serial Number";width=20},
             @{Expression={$_.firmwareVersion};Label="Firmware Version";width=20}

        $interconnectsCol | format-Table $a -AutoSize

        # Display Interconnect information (PAD, Name, Logical Interconnect Name, State, Status)
        $b = @{Expression={' '};Label=" ";width=5},
             @{Expression={$_.name};Label="Interconnect Name";width=22},
             @{Expression={$_.liName};Label="Logical Interconnect";width=30},
             @{Expression={$_.state};Label="State";width=14},
             @{Expression={$_.status};Label="Status";width=20},
             @{Expression={ 
                 
                switch ($_.category)
                {

                    $ResourceCategoryEnum.SasInterconnect
                    {

                        $_uriPropertyName = 'sasLogicalInterconnectUri'

                    }

                    default
                    {
                        
                        $_uriPropertyName = 'logicalInterconnectUri'

                    }

                }

                 Try
                 {

                     $tempLI = Send-HPOVRequest $_.$_uriPropertyName -Hostname $Enclosure.ApplianceConnection

                 }

                 Catch
                 {

                     $PSCmdlet.ThrowTerminatingError($_)

                 }
                 
                 switch ($tempLI.consistencyStatus) 
                 {
 
                    'CONSISTENT'     { "Consistent" }
                    'NOT_CONSISTENT' { "Inconsistent with group" }
                    default          { $tempLI.consistencyStatus }
                 
                 }
             
             };Label="Consistency state";width=26}

        $interconnectsCol | format-Table $b -AutoSize

        # Write-Host "=================================================================================================================="

    }

}

function Remove-HPOVEnclosure 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri", "name", "Enclosure",'Resource')]
        [object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        
        if (-not($PSBoundParameters['Enclosure'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection      = [System.Collections.ArrayList]::new()
        $_EnclosureCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Enclosure Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ($InputObject.category -eq 'enclosures')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType PSObject -Message "The Network resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_EnclosureCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType PSObject -Message "The Enclosure resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'enclosures'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($enclosure in $InputObject) 
            {

                # Enclosure passed is a URI
                if (($enclosure -is [String]) -and [System.Uri]::IsWellFormedUriString($enclosure,'Relative')) 
                {

                    "[{0}] Received URI: $($enclosures)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Enclosure Object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # // NEED APPLIANCE NAME HERE with If Condition
                    Try
                    {

                        $enclosure = Send-HPOVRequest -Uri $enclosure -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                
                }

                # Enclosure passed is the Name
                elseif (($enclosure -is [String]) -and (-not($enclosure.startsWith("/rest")))) 
                {

                    "[{0}] Received Enclosure Name $($enclosure)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Enclosure object from Get-HPOVEnclosure" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    # // NEED APPLIANCE NAME HERE with If Condition
                    Try
                    {

                        $enclosure = Get-HPOVEnclosure -Name $enclosure -ApplianceConnection $ApplianceConnection

                    }
                    

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Enclosure passed is an object
                elseif ($enclosure -is [PSCustomObject] -and ($enclosure.category -ieq 'enclosures')) 
                {
                    
                    "[{0}] Enclosure Object provided: $($enclosure )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Resource' -TargetType 'PSObject' -Message "Invalid Resource Parameter: $($enclosure )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                [void]$_EnclosureCollection.Add($enclosure)

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_EnclosureCollection.count) Enclosure resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Enclosure Resources
        ForEach ($_enclosure in $_EnclosureCollection)
        {

            if ($PSCmdlet.ShouldProcess($_enclosure.name,"Remove Enclosure from appliance '$($_enclosure.ApplianceConnection)'")) 
            {

                "[{0}] Removing Enclosure '$($_enclosure.name)' from appliance '$($_enclosure.ApplianceConnection)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($PSBoundParameters['Force'])
                    {

                        $_enclosure.uri += "?force=true"

                    }

                    Send-HPOVRequest -Uri $_enclosure.Uri -Method DELETE -AddHeader @{'If-Match' = $_enclosure.eTag } -Hostname $_enclosure.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

}

function Get-HPOVServerHardwareType 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Model,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ("x", "export")]
        [ValidateScript ({split-path $_ | Test-Path})]
        [String]$exportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SHTCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance Connection {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            $uri = '{0}?sort=name:asc' -f $ServerHardwareTypesUri

            if ($PSBoundParameters['Name'])
            {

                "[{0}] Server Hardware Type name provided: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                $uri = "{0}&filter=name matches '{1}'" -f $uri, $Name.Replace('*','%25')

            }

            if ($PSBoundParameters['Model'])
            {

                "[{0}] Server Hardware Type model provided: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Model | Write-Verbose

                $uri = "{0}&filter=model matches '{1}'" -f $uri, $model.Replace('*','%25')

            }

            Try
            {

                $_resp = Send-HPOVRequest $uri -hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Name'] -and $_resp.count -eq 0)
            {

                $ExceptionMessage = "'{0}' Server Hardware Type not found on '{1}' appliance connection. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerHardwareTypeNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            elseif ($PSBoundParameters['Model'] -and $_resp.count -eq 0)
            {

                $ExceptionMessage = "'{0}' Server Hardware Type model not found on '{1}' appliance connection. Please check the name and try again." -f $Model, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException ServerHardwareTypeNotFound ObjectNotFound 'Model' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                $_resp.members | ForEach-Object { 
                    
                    $_.PSObject.TypeNames.Insert(0,'HPOneView.ServerHardwareType')

                    [void]$_SHTCollection.Add($_)
                
                }

            }

        }

    }

    End 
    {

        if ($PSboundParameters['ExportFile']) 
        {

            $_SHTCollection | ConvertTo-JSON -Depth 99 > $ExportFile

        }

        else
        {

            Return $_SHTCollection

        }

    }

}

function Set-HPOVServerHardwareType
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [Alias('Resource')]
        [validateNotNullorEmpty()]
        [Object]$InputObject,
    
        [Parameter (Mandatory)]
        [validateNotNullorEmpty()]
        [String]$Name,
            
        [Parameter (Mandatory = $false)]
        [String]$Description,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Support ApplianceConnection property value via pipeline from Enclosure Object
        if(-not $PSboundParameters['InputObject'])
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
    
    }

    Process 
    {    

        # Validate the input object category is server-hardware-types
        if ($InputObject.category -ne 'server-hardware-types')
        {

            $ExceptionMessage = "The specified '{0}' InputObject parameter value is not supported type. Only Server Hardware Type resources are allowed." -f $InputObject
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_UpdatedSHTResourceDescriptions = [PSCustomObject]@{
            name        = $Name;
            description = $Description
        }

        "[{0}] Will update the SHT name from {1} to {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $Name | Write-Verbose

        if ($PSBoundParameters['Description'])
        {

            "[{0}] Will update the SHT sescription from {1} to {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.description, $Description | Write-Verbose        

        }
        
        try
        {

            $_resp = Send-HPOVRequest -Uri $InputObject.uri -Method PUT -Body $_UpdatedSHTResourceDescriptions -Hostname $ApplianceConnection

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_resp.PSObject.TypeNames.Insert(0, 'HPOneView.ServerHardwareType')
        $_resp

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Show-HPOVFirmwareReport 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [Alias('Resource')]
        [validateNotNullorEmpty()]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $false)]
        [validateNotNullorEmpty()]
        [Object]$Baseline,
            
        [Parameter (Mandatory = $false)]
        [Switch]$Export,
            
        [Parameter (Mandatory = $false)]
        [validateNotNullorEmpty()]
        [String]$Location = (get-location).Path,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Support ApplianceConnection property value via pipeline from Enclosure Object
        if(-not($PSboundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ResourceCollection       = [System.Collections.ArrayList]::new()
        $_FirmwareReportCollection = [System.Collections.ArrayList]::new()

        # Test for location
        if ($Export) 
        {
        
            if ( -not (Test-Path $Location)) 
            {  

                $ErrorRecord = New-ErrorRecord InvalidOperationException LocationPathNotFound ObjectNotFound 'Location' -Message "The specified path $Location does not exist. Please verify it and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }
    
    }

    Process 
    {    

        $_r = 1

        # Add Resource to Collection, which can be accepted via the pipeline
        ForEach ($_resource in ($InputObject | ? state -ne 'Unmanaged'))
        {

            if ($_resource -is [String])
            {

                # Error that the Resource isn't an object
                $ExceptionMessage = 'The Inputobject {0} is not a supported resource type, PSObject.' -f $_resource
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidBaselineResouce InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Adding '{1}' object to collection ({2}/{3})." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_resource.name, $_r, ($InputObject | Measure-Object).Count | Write-Verbose 

            [void]$_ResourceCollection.Add($_resource)

            $_r++

        }

    }

    End 
    {

        $_P = 0

        # Process the report generation here
        ForEach ($_resource in $_ResourceCollection)
        {

            if (-not($PSBoundParameters['Verbose']) -or -not($VerbosePreference -eq 'Continue'))
            {
                
                Write-Progress -id 1 -activity "Generate Firmware Report" -percentComplete (($_P / $_ResourceCollection.count) * 100)

            }

            switch ($_resource.category) 
            {

                $ResourceCategoryEnum.EnclosureGroup
                {

                    $_P++

                    $_ProgressParams = @{

                        ID = 1;
                        Activity = "Generate Firmware Report";
                        CurrentOperation = ("Processing '{0}' Enclosure Group" -f $_resource.name);
                        PercentComplete = (($_P / $_ResourceCollection.count) * 100)

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    {
                        
                        "[{0}] Collecting Enclosure Firmware Information - {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose

                    }
                    
                    else 
                    { 

                        Write-Progress @_ProgressParams
                    
                    }

                    "[{0}] Getting Enclosure Group to Enclosure associations, then getting found Enclosure Resources." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        # Get associated Logical Enclosures with Enclosure Group
                        $_uri = '{0}?parentUri={1}&name=ENCLOSURE_GROUP_TO_LOGICAL_ENCLOSURE' -f $AssociationsUri, $_resource.uri
                        [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_resource.ApplianceConnection

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                        
                    # Make sure the EG has associated Enclosures/LogicalEnclosures.
                    if ($_ResourcesFromIndexCol) 
                    {

                        $_e = 0

                        "[{0}] Total number of Logical Enclosures to Process: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ResourcesFromIndexCol.Count | Write-Verbose 

                        foreach ($_le in $_ResourcesFromIndexCol) 
                        { 

                            # Loop through LE EnclosureUris
                            foreach ($_enclosureUri in $_le.enclosureUris)
                            {

                                # Get Enclosure Resource Object
                                Try
                                {

                                    $_enclosure = Send-HPOVRequest -uri $_enclosureUri -Hostname $_resource.ApplianceConnection

                                }
                            
                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                                $_e++

                                $_EnclParams = @{

                                    ID               = 10;
                                    ParentID         = 1;
                                    Activity         = "Create Enclosure Firmware Report";
                                    CurrentOperation = ("[{0}\{1}] Processing '{2}' Enclosure" -f $_e, $_ResourcesFromIndexCol.Count, $_enclosure.name);
                                    PercentComplete  = (($_e / $_ResourcesFromIndexCol.Count) * 100)

                                }

                                # Handle the call from -Verbose so Write-Progress does not get borked on display.
                                if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                                { 

                                    "[{0}] Collecting Enclosure Firmware Information: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_EnclParams | Out-String) | Write-Verbose
                            
                                }
                    
                                else 
                                { 
                                
                                    Write-Progress @_EnclParams
                            
                                }

                                Try
                                {

                                    $_EnclosureReportCol = Get-EnclosureFirmware -Enclosure $_enclosure -Baseline $Baseline -ProgressID 1

                                    "[{0}] Enclosure Firmware Report return: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_EnclosureReportCol | Out-String) | Write-Verbose

                                    ForEach ($_item in $_EnclosureReportCol)
                                    {

                                        "[{0}] Adding {1} in {2} to Enclosure Firmware collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_item.Component, $_item.Name | Write-Verbose
                                        
                                        # $_item | add-member -Type NoteProperty -Name eg -value $_resource.name

                                        [void]$_FirmwareReportCollection.Add($_item)

                                    }

                                }
                            
                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                            }                        

                        }

                    }
                        
                    # Clear Child Write-Progress progress bars
                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Enclosure Firmware Information - Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
             
                    else 
                    { 
                        
                        Write-Progress -ParentId 1 -id 2 -activity "Collecting Enclosure Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Enclosure Group Firmware Information Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
             
                    else 
                    { 
                        
                        Write-Progress -Id 1 -activity "Collecting Enclosure Group Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }

                }

                $ResourceCategoryEnum.LogicalEnclosure
                {

                    $_P++

                    $_ProgressParams = @{

                        ID = 1;
                        Activity = "Generate Firmware Report";
                        CurrentOperation = ("Processing '{0}' Logical Enclosure" -f $_resource.name);
                        PercentComplete = (($_P / $_ResourceCollection.count) * 100)

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    {
                        
                          "[{0}] Collecting Logical Enclosure Firmware Information - {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose

                    }
                    
                    else 
                    { 

                        Write-Progress @_ProgressParams
                    
                    }

                    "[{0}] Getting Enclosure resources from Logical Enclosure." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_e = 0

                    # Loop through LE EnclosureUris
                    foreach ($_enclosureUri in $_resource.enclosureUris)
                    {

                        # Get Enclosure Resource Object
                        Try
                        {

                            $_enclosure = Send-HPOVRequest -uri $_enclosureUri -Hostname $_resource.ApplianceConnection

                        }
                    
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $_e++

                        $_EnclParams = @{

                            ID               = 10;
                            ParentID         = 1;
                            Activity         = "Create Enclosure Firmware Report";
                            CurrentOperation = ("[{0}\{1}] Processing '{2}' Enclosure" -f $_e, $_resource.enclosureUris.Count, $_enclosure.name);
                            PercentComplete  = (($_e / $_resource.enclosureUris.Count) * 100)

                        }

                        # Handle the call from -Verbose so Write-Progress does not get borked on display.
                        if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                        { 

                            "[{0}] Collecting Enclosure Firmware Information: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_EnclParams | Out-String) | Write-Verbose
                    
                        }
            
                        else 
                        { 
                        
                            Write-Progress @_EnclParams
                    
                        }

                        Try
                        {

                            $_EnclosureReportCol = Get-EnclosureFirmware -Enclosure $_enclosure -Baseline $Baseline -ProgressID 1

                            "[{0}] Enclosure Firmware Report return: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_EnclosureReportCol | Out-String) | Write-Verbose

                            ForEach ($_item in $_EnclosureReportCol)
                            {

                                "[{0}] Adding {1} in {2} to Enclosure Firmware collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_item.Component, $_item.Name | Write-Verbose

                                [void]$_FirmwareReportCollection.Add($_item)

                            }

                        }
                    
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }                        
                        
                    # Clear Child Write-Progress progress bars
                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Enclosure Firmware Information - Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
             
                    else 
                    { 
                        
                        Write-Progress -ParentId 1 -id 2 -activity "Collecting Enclosure Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Enclosure Group Firmware Information Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
             
                    else 
                    { 
                        
                        Write-Progress -Id 1 -activity "Collecting Enclosure Group Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }

                }

                # "enclosures"
                $ResourceCategoryEnum.Enclosure
                {

                    # Keep track of the number of resources
                    $_P++

                    $_ProgressParams = @{

                        ID = 1;
                        Activity = "Generate Firmware Report";
                        CurrentOperation = ("Processing '{0}' Enclosure" -f $_resource.name);
                        PercentComplete = (($_P / $_ResourceCollection.count) * 100)

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    {
                        
                          "[{0}] Collecting Enclosure Firmware Information - {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
                    }
                    
                    else 
                    { 

                        Write-Progress @_ProgressParams
                    
                    }

                    Try
                    {

                        $_EnclosureReport = Get-EnclosureFirmware -Enclosure $_resource -Baseline $Baseline -ProgressID 1

                        $_EnclosureReport | ForEach-Object {

                            [void]$_FirmwareReportCollection.Add($_)

                        }

                    }

                    Catch
                    {

                        Write-Progress -id 1 -activity "Collecting Enclosure Firmware Information" -CurrentOperation "Completed" -Completed 

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Enclosure Firmware Information - Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
                
                    else 
                    { 
                        
                        Write-Progress -id 1 -activity "Collecting Enclosure Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }

                }

                $ResourceCategoryEnum.ServerHardware
                { 

                    # Keep track of the number of resources
                    $_P++

                    $_ProgressParams = @{

                        ID = 1;
                        Activity = "Generate Firmware Report";
                        CurrentOperation = ("Processing '{0}' Server(s)" -f $_resource.name);
                        PercentComplete = (($_P / $_ResourceCollection.count) * 100)

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    {
                        
                          "[{0}] Collecting Server Firmware Information - {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
                    }
                    
                    else 
                    { 

                        Write-Progress @_ProgressParams
                    
                    }

                    Try
                    {

                        $_ServerReport = Get-ServerFirmware -Server $_resource -Baseline $Baseline -ProgressID 1

                        $_ServerReport | ForEach-Object {

                            [void]$_FirmwareReportCollection.Add($_)

                        }

                    }

                    Catch
                    {

                        Write-Progress -id 1 -activity "Collecting Server Firmware Information" -CurrentOperation "Completed" -Completed 

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Server Firmware Information - Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
                
                    else 
                    { 
                        
                        Write-Progress -id 1 -activity "Collecting Server Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }
            
                }

                {$ResourceCategoryEnum.Interconnect, $ResourceCategoryEnum.SasInterconnect -Contains $_}
                { 

                    # Keep track of the number of resources
                    $_P++

                    $_ProgressParams = @{

                        ID = 1;
                        Activity = "Generate Firmware Report";
                        CurrentOperation = ("Processing '{0}' Interconnects(s)" -f $_resource.name);
                        PercentComplete = (($_P / $_ResourceCollection.count) * 100)

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    {

                        "[{0}] Completed Collecting Server Firmware Information - {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
                        
                    }
                    
                    else 
                    { 

                        Write-Progress @_ProgressParams
                    
                    }

                    Try
                    {

                        $_InterconnectFirmwareReport = Get-InterconnectFirmware -Interconnect $_resource -Baseline $Baseline -ProgressID 1

                        $_InterconnectFirmwareReport | ForEach-Object {

                            [void]$_FirmwareReportCollection.Add($_)

                        }

                    }

                    Catch
                    {

                        Write-Progress -id 1 -activity "Collecting Interconnect Firmware Information" -CurrentOperation "Completed" -Completed 

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Completed Collecting Interconnect Firmware Information - Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    }
                
                    else 
                    { 
                        
                        Write-Progress -id 1 -activity "Collecting Server Firmware Information" -CurrentOperation "Completed" -Completed 
                    
                    }
           
                }

            }

        }

        Write-Progress -ID 10 -ParentID 1 -Activity "Create Enclosure Firmware Report" -Status "Finished." -Completed

        Write-Progress -Activity "Firmware collection report complete." -Status "Finished." -Completed

        if ($Export) 
        { 

            $_Location = '{0}\FirmwareReport_{1}.csv' -f $Location,[DateTime]::Now.ToUniversalTime().ToString('yyyy-MM-ddTHH.mm.ss.ff.fffZzzz').Replace(':','')

            $_FirmwareReportCollection | ForEach-Object { Export-Csv -InputObject $_ -Path $_Location -AppEnd -NoTypeInformation -Encoding UTF8 }
                
        }

        # Display Report
        else 
        {

            Return $_FirmwareReportCollection

        }

    }

}

function Get-EnclosureFirmware 
{

    <#
        Internal-only function.
    #>


    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateScript({
            if ($_.category -ne 'enclosures') 
            { 
                
                Throw ("The resource object provided is not an Enclosure Resource. Expected category 'enclosures', Received '{0}' [{1}]." -f $_.category, $_.name)
            }

            else
            {

                $True

            }
        
        })]
        [PsCustomObject]$Enclosure, 

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [object]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Int]$ProgressID = 0
        
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        # Reset private variables
        $_BaseLinePolicy  = $Null
        $_EnclosureReport = [System.Collections.ArrayList]::new()

        # Keep track of the number of Servers
        $_s = 0

        # Keep track of the number of Interconnects
        $_i = 0
        
        # Keep track of the number of OAs
        $_o = 0

        # Keep track of the number of composable infrastructure appliances
        $_cia = 0
        # See if EnclosureObject was passed via Pipeline
        if (-not $PSBoundParameters['Enclosure']) 
        { 
            
            $PipelineInput = $True 
        
        }

    }

    Process 
    {
        
        "[{0}] Enclosure Object passed via pipeline: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [Bool]$PipelineInput | Write-Verbose
        "[{0}] Processing Enclosure firmware report for: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Enclosure.name | Write-Verbose

        # Use the Enclosure FwBaseline if it is set
        if (($Enclosure.isFwManaged) -and ($null -eq $Baseline)) 
        { 

            Try
            {

                $BaseLinePolicy = Send-HPOVRequest -Uri $Enclosure.fwBaselineUri -Hostname $Enclosure.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif (($Baseline) -and ($Baseline -is [PsCustomObject]) -and ($Baseline.category -eq $ResourceCategoryEnum['Baseline'])) 
        { 
        
            "[{0}] Baseline resource passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] Baseline resource name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.name | Write-Verbose
            "[{0}] Baseline resource uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.uri | Write-Verbose

            $BaseLinePolicy = $Baseline
            
        }
        
        # Check to see if the wrong Object has been passed
        elseif (($Baseline) -and ($Baseline -is [PsCustomObject]) -and ($Baseline.category -ne "firmware-drivers")) 
        { 
        
            "[{0}] Invalid Baseline resource passed. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ExceptionMessage = "An invalid Baseline Object was passed. Expected Category type 'firmware-drivers', received '{0}' (Object Name: {1}" -f $Baseline.category, $Baseline.name
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidBaselineResouce InvalidArgument 'Baseline' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }
        
        elseif (($Baseline) -and ($Baseline -is [String]) -and ($Baseline.StartsWith(($ApplianceFwDriversUri)))) 
        { 
            
            "[{0}] Baseline URI passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

            Try
            {

                $BaseLinePolicy = Send-HPOVRequest -Uri $Baseline -Hostname $Enclosure.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        
        }
        
        # Check to see if the wrong URI has been passed
        elseif (($Baseline) -and ($Baseline -is [String]) -and $Baseline.StartsWith("/rest/") -and ( -not $Baseline.StartsWith(($ApplianceBaselineRepoUri)))) 
        { 
        
            "[{0}] Invalid Baseline URI passed. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ExceptionMessage = "An invalid Baseline URI was passed. URI must start with '/rest/firmware-drivers/', received '{0}'" -f $Baseline
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidBaselineValue InvalidArgument 'Baseline' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)        
            
        }
        
        elseif (($Baseline) -and ($Baseline -is [String])) 
        { 
        
            "[{0}] Baseline Name passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

            Try
            {

                $FirmwareBaslineName = $Baseline.Clone()

                $BaseLinePolicy = Get-HPOVBaseline -name $Baseline -ErrorAction SilentlyContinue

                If (-not $BaseLinePolicy)
                {

                    $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }
        
        else 
        { 
        
            "[{0}] No Baseline provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $BaseLinePolicy = [PsCustomObject]@{ baselineShortName = "NoPolicySet" } 
        
        }

        # Process shared infrastructure components based on enclosure type
        # If C-Class, attach to XML interface to get OA module information. Will need to override SslValidator checks
        Switch ($Enclosure.enclosureType)
        {

            'C7000'
            {

                # Process OAs first
                ForEach ($_oa in $Enclosure.managerbays)
                {

                    if ($_oa.devicePresence -ne 'Absent')
                    {

                        $_o ++

                        $_ProgressParams = @{

                            id               = (2 + $ProgressID);
                            ParentId         = 1;
                            activity         = "Collecting Enclosure Manager Firmware Information";
                            CurrentOperation = ("[{0}/{1}] Processing '{2}'" -f $_o, $Enclosure.managerBays.count, $_oa.role);
                            percentComplete  = (($_o / $Enclosure.managerBays.count) * 100) 

                        }

                        # Handle the call from -Verbose so Write-Progress does not get borked on display.
                        if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                        { 
                            
                            "[{0}] Collecting Enclosure Manager Firmware Information - Skipping Write-Progress display: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
                        
                        }
                        
                        else 
                        { 
                            
                            Write-Progress @_ProgressParams
                        
                        }

                        if ($BaseLinePolicy.baselineShortName -eq "NoPolicySet") 
                        { 
                            
                            $BaselineVer = "N/A" 
                            $BaselineName  = "N/A" 
                            $BaselineUri = $null
                        
                        }

                        else 
                        { 
                            
                            $_BaselineVersions = $BaseLinePolicy.fwComponents | Where-Object KeyNameList -contains "oa"

                            $_BaselineVer = GetNewestVersion -Collection $_BaselineVersions
                            $BaselineName = $Baseline.description
                            $BaselineUri  = $Baseline.uri
                        
                        }

                        "[{0}] Adding '{1}, OA {2}' to firmware report collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Enclosure.name, $_oa.bayNumber | Write-Verbose

                        $_EnclosureDeviceReport = New-Object HPOneView.Servers.Enclosure+Firmware(("{0}, OA {1}" -f $Enclosure.name, $_oa.bayNumber),
                                                                                        'OnboardAdministrator',
                                                                                        'Firmware',
                                                                                        $_oa.fwVersion,
                                                                                        $_BaselineVer,
                                                                                        $BaselineName,
                                                                                        $BaselineUri,
                                                                                        $Enclosure.name,
                                                                                        $Enclosure.uri,
                                                                                        $Enclosure.ApplianceConnection)

                        [void]$_EnclosureReport.Add($_EnclosureDeviceReport)

                    }

                    else
                    {

                        "[{0}] Onboard Administrator device bay {1} is absent." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_o | Write-Verbose

                    }                    
                    
                }

            }

            'SY12000'
            {

                # Process FLMs first
                ForEach ($_em in $Enclosure.managerbays)
                {

                    $_o ++

                    $_ProgressParams = @{

                        id               = (2 + $ProgressID);
                        ParentId         = 1;
                        activity         = "Collecting Enclosure Manager Firmware Information";
                        CurrentOperation = ("[{0}/{1}] Processing '{2}'" -f $_o, $Enclosure.managerBays.count, $_em.role);
                        percentComplete  = (($_o / $Enclosure.managerBays.count) * 100) 

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Collecting Enclosure Manager Firmware Information - Skipping Write-Progress display: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
                    
                    }
                    
                    else 
                    { 
                        
                        Write-Progress @_ProgressParams
                    
                    }

                    if ($BaseLinePolicy.baselineShortName -eq "NoPolicySet") 
                    { 
                        
                        $BaselineVer = "N/A" 
                        $BaselineName  = "N/A" 
                        $BaselineUri = $null
                    
                    }

                    else 
                    { 
                        
                        $_BaselineVersions = $BaseLinePolicy.fwComponents | Where-Object KeyNameList -Contains "em"

                        $_BaselineVer = GetNewestVersion -Collection $_BaselineVersions
                        $BaselineName  = $Baseline.description
                        $BaselineUri = $Baseline.uri
                    
                    }

                    $_EnclosureDeviceReport = New-Object HPOneView.Servers.Enclosure+Firmware(("{0} (Bay {1})" -f $_em.model.Trim(), $_em.bayNumber),
                                                                                      'EnclosureManager',
                                                                                      'Firmware',
                                                                                      $_em.fwVersion,
                                                                                      $_em.serialNumber,
                                                                                      $_em.partNumber,
                                                                                      $_BaselineVer,
                                                                                      $BaselineName,
                                                                                      $BaselineUri,
                                                                                      $Enclosure.name,
                                                                                      $Enclosure.uri,
                                                                                      $Enclosure.ApplianceConnection)

                    [void]$_EnclosureReport.Add($_EnclosureDeviceReport)

                }

                ForEach ($_appliance in ($Enclosure.applianceBays | Where-Object devicePresence -ne 'Absent'))
                {

                    $_cia ++

                    $_ProgressParams = @{

                        id               = (3 + $ProgressID);
                        ParentId         = 1;
                        activity         = "Collecting Composable Infrastructure appliance firmware information";
                        CurrentOperation = ("[{0}/{1}] Processing '{2}'" -f $_cia, $Enclosure.applianceBays.count, $_appliance.model);
                        percentComplete  = (($_cia / $Enclosure.applianceBays.count) * 100) 

                    }

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Collecting Enclosure Manager Firmware Information - Skipping Write-Progress display: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
                    
                    }
                    
                    else 
                    { 
                        
                        Write-Progress @_ProgressParams
                    
                    }

                    $_applianceSerialNumber  = $_appliance.serialNumber
                    $_appliancePartNumber    = $_appliance.partNumber

                    # Get installed firmware
                    switch ($_appliance.Model)
                    {

                        # need to figure out how to support both DCS and real hardware.
                        {$_ -match 'Composer'}
                        {

                            # if ($null -ne $_appliance.serialNumber)
                            # {

                            # $uri = '{0}/{1}' -f $ApplianceHANodesUri, $_appliance.serialNumber

                            # Try
                            # {

                            # $_applianceDetails = Send-HPOVRequest -Uri $uri -Hostname $Enclosure.ApplianceConnection
                            # $_applianeFirmareVersion = $_applianceDetails.version

                            # }

                            # Catch
                            # {

                            # $PSCmdlet.ThrowTerminatingError($_)

                            # }

                            # }
                            
                            # # This is for DCS
                            # else
                            # {

                                $_applianeFirmareVersion = $PSLibraryVersion.($Enclosure.ApplianceConnection.Name).ApplianceVersion
                                

                            # }
                            
                        }

                        {$_ -match 'Image Streamer'}
                        {

                            Try
                            {

                                $uri = "{0}?filter=applianceSerialNumber eq '{1}'" -f $AvailableDeploymentServersUri, $_appliance.serialNumber
                                $_applianceDetails = Send-HPOVRequest -Uri $uri -Hostname $Enclosure.ApplianceConnection
                                $_applianeFirmareVersion = $_applianceDetails.members.imageStreamerVersion

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                    }

                    $_EnclosureDeviceReport = New-Object HPOneView.Servers.Enclosure+Firmware(("{0} (Bay {1})" -f $_appliance.Model, $_appliance.bayNumber),
                                                                                      'ApplianceDevice',
                                                                                      'Firmware',
                                                                                      $_applianeFirmareVersion,
                                                                                      $_applianceSerialNumber,
                                                                                      $_appliancePartNumber,
                                                                                      'N/A',
                                                                                      'N/A',
                                                                                      $null,
                                                                                      $Enclosure.name,
                                                                                      $Enclosure.uri,
                                                                                      $Enclosure.ApplianceConnection)

                    [void]$_EnclosureReport.Add($_EnclosureDeviceReport)

                }

                # Locate drive enclosure relative to the frame
                Try
                {

                    $uri = "{0}?filter=enclosureUri EQ '{1}'" -f $DriveEnclosureUri, $Enclosure.uri
                    $_driveEnclosures = Send-HPOVRequest -Uri $uri -Hostname $Enclosure.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                ForEach ($_driveEnclosure in $_driveEnclosures.members)
                {

                    # Report drive enclosure IO Adapter(s)
                    ForEach ($_IOAdatper in $_driveEnclosure.ioAdapters)
                    {

                        $_EnclosureDeviceReport = New-Object HPOneView.Servers.Enclosure+Firmware(("{0} {1}{2}" -f $_IOAdatper.Model, $_IOAdatper.ioAdapterLocation.locationEntries.type, $_IOAdatper.ioAdapterLocation.locationEntries.value),
                                                                                      'DriveEnclosureIOAdapter',
                                                                                      'Firmware',
                                                                                      $_IOAdatper.firmwareVersion,
                                                                                      $_IOAdatper.serialNumber,
                                                                                      $_IOAdatper.partNumber,
                                                                                      'N/A',
                                                                                      'N/A',
                                                                                      $null,
                                                                                      $_driveEnclosure.name,
                                                                                      $_driveEnclosure.uri,
                                                                                      $Enclosure.ApplianceConnection)

                        [void]$_EnclosureReport.Add($_EnclosureDeviceReport)
                        
                    }

                    # Report drive device
                    ForEach ($_driveBay in $_driveEnclosure.driveBays)
                    {

                        $_diskDrive = $_driveBay.drive

                        $_EnclosureDeviceReport = New-Object HPOneView.Servers.Enclosure+Firmware(("{0} {1}" -f $_diskDrive.name, $_diskDrive.model),
                                                                                      'DiskDrive',
                                                                                      'Firmware',
                                                                                      $_driveBay.drive.firmwareVersion,
                                                                                      $_diskDrive.serialNumber,
                                                                                      $_diskDrive.model,
                                                                                      'N/A',
                                                                                      'N/A',
                                                                                      $null,
                                                                                      $_driveEnclosure.name,
                                                                                      $_driveEnclosure.uri,
                                                                                      $Enclosure.ApplianceConnection)

                        [void]$_EnclosureReport.Add($_EnclosureDeviceReport)

                    }

                }

            }

            default
            {

                Throw ("'{0}' Not implemented." -f $Enclosure.enclosureType)

            }

        }

        # Process Interconnects within Enclosure
        "[{0}] Getting Interconnect resources from the enclosure." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $_Interconnects = [System.Collections.ArrayList]::new()

        Try
        {            
            
            ForEach ($_InterconnectBay in ($Enclosure.interconnectBays | Where-Object { $null -ne $_.interconnectUri }))
            {
                
                $_Object = Send-HPOVRequest -Uri $_InterconnectBay.interconnectUri -Hostname $Enclosure.ApplianceConnection

                [void]$_Interconnects.Add($_Object)
            
            }

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }        

        # Process each interconnect
        foreach ($_interconnect in $_Interconnects) 
        {

            $_i++

            $_ProgressParams = @{

                id               = (4 + $ProgressID);
                ParentId         = 1;
                activity         = "Collecting Interconnect Firmware Information";
                CurrentOperation = ("Processing {0}: {1} of {2} Interconnect(s)" -f $_Interconnect.name, $_i, $_Interconnects.Count);
                percentComplete  = (($_i / $_Interconnects.Count) * 100) 

            }

            # Handle the call from -Verbose so Write-Progress does not get borked on display.
            if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
            {
                
                "[{0}] Collecting Interconnect Firmware Information - Skipping Write-Progress display: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
            
            }
             
            else 
            { 
                
                Write-Progress @_ProgressParams
            
            }

            Try
            {

                $_InterconnectReport = Get-InterconnectFirmware -Interconnect $_interconnect -Baseline $BaseLinePolicy

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Adding {1} in {2} to Enclosure Firmware collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_InterconnectReport.Component, $_InterconnectReport.Name | Write-Verbose

            [void]$_EnclosureReport.Add($_InterconnectReport)

        }

        # Process Server Resource Objects
        "[{0}] Getting Server resources from the enclosure." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            # This is faster to get all associated servers within the enclosure than to loop through deviceBays to make additional API calls
            $Uri = "{0}?filter=locationUri='{1}'" -f $ServerHardwareUri, $Enclosure.uri
            $_Servers = Send-HPOVRequest -Uri $uri -Hostname $Enclosure.ApplianceConnection

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_s = 0

        foreach ($_server in $_Servers.members) 
        {

            $_s++

            $_ProgressParams = @{

                id               = (3 + $ProgressID);
                ParentId         = 1;
                activity         = "Collecting Server Firmware Information";
                CurrentOperation = ("[{1}/{2}] Processing '{0}' Server" -f $_server.name, $_s, $_Servers.Count);
                percentComplete  = (($_s / $_Servers.members.count) * 100)

            }

            # Handle the call from -Verbose so Write-Progress does not get borked on display.
            if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
            {
                
                "[{0}] Collecting Server Firmware Information - Skipping Write-Progress display: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ProgressParams | Out-String) | Write-Verbose
            
            }
             
            else 
            { 
                
                Write-Progress @_ProgressParams
            
            }

            Try
            {

                $_ServerFirmwareReport = Get-ServerFirmware -Server $_server -Baseline $BaseLinePolicy 

                ForEach ($_item in $_ServerFirmwareReport)
                {

                    "[{0}] Adding {0} in {1} to Enclosure Firmware collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_item.Component, $_item.Name | Write-Verbose

                    [void]$_EnclosureReport.Add($_item)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Handle the call from -Verbose so Write-Progress does not get borked on display.
        if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
        { 
            
            "[{0}] Completed Collecting Enclosure Manager/Server/Interconnect Firmware Information - Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        }
         
        else 
        { 
        
            Write-Progress -ParentId 1 -id (2 + $ProgressID) -activity "Collecting Enclosure Manager Firmware Information" -CurrentOperation "Completed" -Completed                    
            Write-Progress -ParentId 1 -id (3 + $ProgressID) -activity "Collecting Server Firmware Information" -CurrentOperation "Completed" -Completed
            Write-Progress -ParentId 1 -id (4 + $ProgressID) -activity "Collecting Interconnect Firmware Information" -CurrentOperation "Completed" -Completed
            Write-Progress -Activity "Create Enclosure Firmware Report" -PercentComplete (100) -Status "Finished." -Completed

        }

    }

    End 
    {

        Return $_EnclosureReport | Sort-Object Name, Component

    }

}

function Get-ServerFirmware 
{

    <#
        Internal-only function.
    #>


    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Object]$Server, 

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Object]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Int]$ProgressID
        
    )


    Begin 
    {

        $_ServerReport = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ([System.String]::IsNullOrWhiteSpace($Server.serverName))
        {

            $_servername = $Server.name
            
        }

        else
        {

            $_servername = $Server.serverName            

        }

        "[{0}] Processing Server firmware report for: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_servername | Write-Verbose

        if ('Unknown', 'Adding', 'Monitored', 'Unmanaged', 'Removed', 'Unsupported' -notcontains $Server.state)
        {

            "[{0}] Getting Server Hardware Type" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose        

            # Check if the server hardware type allows firmware management
            Try
            {

                $_sht = Send-HPOVRequest -Uri $Server.serverHardwareTypeUri -Hostname $Server.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            if ($_sht.capabilities -match "FirmwareUpdate") 
            {

                "[{0}] Server Hardware Type supports firmware management." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Baseline value provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Baseline | Out-String) | Write-Verbose

                # If a bladeserver and that the caller hasn't specified a Baseline, Use the Enclosure FwBaseline if it is set
                if (-not($Baseline))
                { 

                    # Check to see if there is a profile
                    if ($Server.serverProfileUri) 
                    {

                        "[{0}] No Baseline provided. Checking Server Profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_ServerProfile = Send-HPOVRequest -Uri $Server.serverProfileUri -Hostname $Server.ApplianceConnection

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        # Then check if a Baseline is attached there
                        if ($_ServerProfile.firmware.manageFirmware) 
                        { 
                        
                            "[{0}] Server Profile has baseline attached. Getting baseline details." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_BaselinePolicy = Send-HPOVRequest -Uri $_ServerProfile.firmware.firmwareBaselineUri -Hostname $Server.ApplianceConnection.Name

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            "[{0}] Server Profile Baseline name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_BaselinePolicy.name | Write-Verbose

                            "[{0}] Server Profile Baseline name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_BaselinePolicy.uri | Write-Verbose

                        }
                        
                        # If not, set $BaselinePolicy to NoPolicySet
                        else 
                        {
                            
                            "[{0}] Server Profile does not have a baseline attached." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_BaselinePolicy.uri | Write-Verbose

                            $_BaselinePolicy = [PsCustomObject]@{ 
                                
                                name              = "NoPolicySet"; 
                                baselineShortName = "NoPolicySet" 
                            
                            } 

                        }

                    }

                    else 
                    {

                        "[{0}] No Server Profile assigned, which does not have a baseline policy set." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_BaselinePolicy = [PsCustomObject]@{ 
                                
                            name              = "NoPolicySet"; 
                            baselineShortName = "NoPolicySet" 
                            
                        } 

                    }
                    
                }

                elseif ($Baseline -is [PSCustomObject])
                {

                    if ($Baseline.baselineShortName -eq 'NoPolicySet')
                    {

                        "[{0}] No Baseline provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_BaselinePolicy = [PsCustomObject]@{ 
                                
                            name              = "NoPolicySet"; 
                            baselineShortName = "NoPolicySet" 
                            
                        } 

                    }

                    elseif (($Baseline) -and ($Baseline.category -eq $ResourceCategoryEnum['Baseline'])) 
                    { 
                
                        "[{0}] Baseline resource passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] Baseline resource name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.baselineShortName | Write-Verbose
                        "[{0}] Baseline resource uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.uri | Write-Verbose

                        $_BaselinePolicy = $Baseline.PSObject.Copy()
                    
                    }

                    # Check to see if the wrong Object has been passed
                    elseif (($Baseline) -and ($Baseline.category -ne "firmware-drivers")) 
                    { 
                
                        "[{0}] Invalid Baseline resource passed. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ExceptionMessage = "The wrong Baseline Object was passed. Expected Category type 'firmware-drivers', received '{0}' (Object Name: {1}" -f $Baseline.category, $Baseline.name
                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentType InvalidArgument 'getserverfirmware' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                }            

                elseif (($Baseline) -and ($Baseline -is [String]) -and ($Baseline.StartsWith(($ApplianceFwDriversUri)))) 
                { 
                    
                    "[{0}] Baseline URI passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

                    Try
                    {

                        $_BaseLinePolicy = Send-HPOVRequest -Uri $Baseline -Hostname $Server.ApplianceConnection.Name

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                
                }

                # Check to see if the wrong URI has been passed
                elseif (($Baseline) -and ($Baseline -is [String]) -and $Baseline.StartsWith("/rest/") -and (-not($Baseline.StartsWith(($ApplianceBaselineRepoUri))))) 
                { 

                    "[{0}] Invalid Baseline URI passed. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $ExceptionMessage = "The wrong Baseline URI was passed. URI must start with '/rest/firmware-drivers/', received '{0}'" -f $Baseline
                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentType InvalidArgument 'getserverfirmware' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)        
                    
                }

                # Baseline must be a Name
                else
                { 
                
                    "[{0}] Baseline Name passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

                    Try
                    {

                        $FirmwareBaslineName = $Baseline.Clone()

                        $_BaseLinePolicy = Get-HPOVBaseline -name $Baseline -ApplianceConnection $Server.ApplianceConnection.Name -ErrorAction Stop

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }
                    
                }

                # Check Baseline Policy and set Compliance statement
                if ($_BaseLinePolicy.baselineShortName -eq "NoPolicySet") 
                { 
                                
                    # Get firmware report from server resource since no baseline is associated
                    $_Uri = '{0}/firmware' -f $Server.uri

                    Try
                    {

                        $_ServerHardwareFirmwareCompliance = Send-HPOVRequest -Uri $_Uri -Hostname $Server.ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                
                                        
                }

                else
                {

                    # This is where we generate compliance report of server hardware with baseline
                    Try
                    {

                        $_FirmwareComplianceReportRequest = @{
                            serverUUID         = $Server.uuid;
                            firmwareBaselineId = $_BaseLinePolicy.resourceId
                        }

                        $_ServerHardwareFirmwareCompliance = Send-HPOVRequest -Uri $ServerHardwareFirmwareComplianceUri -Method POST -Body $_FirmwareComplianceReportRequest -Hostname $Server.ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                Switch ($_ServerHardwareFirmwareCompliance.type)
                {

                    'server-hardware-firmware-1'
                    {

                        ForEach ($_Component in $_ServerHardwareFirmwareCompliance.components)
                        {

                            $_ComponentName = $_Component.componentName

                            if ($_Component.componentName.Contains('.sys') -or $_Component.componentName.Contains('.ko') -or $_Component.componentName.Contains('driver') -or $_Component.componentName.Contains('null'))
                            {

                                $_ComponentType = 'Software'

                                if ($_ComponentName -eq 'null')
                                {

                                    $_ComponentName = $_Component.componentLocation

                                }

                            }

                            else
                            {

                                $_ComponentType = "Firmware"

                            }

                            if (($_ComponentName.Contains('System ROM') -or $_ComponentName.Contains('System BIOS')) -and -not $_ComponentName.Contains('Backup')-and -not $_ComponentName.Contains('Redundant'))
                            {

                                $_SerialNumber = $Server.serialNumber
                                $_PartNumber   = $Server.partNumber

                            }

                            else
                            {

                                $_SerialNumber = 'N/A'
                                $_PartNumber = 'N/A'

                            }

                            $_ComponentVersion = New-Object HPOneView.Servers.ServerHardware+Firmware ($_ComponentName,
                                                                                            $_ComponentType,
                                                                                            $_Component.componentVersion,
                                                                                            $_SerialNumber,
                                                                                            $_PartNumber,
                                                                                            $_Component.baselineVersion,
                                                                                            $_BaseLinePolicy.name,
                                                                                            $_BaseLinePolicy.uri,
                                                                                            $_servername,
                                                                                            $Server.shortModel,
                                                                                            $Server.uri,
                                                                                            $Server.ApplianceConnection)

                            [void]$_ServerReport.Add($_ComponentVersion)

                        }            

                    }

                    default
                    {

                        if ($_ServerHardwareFirmwareCompliance.componentMappingList.Count -eq 0 -and $Baseline -ne "NoPolicySet")
                        {

                            Try
                            {

                                $_ServerFirmwareComponents = Send-HPOVRequest -Uri ($Server.uri + "/firmware") -Hostname $Server.ApplianceConnection

                            }
                            
                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            ForEach ($_Component in $_ServerFirmwareComponents.components)
                            {

                                $_componentName = $_Component.componentName
                                $_componentType = 'Firmware'

                                Switch ($_componentName)
                                {

                                    {'System ROM', 'System BIOS' -match $_}
                                    {

                                        $_swKeyNameListName = $Server.romVersion.SubString(0,3)
                                        $_BaselineVersion = GetNewestVersion -Collection ($Baseline.fwComponents | Where-Object KeyNameList -contains $_swKeyNameListName)

                                        if ($_Component.componentName.Contains('System ROM') -or $_Component.componentName.Contains('System BIOS') -and -not $_Component.componentName.Contains('Backup')-and -not $_Component.componentName.Contains('Redundant'))
                                        {

                                            $_SerialNumber = $Server.serialNumber
                                            $_PartNumber   = $Server.partNumber

                                        }

                                        else
                                        {

                                            $_SerialNumber = 'N/A'
                                            $_PartNumber = 'N/A'

                                        }

                                    }

                                    'iLO'
                                    {

                                        $_swKeyNameListName = $MpModelTable.($Server.mpModel)
                                        $_BaselineVersion = GetNewestVersion -Collection ($Baseline.fwComponents | Where-Object KeyNameList -contains $_swKeyNameListName)

                                    }

                                    'Intelligent Provisioning'
                                    {

                                        $_BaselineVersion = 'N/A'

                                    }

                                    'Power Management Controller Firmware'
                                    {

                                        switch ($Server.model)
                                        {

                                            {'Gen9' -match $_}
                                            {

                                                $_swKeyNameListName = 'PowerPIC-Gen9'

                                            }

                                            {'Gen8' -match $_}
                                            {

                                                $_swKeyNameListName = 'PowerPIC-Gen8'

                                            }

                                        }

                                        $_BaselineVersion = GetNewestVersion -Collection ($Baseline.fwComponents | Where-Object KeyNameList -contains $_swKeyNameListName)

                                    }

                                    'null'
                                    {

                                        $_componentName = $_Component.componentLocation
                                        $_componentType = 'Driver'

                                    }

                                }

                                $_ComponentVersion = New-Object HPOneView.Servers.ServerHardware+Firmware ($_componentName,
                                                                                                            $_componentType,
                                                                                                            $_Component.componentVersion,
                                                                                                            $_SerialNumber,
                                                                                                            $_PartNumber,
                                                                                                            $_BaselineVersion,
                                                                                                            $_BaseLinePolicy.name,
                                                                                                            $_BaseLinePolicy.uri,
                                                                                                            $_servername,
                                                                                                            $Server.shortModel,
                                                                                                            $Server.uri,
                                                                                                            $Server.ApplianceConnection)

                                [void]$_ServerReport.Add($_ComponentVersion)

                            }

                        }

                        else
                        {

                            ForEach ($_Component in $_ServerHardwareFirmwareCompliance.componentMappingList)
                            {

                                $_componentName = $_Component.componentName
                                $_componentType = 'Firmware'

                                Switch ($_componentName)
                                {

                                    {'System ROM', 'System BIOS' -match $_}
                                    {

                                        if ($_Component.componentName.Contains('System ROM') -or $_Component.componentName.Contains('System BIOS') -and -not $_Component.componentName.Contains('Backup')-and -not $_Component.componentName.Contains('Redundant'))
                                        {

                                            $_SerialNumber = $Server.serialNumber
                                            $_PartNumber   = $Server.partNumber

                                        }

                                        else
                                        {

                                            $_SerialNumber = 'N/A'
                                            $_PartNumber = 'N/A'

                                        }

                                    }

                                    'Intelligent Provisioning'
                                    {

                                        $_BaselineVersion = 'N/A'

                                    }

                                    'null'
                                    {

                                        $_componentName = $_Component.componentLocation
                                        $_componentType = 'Driver'

                                    }

                                }
    
                                $_ComponentVersion = New-Object HPOneView.Servers.ServerHardware+Firmware ($_componentName,
                                                                                                            $_componentType,
                                                                                                            $_Component.installedVersion,
                                                                                                            $_SerialNumber,
                                                                                                            $_PartNumber,
                                                                                                            $_Component.baselineVersion,
                                                                                                            $_BaseLinePolicy.name,
                                                                                                            $_BaseLinePolicy.uri,
                                                                                                            $_servername,
                                                                                                            $Server.shortModel,
                                                                                                            $Server.uri,
                                                                                                            $Server.ApplianceConnection)
    
                                [void]$_ServerReport.Add($_ComponentVersion)
    
                            }    
                            
                        }                    

                    }

                }

            }

            # Server firmware is unmanageable based on its Server Hardware Type
            else 
            { 

                $_SerialNumber = $Server.serialNumber
                $_PartNumber   = $Server.partNumber
                
                "[{0}] Server Hardware Type does not support firmware management." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_UnmanageableServer = New-Object HPOneView.Servers.ServerHardware+Firmware ("N/A",
                                                                                            "N/A",
                                                                                            "N/A",
                                                                                            $_SerialNumber,
                                                                                            $_PartNumber,
                                                                                            "N/A",
                                                                                            "Unmanaged",
                                                                                            $null,
                                                                                            $_servername,
                                                                                            $Server.shortModel,
                                                                                            $Server.uri,
                                                                                            $Server.ApplianceConnection)
                [void]$_ServerReport.Add($_UnmanageableServer)
                
            }

        }

        else
        {

            "[{0}] Server Hardware is not in a Managed state." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_SerialNumber = $Server.serialNumber
            $_PartNumber   = $Server.partNumber

            $_UnmanageableServer = New-Object HPOneView.Servers.ServerHardware+Firmware ("N/A",
                                                                                        "N/A",
                                                                                        "N/A",
                                                                                        $_SerialNumber,
                                                                                        $_PartNumber,
                                                                                        "N/A",
                                                                                        "Unmanaged",
                                                                                        $null,
                                                                                        $_servername,
                                                                                        $Server.shortModel,
                                                                                        $Server.uri,
                                                                                        $Server.ApplianceConnection)
            [void]$_ServerReport.Add($_UnmanageableServer)

        }        

    }

    End 
    {

        Return $_ServerReport | Sort-Object Name, Component

    }

}

function Get-InterconnectFirmware 
{

    <#
        Internal-only function.
    #>


    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [PsCustomObject]$Interconnect, 

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [object]$Baseline = $Null,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Int]$ProgressID
        
    )


    Begin 
    {

        $_InterconnectReport = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        "[{0}] Processing Interconnect firmware report for: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Interconnect.name | Write-Verbose

        $_InterconnectFirmwareVersion = $Interconnect.firmwareVersion
        
        if (-not $Baseline)
        {

            "[{0}] Baseline was not provided, checking Logical Interconnect Firmware Baseline set." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                switch ($Interconnect.category)
                {

                    'sas-interconnects'
                    {

                        $_baseUri = $Interconnect.sasLogicalInterconnectUri

                    }

                    'interconnects'
                    {

                        $_baseUri = $Interconnect.logicalInterconnectUri

                    }

                }

                $_Uri = '{0}/firmware' -f $_baseUri

                $_LogicalInterconnectFirmware = Send-HPOVRequest -Uri $_Uri -Hostname $Interconnect.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_LogicalInterconnectFirmware.sppUri.ToLower() -ne 'unknown' -and -not [System.String]::IsNullOrWhiteSpace($_LogicalInterconnectFirmware.sppUri))
            {
                
                Try
                {

                    $_BaseLinePolicy = Send-HPOVRequest -Uri $_LogicalInterconnectFirmware.sppUri -Hostname $Interconnect.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                "[{0}] Logical Interconenct Firmware Baseline name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_BaseLinePolicy.name | Write-Verbose

            }

            Elseif (-not [System.String]::IsNullOrWhiteSpace($Interconnect.enclosureUri))
            {

                "[{0}] Baseline was not provided, checking Enclosure Firmware Baseline set." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_Enclosure = Send-HPOVRequest -Uri $Interconnect.enclosureUri -Hostname $Interconnect.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
            
                "[{0}] Enclosure Firmware Baseline set: {0}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Enclosure.isFwManaged | Write-Verbose 

                # Check if the Enclosure has a Firmware Baseline attached
                if ($_Enclosure.isFwManaged -and $_Enclosure.fwBaselineUri)
                { 

                    Try
                    {

                        $_BaseLinePolicy = Send-HPOVRequest -Uri $_Enclosure.fwBaselineUri -Hostname $Interconnect.ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    "[{0}] Enclosure Firmware Baseline name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_BaseLinePolicy.name | Write-Verbose

                }

                else 
                { 
            
                    "[{0}] No Baseline provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_BaselinePolicy = [PsCustomObject]@{ 
                                
                        name              = "NoPolicySet"; 
                        baselineShortName = "NoPolicySet" 
                        
                    } 
            
                }

            }

            else 
            { 
        
                "[{0}] No Baseline provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_BaselinePolicy = [PsCustomObject]@{ 
                            
                    name              = "NoPolicySet"; 
                    baselineShortName = "NoPolicySet" 
                    
                } 
        
            }

        }
        
        elseif ($Baseline -is [PSCustomObject])
        {

            if ($Baseline.baselineShortName -eq 'NoPolicySet')
            {

                "[{0}] No Baseline provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_BaselinePolicy = [PsCustomObject]@{ 
                                
                    name              = "NoPolicySet"; 
                    baselineShortName = "NoPolicySet" 
                    
                } 

            }

            elseif (($Baseline) -and ($Baseline.category -eq $ResourceCategoryEnum['Baseline'])) 
            { 
            
                "[{0}] Baseline resource passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Baseline resource name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.baselineShortName | Write-Verbose 
                "[{0}] Baseline resource uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.uri | Write-Verbose 

                $_BaselinePolicy = $Baseline.PSObject.Copy()
                
            }

            # Check to see if the wrong Object has been passed
            elseif ($null -ne $Baseline -and $Baseline.category -ne "firmware-drivers")
            { 
            
                "[{0}] Invalid Baseline resource passed. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $ExceptionMessage = "An invalid Baseline Object was passed. Expected Category type 'firmware-drivers', received '{0}' (Object Name: {1})" -f $Baseline.category, $Baseline.name
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentType InvalidArgument 'Baseline' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
            }

        }            

        elseif ($null -ne $Baseline -and $Baseline -is [String] -and $Baseline.StartsWith($ApplianceFwDriversUri))
        { 
                
            "[{0}] Baseline URI passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose 

            Try
            {

                $_BaseLinePolicy = Send-HPOVRequest -Uri $Baseline -Hostname $Server.ApplianceConnection

            }
                
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

        # Check to see if the wrong URI has been passed
        elseif ($null -ne $Baseline -and $Baseline -is [String] -and -not $Baseline.StartsWith($ApplianceBaselineRepoUri))
        { 

            "[{0}] Invalid Baseline URI passed. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $ExceptionMessage = "An invalid Baseline URI was passed. URI must start with '/rest/firmware-drivers/', received '{0}'" -f $Baseline
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentType InvalidArgument 'Baseline' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)        
                
        }

        else 
        { 
                
            "[{0}] Unknown baseline." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose 
            
        }

        if ($_BaseLinePolicy.baselineShortName -eq "NoPolicySet") 
        { 
        
            $_BaselineVer = "N/A"
            $_Compliance = "N/A"

        }

        else 
        { 

            switch ($Interconnect.enclosureType)
            {

                'C7000'
                {

                    # C-CLASS
                    # {vceth, vc8gb} HPE BladeSystem c-Class Virtual Connect Firmware, Ethernet plus 8Gb 20-port and 8/16Gb 24-port FC Edition Component for Linux
                    $_ComponentType = 'vceth'                    

                }

                default
                {

                    switch ($Interconnect.model)
                    {

                        'Virtual Connect SE 40Gb F8 Module for Synergy'
                        {

                            # {icmvc40gbf8} HPE Virtual Connect SE 40Gb F8 Module for Synergy Firmware install package
                            $_ComponentType = 'icmvc40gbf8'

                        }


                        'Virtual Connect SE 16Gb FC Module for Synergy'
                        {

                            # {icmvc16gbfc} Virtual Connect SE 16Gb FC Module for Synergy
                            $_ComponentType = 'icmvc16gbfc'

                        }

                        {'Synergy 10Gb Interconnect Link Module', 'Synergy 20Gb Interconnect Link Module' -contains $_}
                        {
                            
                            # {icmlm} Synergy 10/20 Gb Interconnect Link Module
                            $_ComponentType = 'icmlm'
                            
                        }

                        'Synergy 10Gb Pass-Thru Module'
                        {

                            # {icmpt} Synergy 10Gb Pass-Thru Module
                            $_ComponentType = 'icmpt'

                        }

                        'Synergy 12Gb SAS Connection Module'
                        {

                            # {12G SAS Conn Mod} Smart Component for HPE Synergy 12Gb SAS Connection Module Firmware
                            $_ComponentType = '12G SAS Conn Mod'

                        }

                        default
                        {

                            Throw ("{0} module not implemented." -f $Interconnect.model)

                        }

                    }

                }

            }

            $_BaselineVersions = $_BaseLinePolicy.fwComponents | Where-Object KeyNameList -contains $_ComponentType

            $_BaselineVer = GetNewestVersion -Collection $_BaselineVersions
                                
        }

        $_EnclosureDeviceReport = New-Object HPOneView.Servers.Enclosure+Firmware($Interconnect.name,
                                                                          $Interconnect.model,
                                                                          'Firmware',
                                                                          $_InterconnectFirmwareVersion,
                                                                          $Interconnect.serialNumber,
                                                                          $Interconnect.partNumber,
                                                                          $_BaselineVer,
                                                                          $_BaselinePolicy.name,
                                                                          $_BaselinePolicy.uri,
                                                                          $Interconnect.enclosureName,
                                                                          $Interconnect.enclosureUri,
                                                                          $Interconnect.ApplianceConnection)

        [void]$_InterconnectReport.Add($_EnclosureDeviceReport)

    }

    End 
    {

        Return $_InterconnectReport

    }

}

Function GetNewestVersion
{

    <#
        Internal-only function.
    #>


    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Array]$Collection

    )

    Process
    {

        if ($Collection.Count -eq 0)
        {

            # The baseline likely doesn't contain the component firmware

            Return 'N/A'

        }

        $_NewerVersion = '0.0'

        # Figure out which is the newest, and only display that if multiple ROM versions found
        foreach ($_Component in $Collection)
        {

            'Processing {0} version of {1}' -f $_Component.Version, $_Component.name | Write-Verbose

            if ($_Component.Version -ge $_NewerVersion)
            {

                $_NewerVersion = $_Component.Version
                    
            }

        }

        if ($_NewerVersion -eq '0.0')
        {

            $_NewerVersion = 'N/A'

        }

        Return $_NewerVersion

    }

}

function Enable-HPOVDeviceUid
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Server','Enclosure','Frame','Resource')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ResourceStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $_RequestCollection = [System.Collections.ArrayList]::new()

        if ($PiplineInput)
        {

            "[{0}] Pipeline Input Received." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        if ($InputObject -isnot [PSCustomObject])
        {

            $Message = 'The -Resource Parameter value is not an Object. Please use Get-HPOVServer or Get-HPOVEnclosure to provide an allowed resource object.'
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_PatchRequest = NewObject -PatchOperation

        "[{0}] Turning UID on for: {1} {{2}}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.category | Write-Verbose

        switch ($InputObject.category)
        {

            {'server-hardware', 'enclosures' -contains $_}
            {

                $_PatchRequest.op = 'replace'
                $_PatchRequest.path  = '/uidState'
                $_PatchRequest.value = 'On'

            }

            default
            {

                $Message = "The -Resource Parameter value is not a supported object, {0}. This Cmdlet only supports 'server-hardware' or 'enclosures'. Please use Get-HPOVServer or Get-HPOVEnclosure to provide an allowed resource object." -f $InputObject.category
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $Message
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        [void]$_RequestCollection.Add($_PatchRequest)

        Try
        {

            $_resp = Send-HPOVRequest $InputObject.uri PATCH $_RequestCollection -ApplianceConnection $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        [void]$_ResourceStatusCollection.Add($_resp)

    }

    End 
    {

        Return $_ResourceStatusCollection

    }

}

function Disable-HPOVDeviceUid
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Server','Enclosure','Frame','Resource')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ResourceStatusCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($ApplianceConnection.ApplianceType -ne 'Composer')
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. This Cmdlet is only supported with Synergy Composers.' -f $ApplianceConnection.Name)
            $PSCmdlet.WriteError($ErrorRecord)

        }

        $_RequestCollection = [System.Collections.ArrayList]::new()

        if ($PiplineInput)
        {

            "[{0}] Pipeline Input Received." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        if ($InputObject -isnot [PSCustomObject])
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgument InvalidArgument 'InputObject' -Message "InputObject is not a PSCustomObject."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_PatchRequest = NewObject -PatchOperation

        "[{0}] Turning UID OFF for: {1} {{2}}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.category | Write-Verbose

        switch ($InputObject.category)
        {

            {'server-hardware', 'enclosures' -contains $_}
            {

                $_PatchRequest.op = 'replace'
                $_PatchRequest.path  = '/uidState'
                $_PatchRequest.value = 'Off'

            }

            default
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidObjectCategory InvalidArgument 'InputObject' -Message "InputObject is not a supported object category. Only 'server-hardware' or 'enclosures' Synergy resources are supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        [void]$_RequestCollection.Add($_PatchRequest)

        Try
        {

            $_resp = Send-HPOVRequest $InputObject.uri PATCH $_RequestCollection -ApplianceConnection $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        [void]$_ResourceStatusCollection.Add($_resp)

    }

    End 
    {

        Return $_ResourceStatusCollection

    }

}

function ConvertTo-HPOVImageStreamerConfiguration
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('EnclosureGroup','EG')]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$UplinkSetName,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Array]$UplinkPorts = @("Enclosure1:Bay3:Q1.1", "Enclosure1:Bay3:Q2.1", "Enclosure2:Bay6:Q1.1", "Enclosure2:Bay6:Q2.1"),
        
        [Parameter (Mandatory, ParameterSetName = 'default')]
        [ValidateNotNullOrEmpty()]
        [Object]$DeploymentNetwork,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        
        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_Collection     = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        If ($ApplianceConnection.ApplianceType -ne 'Composer')
        {

            $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $ApplianceConnection.Name, $ApplianceConnection.ApplianceType
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        Try
        {

            if (-not(Get-HPOVOSDeploymentServer -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue))
            {

                $ExceptionMessage = 'The appliance {0} does not have a Deployment Server. One must be created before attempting to set an Enclosure Group and Logical Interconnect Group policy change.' -f $ApplianceConnection.name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.DeploymentServerResourceException OsDeploymentServerNotFound ObjectNotFound 'ApplianceConnect' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $MultipleAssociatedEGs = $False

        "[{0}] InputObject: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Out-String) | Write-Verbose 

        # Validate InputObject
        if ($InputObject -is [PCustomObject])
        {

            "[{0}] Processing category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose 

            if ($InputObject.category -eq 'logical-enclosure')
            {

                Try
                {

                    $InputObject = Send-HPOVRequest -Uri $InputObject.enclosureGroupUri -ApplianceConnection $InputObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

            elseif ($InputObject.category -eq 'logical-interconnect-groups')
            {

                # Check to see if the LIG is a member of other EG's via the Index?
                try
                {

                    $IndexResults = Send-HPOVRequest -Uri ('{0}?childUri={1}&name=ENCLOSURE_GROUP_TO_LOGICAL_INTERCONNECT_GROUP' -f $IndexUri, $InputObject.uri)
                    
                    $MultipleAssociatedEGs = $IndexResults.count -gt 1

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($InputObject.category -ne 'enclosure-groups')
            {

                $ErrorRecord = New-ErrorRecord
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        # Look for name?
        else
        {

            Try
            {

                $InputObject = Get-HPOVEnclosureGroup -Name $InputObject -ErrorAction Stop

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Process multiple EG's
        if ($MultipleAssociatedEGs)
        {

            $InputObject = [System.Collections.ArrayList]::new()

            "[{0}] Processing multiple Enclosure Group associations to Logical Interconnect Group" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

            ForEach ($_Item in $IndexResults)
            {

                Try
                {

                    $EnclosureGroup = Send-HPOVRequest -Uri $_Item.parentUri -Hostname $ApplianceConnection

                    [void]$InputObject.Add($EnclosureGroup)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        # Single EG
        else
        {

            "[{0}] Processing single Enclosure Group associations to Logical Interconnect Group" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
        
        }

        # Process all EG's by removing the LIG association from Bay3 and Bay6 first
        ForEach ($_EnclosureGroup in $InputObject)
        {

            # EG is already configured for Image Streamer, generate error
            if ($_EnclosureGroup.osDeploymentSettings.manageOSDeployment)
            {

                $ExceptionMessage = 'The Enclosure Group {0} is already configured for Image Streamer.' -f $_EnclosureGroup.name
                $ErrorRecord = New-ErrorRecord HPOneView.EnclosureGroupResourceException EnclosureGroupAlreadyConfigured InvalidParameter 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                # Locate LIG within EG at Frame 1, Bay 3 and Frame 2, Bay 6
                ForEach ($_LIGUri in ($_EnclosureGroup.interconnectBayMappings | Where-Object { 3,6 -contains $_.interconnectBay }))
                {

                    Try
                    {

                        $Bay3LIG = Send-HPOVRequest -Uri ($_LigUri | Where-Object interconnectBay -eq 3).logicalInterconnectGroupUri
                        $Bay6LIG = Send-HPOVRequest -Uri ($_LigUri | Where-Object interconnectBay -eq 6).logicalInterconnectGroupUri
                        $associatedig = $Bay3Lig.PSObject.Copy()

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # LIGs do not match, generate terminating error that it is not supported.
                if ($Bay3Lig.uri -ne $Bay6Lig.uri)
                {

                    $ExceptionMessage = 'The Logical Interconnect Groups assigned to Bays 3 and 6 are not the same policy (Bay3: {0}; Bay6: {1}). Image Streamer is only supported with Redundant Interconnect Modules.' -f $Bay3Lig.name,$Bay6Lig.name
                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException UnsupportedLigConfiguration InvalidOperation 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # UPDATE EG
                $ShouldProcessMessage = "Remove Logical Interconnect Group {0} from Enclosure Group on appliance '{1}'" -f $Bay3Lig.name, $InputObject.ApplianceConnection.Name

                if ($PSCmdlet.ShouldProcess($_EnclosureGroup.name, $ShouldProcessMessage)) 
                {

                    # Copy object to then update copy, retain original for use later
                    $UpdateEg = $_EnclosureGroup.PSObject.Copy()

                    # Strip out Bays 3 and 6 from Interconnect Bay Mappings
                    $UpdateEg.interconnectBayMappings | Where-Object { 3,6 -notcontains $_.interconnectBay }

                    # Update EG object on appliance
                    Try
                    {

                        $Results = Send-HPOVRequest -Uri $UpdateEg.uri -Method PUT -Body $UpdateEg -ApplianceConnection $UpdateEg.ApplianceConnection | Wait-HPOVTaskComplete

                        [void]$_Collection.Add($UpdateEg)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    if ($Results.taskState -ne 'Completed')
                    {

                        $ExceptionMessage = 'The Logical Interconnect Groups update did not complete successfully: {0}' -f [String]::Join(' ', $Results.taskErrors.message)
                        $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidUpdateLigResult InvalidResult 'InputObject' -TargetType $_EnclosureGroup.GetType().Name -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                elseif ($PSBoundParameters['WhatIf'])
                {

                    "[{0}] User passed -WhatIf parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }

            # Update LIG with new Uplink Set
            $ShouldProcessMessage = "Add new Image Streamer Uplink Set {0}" -f $UplinkSetName

            if ($PSCmdlet.ShouldProcess($associatedig.name, $ShouldProcessMessage)) 
            {

                $UplinkSetParams = @{

                    Name        = $UplinkSetName;
                    Type        = 'ImageStreamer';
                    InputObject = $Bay3Lig;
                    Networks    = $DeploymentNetwork;
                    UplinkPorts = $UplinkPorts

                }

                Try
                {

                    $i3SUplinkSetResults = New-HPOVUplinkSet @UplinkSetParams -ApplianceConnection $InputObject.ApplianceConnection | Wait-HPOVTaskComplete

                }

                Catch
                {

                    $PSCmdlet.ThrowterminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] User passed -WhatIf parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            # Update each EG with Deployment Network settings and Bay3 and Bay6 LIG mapping;
            ForEach ($_EnclosureGroupToUpdate in $InputObject)
            {

                # Get EG resource to get updated eTag and modifiedDate values
                Try
                {

                    $UpdatedEg = Get-HPOVEnclosureGroup -Name $_EnclosureGroupToUpdate.name -ApplianceConnection $_EnclosureGroupToUpdate.ApplianceConnection -ErrorAction Stop

                }

                Catch
                {

                    $PSCmdlet.ThrowterminatingError($_)

                }
                
                # Update original object with new eTag and modifiedDate values
                $_EnclosureGroupToUpdate.eTag         = $UpdatedEg.eTag.Copy()
                $_EnclosureGroupToUpdate.modifiedDate = $UpdatedEg.modifiedDate.Copy()
                
                Try
                {

                    Send-HPOVRequest -Uri $_EnclosureGroupToUpdate.uri -Method PUT -Body $_EnclosureGroupToUpdate -ApplianceConnection $_EnclosureGroupToUpdate.ApplianceConnection | Wait-HPOVTaskComplete

                }

                Catch
                {

                    $PSCmdlet.ThrowterminatingError($_)

                }

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Show-HPOVUtilization
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Resource')]
        [Object]$InputObject,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        # Throw "Not implemented"

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Key off of ApplianceConnection for Pipeline Input
        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            Try
            {

                $Resource.ApplianceConnection = Test-HPOVAuth $Resource.ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $errorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($errorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_resource in $InputObject)
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Processing object: {0}" -f $_resource.name | Write-Verbose 

            switch ($_resource.category)
            {

                ${ResourceCategoryEnum.ServerProfile}
                {

                    $_uri = $_resource.serverHardwareUri + '/utilization'

                }

                'server-hardware'
                {

                    $_uri = $_resource.uri + '/utilization'

                }

            }

            # Check to see if the resource is eligable for performance monitoring.

            Try
            {

                $_UtilizationData = Send-HPOVRequest -uri $_uri -Hostname $_resource.ApplianceConnection.Name

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            switch ($_resource.category)
            {

                'server-hardware'
                {

                    $_UtilizationObj = New-Object HPOneView.ServerUtilization($_resource.name, $_resource.uri, [HPOneView.Library.ApplianceConnection]$_resource.ApplianceConnection)

                }

                'enclosures'
                {

                    $_UtilizationObj = New-Object HPOneView.EnclosureUtilization($_resource.name, $_resource.uri, [HPOneView.Library.ApplianceConnection]$_resource.ApplianceConnection)

                }

                default
                {

                    # Resource is unsupported, generate error

                }

            }

            ForEach ($_item in $_UtilizationData.metricList)
            {
            
                switch ($_item.metricName)
                {
            
                    'AmbientTemperature'
                    {
            
                        $_total = 0
                        $_count = 0
                        $_item.metricSamples | ForEach-Object { $_[1] | ForEach-Object { $_total += $_; $_count++ } }
            
                        $_UtilizationObj.AmbientTemperatureAverage = [Math]::Round(($_total / $_count), 2)
                        $_UtilizationObj.AmbientTemperature = $_item.metricCapacity
                    
                    }
            
                    'AveragePower'
                    {
            
                        $_total = 0
                        $_count = 0
                        ($_item.metricSamples | ForEach-Object { $_[1] | ForEach-Object { $_total += $_; $_count++ } })
                    
                        $_UtilizationObj.PowerAverage = [Math]::Round(($_total / $_count), 2)
                        
                    }

                    'CpuAverageFreq'
                    {

                        $_total = 0
                        $_count = 0
                        ($_item.metricSamples | ForEach-Object { $_[1] | ForEach-Object { $_total += $_; $_count++ } })

                        $_UtilizationObj.CpuAverage = [Math]::Round(($_total / $_count), 2)

                    }

                    'CpuUtilization'
                    {


                    }
            
                    'PeakPower'
                    {
                    
                        $_PeakValue = 0
            
                        ForEach ($_Sample in $_item.metricSamples)
                        {
            
            
                            if ($_Sample[1] -gt $_PeakValue)
                            {
            
                                $_PeakValue = $_Sample[1]
            
                            }
            
                        }
            
                        $_UtilizationObj.PowerPeak = $_PeakValue
                    
                    }
            
                }
            
                
                
            }

            $_UtilizationObj

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Storage Systems and Volume Management:
#

function Get-HPOVStorageSystem 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Name")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [ValidateNotNullOrEmpty()]
        [Alias ('SystemName')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "Serial")]
        [ValidateNotNullOrEmpty()]
        [Alias ('SN')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ParameterSetName = "Serial")]
        [ValidateSet ('StoreVirtual', 'StoreServ')]
        [String]$Family,

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ParameterSetName = "Serial")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ParameterSetName = "Serial")]
        [Alias ('Report')]
        [Switch]$List

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if ($PSBoundParameters['List'])
        {

            Write-Warning "The -List parameter has been deprecated."

        }

        $_StorageSystemCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $uri = $StorageSystemsUri + '?sort:asc'

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($Name)
            { 

                "[{0}] Filtering for Name property" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_method = 'eq'

                if ($Name.Contains('*'))
                {

                    $Name = $Name.Replace("*","%25").Replace("&","%26") 

                    $_method = 'matches'

                }
                
                
                $uri += "&filter=name {0} '{1}'" -f $_method, $Name
                        
            }

            elseif ($Hostname)
            {

                "[{0}] Filtering for Hostname property" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_method = 'eq'

                if ($Hostname.Contains('*'))
                {

                    $Hostname = $Hostname.Replace("*","%25").Replace("&","%26") 

                    $_method = 'matches'

                }

                $uri += "&filter=hostname {0} '{1}'" -f $_method, $Hostname

            }

            if ($Family)
            {

                $uri += "&filter=family EQ '{0}'" -f $Family

            }

            "[{0}] Getting list of Storage Systems" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_StorageSystems = Send-HPOVRequest -Uri $uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($SerialNumber)
            {

                [Array]$_StorageSystems.members = $_StorageSystems.members | Where-Object { $_.deviceSpecificAttributes.serialNumber -eq $SerialNumber }

            }

            # Generate Terminating Error if resource not found
            if (-not($_StorageSystems.members.Count -gt 0) -and ($Name -or $SerialNumber -or $Hostname)) 
            {
                
                if ($Name) 
                { 
                    
                    "[{0}] Woops! No '$Name' Storage System found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $ExceptionMessage = "No Storage System with '{0}' system name found. Please check the name or use Add-HPOVStorageSystem to add the Storage System." -f $Name
                        
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageSystemResourceException StorageSystemResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage

                }

                elseif ($Hostname) 
                { 
                    
                    "[{0}] Woops! No '$Hostname' Storage System found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $ExceptionMessage = "No Storage System with '{0}' system name found. Please check the name or use Add-HPOVStorageSystem to add the Storage System." -f $Hostname
                        
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageSystemResourceException StorageSystemResourceNotFound ObjectNotFound 'Hostname' -Message $ExceptionMessage

                }

                elseif ($SerialNumber) 
                { 
                    
                    "[{0}] Woops! No Storage System with '$SerialNumber' serial number found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $ExceptionMessage = "No Storage System with '{0}' serial number found. Please check the name or use Add-HPOVStorageSystem to add the Storage System." -f $SerialNumber
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageSystemResourceException StorageSystemResourceNotFound ObjectNotFound 'SerialNumber' -Message $ExceptionMessage

                }
                    
                # Generate Terminating Error
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                $_StorageSystems.members | ForEach-Object {

                    $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System')

                    if ($_.ports)
                    {

                        $_.ports | ForEach-Object { 
                            
                            # This is temporary
                            Add-Member -InputObject $_ -NotePropertyName ApplianceConnection -NotePropertyValue $_.ApplianceConnection

                            $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System.Port') 

                        }

                    }

                    if ($_.deviceSpecificAttributes.discoverdPools) { $_.deviceSpecificAttributes.discoverdPools | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System.Pool')} }
                    if ($_.deviceSpecificAttributes.managedPools) { $_.deviceSpecificAttributes.managedPools | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System.Pool')} }

                    $_

                }    

            }    

        }
         
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVStorageSystem 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Name','StorageSystem')]
        [Object]$InputObject,
        
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }    

        $_StorageSystemRefreshCollection = [System.Collections.ArrayList]::new()
    
    }

    Process 
    { 

        ForEach ($_system in $InputObject) 
        {

            switch ($_system.gettype().name) 
            {

                "String" 
                { 
                    

                    "[{0}] System Name was provided, calling Get-HPOVStorageSystem." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_system = Get-HPOVStorageSystem $_system

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

                "PSCustomObject" 
                {
                
                    if ($_system.category -eq "storage-systems") 
                    {
                    
                        "[{0}] Storage System resource object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Storage System Name: {0}" -f $_system.name | Write-Verbose
                        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Storage System URI: {0}"  -f $_system.uri | Write-Verbose

                    }

                    else 
                    {

                        # Wrong category, generate error
                        $ErrorRecord = New-ErrorRecord HPOneView.StorageSystemResourceException WrongCategoryType InvalidResult 'InputObject' -TargetType 'PSObject' -Message ("The '{0}' is the wrong value. Only 'storage-systems' category is allowed. Please check the value and try again." -f $_system.category)#-verbose
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                default 
                {                         
                    
                    # Wrong category, generate error
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageSystemResourceException UnsupportedDataType InvalidArgument 'InputObject' -TargetType $_system.GetType().Name -Message ("The {0} is unsupported. Only [System.String], [System.Array] of [System.String] or [System.Management.Automation.PSCustomObject] are allowed. Please check the value and try again." -f $_system.Gettype().Name )
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                }

            }

            # Update object to refresh state
            $_system.requestingRefresh = $true

            Try
            {

                $_results = Send-HPOVRequest -uri $_system.uri -Method PUT -Body $_system -Hostname $_system.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            [void]$_StorageSystemRefreshCollection.Add($_results)

        }
   
    }

    End 
    {

        Return $_StorageSystemRefreshCollection

    }

}

function Add-HPOVStorageSystem 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'StoreServe')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory = $False, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory = $False, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,
         
        [Parameter (Mandatory = $False, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory = $False, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Mandatory = $False, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory = $False, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory = $false, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateSet ('StoreServ', 'StoreVirtual', 'Nimble')]
        [String]$Family = 'StoreServ',

        [Parameter (Mandatory = $false, ParameterSetName = 'StoreServe')]
        [ValidateNotNullOrEmpty()]
        [String]$Domain = 'NO DOMAIN',

        [Parameter (Mandatory = $false, ParameterSetName = 'StoreServe')]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Ports,

        [Parameter (Mandatory, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$VIPS,

        [Parameter (Mandatory = $false, ParameterSetName = 'StoreServe')]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$PortGroups,

        [Parameter (Mandatory = $false, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory = $false, ParameterSetName = 'StoreVirtualOrNimble')]
        [Switch]$ShowSystemDetails,

        [Parameter (Mandatory = $false, ParameterSetName = 'StoreServe')]
        [Parameter (Mandatory = $false, ParameterSetName = 'StoreVirtualOrNimble')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

        if ($Password -is [SecureString])
        {

            $Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        if ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        if (-not($PSBoundParameters['Credential']) -and -not($PSBoundParameters['Username']))
        {

            $ExceptionMessage = "Credentials are required in order to add a storage system. Please use either the -Credential or -Username parameter to supply a valid account to authenticate with."
            $ErrorRecord = New-ErrorRecord InvalidOperationException MissingCredentialParameter InvalidArgument 'Auth' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            $ExceptionMessage = "Credentials are required in order to add a storage system. Please use the Password parameter to supply a String or SecureString value. Or use the Credential parameter to supply a PSCredential object."
            $ErrorRecord = New-ErrorRecord InvalidOperationException MissingPasswordParameter InvalidArgument 'Password' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Will need to re-evaluate this statement when Nimble FC support is added
        if ((-not $PSBoundParameters['VIPS']) -and 'Nimble', 'StoreVirtual' -Contains $Family)
        {

            $ExceptionMessage = "Adding a StoreVirtual resource requires you to provide the VIP or VIPS and associated Ethernet Network."
            $ErrorRecord = New-ErrorRecord InvalidOperationException MissingVIPSParameter InvalidArgument 'VIPS' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            "[{0}] Processing appliance '{1}' (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_storagesystemcredentials = NewObject -StorageSystemCredentials

            $_storagesystemcredentials.hostname = $hostname
            $_storagesystemcredentials.username = $username
            $_storagesystemcredentials.password = $password
            $_storagesystemcredentials.family   = $StorageSystemFamilyTypeEnum[$Family]

            Try
            {

                $_storageSystemDiscoveryTask = Send-HPOVRequest -Uri $StorageSystemsUri -Method POST -Body $_storagesystemcredentials -Hostname $_appliance.Name | Wait-HPOVTaskComplete

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }            

            if ($_storageSystemDiscoveryTask.taskState -eq "Completed") 
            {

                Try
                {
                    
                    $_connectedStorageSystem = Send-HPOVRequest -Uri $_storageSystemDiscoveryTask.associatedResource.resourceUri -Hostname $_appliance.Name
                
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }        

                "[{0}] Processing '{1}' Storage System." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_connectedStorageSystem.name | Write-Verbose

                $_connectedStorageSystem.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System')

                # Display Storage System details
                if ($ShowSystemDetails) 
                { 
                    
                    $_connectedStorageSystem | Out-Host 
                
                }
                
                if ($_connectedStorageSystem.deviceSpecificAttributes.discoveredPools)
                {

                    $_connectedStorageSystem.deviceSpecificAttributes.discoveredPools | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System.DiscoveredPool') 

                    }

                    # Display Storage System Unmanaged Pool details
                    if ($ShowSystemDetails) 
                    { 
                        
                        $_connectedStorageSystem.deviceSpecificAttributes.discoveredPools | Sort-Object domain,name | Out-Host 
                    
                    }

                }

                if ($_connectedStorageSystem.ports)
                {

                    ForEach ($_port in $_connectedStorageSystem.ports)
                    {
                        
                        # This is temporary
                        Add-Member -InputObject $_port -NotePropertyName ApplianceConnection -NotePropertyValue $_connectedStorageSystem.ApplianceConnection

                        $_port.PSObject.TypeNames.Insert(0,'HPOneView.Storage.System.Port') 

                    }

                    # Display Storage System Unmanaged Port details
                    if ($ShowSystemDetails) 
                    { 
                        
                        $_connectedStorageSystem.ports | Out-Host 
                                        
                    }
                    
                }

                # Check if ISCSI paramset first, and handle ports
                # if ($PSCmdlet.ParameterSetName -eq 'StoreVirtualOrNimble' -or $Family -eq 'StoreVirtual')
                if ($PSCmdlet.ParameterSetName -eq 'StoreVirtualOrNimble')
                {

                    ForEach ($_VIP in $VIPS.GetEnumerator())
                    {

                        if ($null -eq $_VIP.Value)
                        {

                            Try
                            {
                                
                                CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                            
                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            $ExceptionMessage = "The associated Network to the provided VIP {0} is a null value." -f $_VIP.Name
                            $ErrorRecord = New-ErrorRecord InvalidOperationException NullVIPNetwork InvalidArgument 'VIPS' -TargetType 'VIPNetwork' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Validate the Network associated with the VIP is an Ethernet resource
                        if ($_VIP.Value.category -ne $ResourceCategoryEnum.EthernetNetwork)
                        {

                            Try
                            {
                                
                                CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                            
                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            $ExceptionMessage = "The provided VIP {0} and associated Network {1} is not an allowed Ethernet network resource." -f $_VIP.Name, $_VIP.Value.name
                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidVIPNetwork InvalidArgument 'VIPS' -TargetType $VIPS.GetType().Name -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        if ($_connectedStorageSystem.ports | Where-Object name -eq $_VIP.Name)
                        {

                            $_StoragePort = ($_connectedStorageSystem.ports | Where-Object name -eq $_VIP.Name).PSObject.Copy()
                            $_IndexOf     = $_connectedStorageSystem.ports.name.IndexOf($_StoragePort.name)

                        }
                        
                        else
                        {

                            Try
                            {
                                
                                CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                            
                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            $ExceptionMessage = "The provided VIP {0} name was not found to be present on the {1} system: {2}." -f $_VIP.Name, [String]::Join(', ', $Family, $_connectedStorageSystem.ports.name)
                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidVIPName InvalidArgument 'VIPS' -TargetType $VIPS.GetType().Name -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_StoragePort.expectedNetworkUri  = $_VIP.Value.uri
                        $_StoragePort.expectedNetworkName = $_VIP.Value.name
                        $_StoragePort.mode                = 'Managed'

                        $_connectedStorageSystem.ports[$_IndexOf] = $_StoragePort

                    }

                }

                else
                {

                    # Handle Host Port configuration
                    if ($PSBoundParameters['Ports'])
                    {

                        ForEach ($_port in $Ports.GetEnumerator())
                        {

                            "[{0}] Processing '{1}' Port" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_port.name | Write-Verbose

                            if ($_connectedStorageSystem.ports | Where-Object name -eq $_port.Name)
                            {

                                $_StoragePort = ($_connectedStorageSystem.ports | Where-Object name -eq $_port.Name).PSObject.Copy()
                                $_IndexOf     = $_connectedStorageSystem.ports.name.IndexOf($_StoragePort.name)

                                "[{0}] Found port: '{1}' [{2}]" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePort.Name, $_IndexOf | Write-Verbose

                            }
                            
                            else
                            {

                                "[{0}] Cleaning up storage system" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                Try
                                {

                                    CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem

                                }
                                
                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }        

                                $ExceptionMessage = "The provided host port {0} name was not found to be present on the StoreServ system. Available host ports are: {1}." -f $_port.Name, [String]::Join(', ', $_connectedStorageSystem.ports.name)
                                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidVIPName InvalidArgument 'Ports' -TargetType $Ports.GetType().Name -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            # First get the network. Will error if network does not exist
                            switch ($_port.value.GetType().Name)
                            {

                                'String'
                                {
                                
                                    if ($_port.value -ne 'Auto' -and $null -ne $_port.value)
                                    {

                                        Try
                                        {

                                            '[{0}] Looking in idex for {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_port.value | Write-Verbose

                                            $uri = '{0}?filter=name:"{1}"&category:fc-networks&category:fcoe-networks' -f $IndexUri, $_port.value 
                                            
                                            $_resp = Send-HPOVRequest -Uri $uri -ApplianceConnection $_appliance.Name

                                        }

                                        Catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                        # Error, as we couldn't find a unique FC/FCoE resource from the name via the Index
                                        if ($_resp.count -gt 1)
                                        {

                                            Try
                                            {
                                                
                                                CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                                            
                                            }

                                            Catch
                                            {

                                                $PSCmdlet.ThrowTerminatingError($_)

                                            }

                                            $Message     = "The provided Storage Port Network Resource name {0} was found via the index as the name of {1} resources. Please make sure you are specifying a unique FC or FCoE resource name." -f $_port.value, $_resp.count 
                                            $ErrorRecord = New-ErrorRecord InvalidOperationException NonUniqueStoragePortFabricName InvalidResult 'Ports' -TargetType $Ports.GetType().Name -Message $Message
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                        }

                                        elseif ($_resp.count -eq 0)
                                        {

                                            Try
                                            {
                                                
                                                CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                                            
                                            }

                                            Catch
                                            {

                                                $PSCmdlet.ThrowTerminatingError($_)

                                            }

                                            $Message     = "The provided Storage Port Network Resource name {0} was not found via the index. Please verify the FC or FCoE Network exists." -f $_port.Value
                                            $ErrorRecord = New-ErrorRecord InvalidOperationException StorageSystemPortNetworkNotFound ObjectNotFound 'Ports' -TargetType $Ports.GetType().Name -Message $Message
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                        }

                                        Try
                                        {

                                            '[{0}] Getting full network object {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_port.value | Write-Verbose

                                            $_sNet = Send-HPOVRequest -Uri $_resp.members.uri

                                        }
                                        
                                        Catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                    }
                                    
                                    else 
                                    {
                                    
                                        $_snet = [PScustomObject]@{

                                            expectedNetorkUri = 'Auto';
                                            name              = 'Auto';

                                        }

                                    }
                                
                                }

                                'PSCustomObject'
                                {

                                    if ('fc-networks', 'fcoe-networks' -contains $_port.value.category)
                                    {

                                        $_snet = [PScustomObject]@{

                                            expectedNetorkUri = $_port.value.uri;
                                            name              = $_port.value.name

                                        }

                                    }

                                    elseif ($_port.value.category -eq 'fc-sans')
                                    {

                                        $_snet = [PScustomObject]@{

                                            expectedNetorkUri = $_port.value.associatedNetworks.uri;
                                            name              = $_port.value.associatedNetworks.name

                                        }
                                        
                                    }

                                }

                                default
                                {

                                    Try
                                    {
                                        
                                        CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                                    
                                    }

                                    Catch
                                    {

                                        $PSCmdlet.ThrowTerminatingError($_)

                                    }

                                    $Message     = "The provided Storage Port Network value is not a supported object type, {0}. Please verify the FC or FCoE Network exists." -f $_port.value.GetType().FullName
                                    $ErrorRecord = New-ErrorRecord InvalidOperationException StorageSystemPortNetworkNotFound ObjectNotFound 'Ports' -TargetType $Ports.GetType().Name -Message $Message
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                            }                    

                            # Update the ports Expected SAN/Network property
                            if ($_sNet.expectedNetorkUri -eq 'Auto' -and $null -eq $_StoragePort.actualSanUri)
                            {

                                $_StoragePort.mode = 'AutoSelectExpectedSan'

                            }

                            elseif ($_sNet.expectedNetorkUri -ne 'Auto' -and $null -eq $_StoragePort.actualSanUri)
                            {

                                $_StoragePort.expectedNetworkUri  = $_sNet.expectedNetorkUri
                                $_StoragePort.expectedNetworkName = $_sNet.name
                                $_StoragePort.mode                = 'Managed'

                            }

                            if ($PSBoundParameters['PortGroups'])
                            {

                                if ($PortGroups.Get_Item($_port.Name))
                                {

                                    "[{0}] Found '{1}' Port Group for '{2}' port." -f $MyInvocation.InvocationName.ToString().ToUpper(), $PortGroups.Get_Item($_port.Name), $_port.Name | Write-Verbose

                                    $_StoragePort.groupName = $PortGroups.Get_Item($_port.Name)

                                    # Remove the PortGroup item from the Hashtable so we can Process left overs later
                                    $PortGroups.Remove($_port.Name)

                                }

                            }

                            $_connectedStorageSystem.ports[$_IndexOf] = $_StoragePort
                            
                        }

                    }

                    # Process any of the leftover portgroup collection
                    if ($PortGroups)
                    {

                        "[{0}] {1} PortGroups remain to be configured." -f $MyInvocation.InvocationName.ToString().ToUpper(), $PortGroups.Count | Write-Verbose

                        ForEach ($_pg in $PortGroups.GetEnumerator())
                        {

                            "[{0}] Processing {1} Port for PortGroup assignment." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pg.Name, $_pg.Value | Write-Verbose

                            if ($_connectedStorageSystem.ports | Where-Object name -eq $_pg.Name)
                            {

                                $_port = $_connectedStorageSystem.ports | Where-Object name -eq $_pg.Name

                                "[{0}] Found {1} -> {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pg.Name, $_pg.Value | Write-Verbose

                                $_connectedStorageSystem.ports[($_connectedStorageSystem.ports.IndexOf($_port))].groupName = $_pg.Value

                            }

                            else
                            {

                                "[{0}] {1} was not found in the unmanagedPorts collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pg.Name | Write-Verbose

                            }

                        }

                    }            

                    # Validate the $Domain Parameter exists in the list of unmanaged domains returned in the connect call
                    if ($_connectedStorageSystem.deviceSpecificAttributes.discoveredDomains -ccontains $Domain)                
                    {

                        "[{0}] Found Virtual Domain '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Domain| Write-Verbose

                        # The domain exists, update the managedDomain property
                        $_connectedStorageSystem.deviceSpecificAttributes.managedDomain = $_connectedstoragesystem.deviceSpecificAttributes.discoveredDomains | Where-Object { $_ -eq $Domain }

                        [Array]$_connectedStorageSystem.deviceSpecificAttributes.discoveredDomains = @($_connectedStorageSystem.deviceSpecificAttributes.discoveredDomains | Where-Object { $_ -ne $Domain })

                    }

                    else 
                    {

                        "[{0}] Domain '{1}' not found (name is Case Sensitive). Cleaning up." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Domain | Write-Verbose

                        Try
                        {
                            
                            CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                        
                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $ExceptionMessage = "Storage Domain '{0}' not found (name is Case Sensitive). Please check the storage domain exist on the storage system." -f $Domain
                        $ErrorRecord = New-ErrorRecord InvalidOperationException StorageDomainResourceNotFound ObjectNotFound 'Domain' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            else 
            {

                # ERROR
                $_connectedStorageSystem | Out-Host

                if ($_storageSystemDiscoveryTask.taskErrors.errorCode -eq 'STRM_RESOURCE_ALREADY_PRESENT' -or -not $_storageSystemDiscoveryTask.associatedResource.resourceUri)
                {

                    "[{0}] {1} {2} {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_storageSystemDiscoveryTask.taskErrors.details, $_storageSystemDiscoveryTask.taskErrors.recommEndedActions, $_storageSystemDiscoveryTask.taskErrors.errorCode| Write-Verbose

                    $ErrorRecord = New-ErrorRecord InvalidOperationException $_storageSystemDiscoveryTask.taskErrors[0].errorCode InvalidResult 'StoragSystem' -Message ($_storageSystemDiscoveryTask.taskErrors[0].message + ' ' + $_storageSystemDiscoveryTask.taskErrors[0].recommEndedActions)
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else
                {

                    "[{0}] Task error occurred. Cleaning Up." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {
                        
                        CleanUpStorageSystemOnError -InputObject $_connectedStorageSystem
                    
                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }    

                    "[{0}] Generating error message." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    $ErrorRecord = New-ErrorRecord InvalidOperationException $_storageSystemDiscoveryTask.taskErrors[0].errorCode InvalidResult 'Add-HPOVStorageSystem' -Message "$($_storageSystemDiscoveryTask.taskErrors[0].message)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            "[{0}] Sending request to finalize adding Storage System to appliance" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $task = Send-HPOVRequest -Uri $_connectedStorageSystem.uri -Method PUT -Body $_connectedStorageSystem -Hostname $_appliance.Name

            }

            Catch
            {
                
                $task = $null
                
                $PSCmdlet.ThrowTerminatingError($_)

            }            

            if ($PSBoundParameters['Async'])
            {

                $task

            }

            else
            {

                $task | Wait-HPOVTaskComplete

            }

        }
        
    }

    End 
    {

        '{0} Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }
   
}

# Helper function
function CleanUpStorageSystemOnError
{

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        $InputObject

        # [Parameter (Mandatory, ParameterSetName = "default")]
        # [ValidateNotNullOrEmpty()]
        # [String]$Uri,

        # [Parameter (Mandatory, ParameterSetName = "default")]
        # [ValidateNotNullOrEmpty()]
        # [HPOneView.Library.ApplianceConnection]$ApplianceConnection

    )


    Try
    {

        $reply = Send-HPOVRequest -Uri $InputObject.uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection | Wait-HPOVTaskComplete

    }
    
    Catch
    {

        $PSCmdlet.ThrowTerminatingError($_)

    }

}

function Remove-HPOVStorageSystem 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name","StorageSystem")]
        [object]$InputObject,

        [Parameter (Mandatory = $false)]
        [Switch]$force,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_StorageSystemCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Storage System Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('storage-systems' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message "The Storage System resource object provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_StorageSystemCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message "The Storage System resource object is not an expected category type [$($InputObject.category)]. The allowed resource category type is 'storage-systems'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing Storage System Name $($StorageSystem)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_StorageSystem = Get-HPOVStorageSystem $InputObject -ApplianceConnection $_appliance

                    $_StorageSystem | ForEach-Object {

                        [void]$_StorageSystemCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Processing $($_StorageSystemCollection.count) Storage System object resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Storage Resources
        ForEach ($_storagesystem in $_StorageSystemCollection)
        {

            if ($PSCmdlet.ShouldProcess($_storagesystem.ApplianceConnection.Name,"Remove Storage System '$($_storagesystem.name)' from appliance")) 
            {

                "[{0}] Removing Storage System '$($_storagesystem.name)' from appliance '$($_storagesystem.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($PSboundParameters['force'])
                {

                    $_storagesystem.uri += "?force=true"

                }

                Try
                {

                    Send-HPOVRequest -Uri $_storagesystem.Uri -Method DELETE -Hostname $_storagesystem.ApplianceConnection.Name -AddHeader @{'If-Match' = '*'}

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Show-HPOVStorageSystemPerformancePolicy
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    [OutputType ([HPOneView.Storage.PerformancePolicy])]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [object]$InputObject,

        [Parameter (Mandatory = $false)]
        [String]$Name

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

    }

    Process 
    {

        # Validate the provided inputobject is a Numble class storage system
        if ($InputObject.family -ne 'Nimble')
        {

            $ExceptionMessage = "The provided InputObject is not a Nimble storage system."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidInputObjectParameter InvalidOperation 'InputObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($PSBoundParameters['Name'])
        {

            $_PerformancePolicies = $InputObject.deviceSpecificAttributes.performancePolicies | ? name -eq $Name

        }
        
        else
        {

            $_PerformancePolicies = $InputObject.deviceSpecificAttributes.performancePolicies

        }

        ForEach ($_performancePolicy in $_PerformancePolicies)
        {

            New-Object HPOneView.Storage.PerformancePolicy($_performancePolicy.id,
                                                           $_performancePolicy.name,
                                                           $_performancePolicy.isCached,
                                                           $_performancePolicy.blockSize,
                                                           $_performancePolicy.spacePolicy,
                                                           $_performancePolicy.isCompressed,
                                                           $_performancePolicy.applicationCategory,
                                                           $InputObject.name,
                                                           $InputObject.uri,
                                                           $InputObject.ApplianceConnection)
        }

    }

    End 
    {

        '{0} Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVStoragePool 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    [OutputType ([HPOneView.Storage.StoragePool])]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('pool', 'PoolName')]
        [String]$Name,

        [Parameter (Mandatory = $false, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('systemName', 'system')]
        [object]$StorageSystem,    

        [Parameter (Mandatory = $false)]
        [Switch]$Managed,

        [Parameter (Mandatory = $false)]
        [Switch]$Unmanaged,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $colStoragePools = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        # Check if StorageSystem is a PSCustomObject
        if ($StorageSystem -is [PSCustomObject] -and $StorageSystem.category -eq 'storage-systems')
        {

            "[{0}] StorageSystem Object provided. Using ApplianceConnection property of object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ApplianceConnection = $ConnectedSessions | Where-Object Name -eq $StorageSystem.ApplianceConnection.Name

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    "[{0}] Getting list of Scope names to pass into query." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                "[{0}] Filtering for Label: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Label | Write-Verbose

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            if ($PSBoundParameters['Managed'])
            {
            
                "[{0}] Filtering for unmanaged pools." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Void]$_Query.Add("isManaged:'true'")

            }

            if ($PSBoundParameters['Unmanaged'])
            {
            
                "[{0}] Filtering for unmanaged pools." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Void]$_Query.Add("isManaged:'false'")

            }

            if ($PSBoundParameters['StorageSystem'])
            {

                if ($StorageSystem -is [String] -and (-not $StorageSystem.startswith($StorageSystemsUri)))
                { 
        
                    "[{0}] Storage system name was provided: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageSystem | Write-Verbose

                    Try
                    {

                        $StorageSystem = Get-HPOVStorageSystem -SystemName $StorageSystem -ApplianceConnection $_appliance.Name -ErrorAction Stop

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
            
                }

                elseif ($StorageSystem -is [PsCustomObject] -and $StorageSystem.category -eq "storage-systems") 
                { 
        
                    "[{0}] StorageSystem Object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] StorageSystem Name: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageSystem.name | Write-Verbose
                    "[{0}] StorageSystem Uri: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageSystem.uri | Write-Verbose

                }

                [Void]$_Query.Add(("storageSystemUri:'{0}'" -f $StorageSystem.uri))

            }

            $_Category = 'category=storage-pools'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                "[{0}] {1} returned objects" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ResourcesFromIndexCol.Count | Write-Verbose 

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Look for empty return and write error
            if ($_ResourcesFromIndexCol.Count -gt 0)
            {
            
                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    "[{0}] Adding Storage System '{1}' to collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.name | Write-Verbose 

                    # StoreServ pool
                    if ($_member.deviceSpecificAttributes.domain)
                    {

                        $_DeviceAttrib = new-object HPOneView.Storage.StoreServeDeviceSpecificAttributes($_member.deviceSpecificAttributes.uuid, 
                                                                                                         $_member.deviceSpecificAttributes.domain, 
                                                                                                         $_member.deviceSpecificAttributes.deviceType, 
                                                                                                         $_member.deviceSpecificAttributes.deviceSpeed, 
                                                                                                         $_member.deviceSpecificAttributes.supportedRAIDLevel, 
                                                                                                         $_member.deviceSpecificAttributes.capacityLimit, 
                                                                                                         $_member.deviceSpecificAttributes.capacityWarningLimit,
                                                                                                         (New-Object HPOneView.Storage.AllocatedCapacity($_member.deviceSpecificAttributes.allocatedCapacity.totalAllocatedCapacity, $_member.deviceSpecificAttributes.allocatedCapacity.volumeAllocatedCapacity,$_member.deviceSpecificAttributes.allocatedCapacity.snapshotAllocatedCapacity)))

                    }

                    elseif ($_member.deviceSpecificAttributes.freePinnableCacheCapacity)
                    {

                        $_Folders = New-Object 'System.Collections.Generic.List[HPOneView.Storage.NimbleFolder]'

                        ForEach ($_folder in $_member.deviceSpecificAttributes.folders)
                        {

                            $_Folders.Add((New-Object HPOneView.Storage.NimbleFolder($_folder.id, $_folder.name)))

                        }

                        $_DeviceAttrib = new-object HPOneView.Storage.NimbleDeviceSpecificAttributes($_Folders, 
                                                                                                     $_member.deviceSpecificAttributes.deviceId, 
                                                                                                     $_member.deviceSpecificAttributes.isDeduplicationCapable, 
                                                                                                     $_member.deviceSpecificAttributes.freePinnableCacheCapacity)

                    }

                    # StoreVirtual pool
                    else
                    {

                        $_VolumeCreationSpacePolicyCol = New-Object 'System.Collections.Generic.List[HPOneView.Storage.VolumeCreationSpace]'

                        ForEach ($_Policy in $_member.deviceSpecificAttributes.volumeCreationSpace)
                        {

                            $_VolumeCreationSpacePolicyCol.Add((New-Object HPOneView.Storage.VolumeCreationSpace($_Policy.availableSpace, $_Policy.replicationLevel)))
                            
                        }

                        $_DeviceAttrib = new-object HPOneView.Storage.StoreVirtualDeviceSpecificAttributes($_member.deviceSpecificAttributes.isMlptEnabled, 
                                                                                                           $_VolumeCreationSpacePolicyCol)

                    }

                    New-Object HPOneView.Storage.StoragePool($_member.name, 
                                                             $_member.description, 
                                                             $_member.scopesUri, 
                                                             $_member.storageSystemUri, 
                                                             $_member.isManaged, 
                                                             $_member.totalCapacity,
                                                             $_member.freeCapacity, 
                                                             $_member.allocatedCapacity, 
                                                             $_member.requestingRefresh,
                                                             $_member.lastRefreshTime,
                                                             $_DeviceAttrib, 
                                                             $_member.status, 
                                                             $_member.state, 
                                                             $_member.uri,
                                                             $_member.eTag, 
                                                             $_member.created, 
                                                             $_member.modified,
                                                             $_member.ApplianceConnection)

                }
            
            }

            elseif ($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] Storage Pool '{1}' not found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose
                
                $ExceptionMessage = "Storage Pool '{0}' not found on '{1}' appliance connection. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException StoragePoolResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)    

            }

            else
            {

                "[{0}] No Storage Pools found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

    }

}

function Add-HPOVStoragePool 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Hostname', 'name')]
        [object]$StorageSystem,

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Alias ('PoolName', 'spName', 'cpg')]
        [object]$Pool,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSboundParameters['StorageSystem']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

        Write-Warning "This Cmdlet will be deprecated in a future release. Please update your scripts to use Set-HPOVStoragePool."

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance '{1}' (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose
        
            ForEach ($_pool in $Pool)
            {

                "[{0}] Processing '$_pool'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Validate StroageSystem Parameter object
                if ($StorageSystem -is [PSCustomObject] -and $StorageSystem.ApplianceConnection.Name -ne $_appliance.Name)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException InvalidateStorageSystemApplianceConnection InvalidArgument 'StorageSystem' -TargetType 'PSObject' -Message "The -StorageSystem object does not appear to originate [$($StorageSystem.ApplianceConnection.Name)] from the same provided ApplianceConnection [$($_appliance.Name)]"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif ($StorageSystem -is [PsCustomObject] -and $StorageSystem.category -eq "storage-systems") 
                { 

                    "[{0}] Storage System resource object was provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageSystem.name, $StorageSystem.uri | Write-Verbose
                    
                    $_StorageSystem = $StorageSystem.PSObject.Copy()
                    
                }
                
                # Else the PsCustomObject is not the correct Category type, so error.
                elseif ($StorageSystem -is [PsCustomObject]) 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException InvalidResourceCategoryValue InvalidArgument 'StorageSystem' -TargetType 'PSObject' -Message "The -StorageSystem Parameter value is the wrong resource type ($($StorageSystem.category)). The correct resource category 'storage-systems' is allowed. Please check the value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Do not allow an array
                elseif ($StorageSystem -is [Array]) 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException ArrayNotAllow InvalidArgument 'StorageSystem' -TargetType 'PSObject' -Message "The -StorageSystem Parameter only accepts [System.String] or [System.Management.Automation.PSCustomObject] value. Please correct the value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else 
                {

                    "[{0}] Storage System Name is passed $($StoragSystem)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting list of Storage Systems" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_storagesystem = Get-HPOVStorageSystem -SystemName $StorageSystem -ApplianceConnection $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Generate Terminating Error if Storage System resource not found
                    if (-not($_storagesystem)) 
                    {
                            
                        "[{0}] Woops! No '$StorageSystem' Storage System found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException StorageSystemResourceNotFound ObjectNotFound 'StorageSystem' -Message "No Storage System with '$StorageSystem' system name found. Please check the name or use Add-HPOVStorageSystem to add the Storage System."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                    
                }

                # Get the list of unmanaged and managed pools in the managed domain
                Try
                {
                    
                    $_Results = Send-HPOVRequest ("{0}?filter=name EQ '{1}'" -f $_storagesystem.storagePoolsUri, $_pool) -Hostname $_appliance.Name
                    [PSCustomObject]$_PoolFound = $_Results.members[0]

                    "[{0}] Storage Pool object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_PoolFound | Out-String) | Write-Verbose

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $_PoolFound)
                {

                    # Storage pool resource does not exist in the existing managed list or in the unmanaged list in the managed domain
                    "[{0}] No Storage pool resource with '{1}' found in the managed Storage System." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pool | Write-Verbose

                    $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException StorageSystemResourceNotFound ObjectNotFound 'PoolName' -Message "No Storage pool resource with '$_pool' found in the managed Storage System."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif ($_PoolFound.isManaged)
                {

                    "[{0}] Storage pool resource '{1}' already exists in the managed list." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pool | Write-Verbose

                    $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException StoragePoolResourceExists ResourceExists 'PoolName' -Message "Storage pool resource '$_pool' already exists in the managed list."
                    $PSCmdlet.WriteError($ErrorRecord) #"Storage pool resource '$p' already exists"

                }

                else
                {

                    # Good here... Add the storage pool
                    $_PoolFound.isManaged = $true
                    
                    # Add the pool to array of pools to manage
                    Try
                    {

                        Send-HPOVRequest -Uri $_PoolFound.uri -method PUT -body $_PoolFound -Hostname $_PoolFound.ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

            }

        }

    }

    End  
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $colStatus

    }

}

function Set-HPOVStoragePool 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Pool')]
        [HPOneView.Storage.StoragePool[]]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Bool]$Managed,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSboundParameters['StorageSystem']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
     
    Process 
    {
    
        ForEach ($_pool in $InputObject)
        {

            "[{0}] Processing storage pool {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pool.Name, $_pool.uri | Write-Verbose

            if ($_pool.isManaged -and $Managed)
            {

                "[{0}] Storage pool resource '{1}' is already managed." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_pool.Name | Write-Verbose

                $ExceptionMessage = "Storage pool resource '{0}' is already managed." -f $_pool.Name
                $ErrorRecord = New-ErrorRecord HPOneView.StoragePoolResourceException StoragePoolResourceExists ResourceExists 'InputObject' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                # Get the list of unmanaged and managed pools in the managed domain
                Try
                {
                    
                    $__pool = Send-HPOVRequest -Uri $_pool.uri -Hostname $_pool.ApplianceConnection
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Good here... Add the storage pool
                $__pool.isManaged = $Managed
                
                # Add the pool to array of pools to manage
                Try
                {

                    Send-HPOVRequest -Uri $_pool.uri -method PUT -body $__pool -Hostname $_pool.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

        }

    }

    End  
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVStoragePool 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Name','StoragePool')]
        [HPOneView.Storage.StoragePool[]]$InputObject,
        
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }    

    }

    Process 
    { 

        ForEach ($_pool in $InputObject) 
        {

            Try
            {

                $_PoolToUpdate = Send-HPOVRequest -uri $_pool.uri -Hostname $_pool.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Update object to refresh state
            $_PoolToUpdate.requestingRefresh = $true

            Try
            {

                Send-HPOVRequest -uri $_pool.uri -Method PUT -Body $_PoolToUpdate -Hostname $_pool.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }
   
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVStoragePool 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "StorageSystem")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri", "name", 'StoragePool')]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = "StorageSystem")]
        [ValidateNotNullOrEmpty()]
        [Alias ("storage")]
        [Object]$StorageSystem,
        
        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Parameter (Mandatory = $False, ParameterSetName = "StorageSystem")]
        [Switch]$Force,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "StorageSystem")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection        = [System.Collections.ArrayList]::new()
        $_StoragePoolCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Storage Pool Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ($InputObject -is [HPOneView.Storage.StoragePool] -or 'storage-pools' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message "The Storage Pool resource object provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_StoragePoolCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message "The Storage Pool resource object is not an expected category type [$($StoragePool.category)]. The allowed resource category type is 'storage-pools'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing Storage Pool Name $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_StoragePool = Get-HPOVStoragePool $InputObject -ApplianceConnection $_appliance -ErrorAction Stop

                    $_StoragePool | ForEach-Object {

                        [void]$_StoragePoolCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End 
    {

        "[{0}] Processing $($_StoragePoolCollection.count) Storage Pool object resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Storage Resources
        ForEach ($_storagepool in $_StoragePoolCollection)
        {

            if ($PSCmdlet.ShouldProcess($_storagepool.ApplianceConnection.Name,"Remove Storage Pool '$($_storagepool.name)' from appliance")) 
            {

                "[{0}] Setting Storage Pool '$($_storagepool.name)' to 'Unmanaged' on appliance '$($_storagepool.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    $__pool = Send-HPOVRequest -Uri $_storagepool.uri -Hostname $_storagepool.ApplianceConnection
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Good here... unmanage the storage pool
                $__pool.isManaged = $false

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_storagepool.Uri -Method PUT -Body $__pool -Hostname $_storagepool.ApplianceConnection

                    [void]$_TaskCollection.Add($_resp)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function Get-HPOVStorageVolumeSet
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    [OutputType ([HPOneView.Storage.VolumeSet])]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $colStoragePools = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                "[{0}] Filtering for Label: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Label | Write-Verbose

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.StorageVolumeSet

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {
                
                "[{0}] No Storage Volume Template with '{1}' name found on '{2}' appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose
                
                $ExceptionMessage = "No Storage Volume with '{0}' name found on '{1}' appliance connection. Please check the name or use New-HPOVStorageVolumeTemplate to create the volume template." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException StorageVolumeResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            elseif ($_ResourcesFromIndexCol -eq 0) 
            {

                "[{0}] No Storage Volume Templates found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    # Get associated Storage Systems to Volume Sets with "name EQ 'STORAGE_SYSTEM_TO_STORAGE_VOLUME_SET'" to then embed within the Storage Volume object
                    
                    $_StorageVolumeResources = [System.Collections.ArrayList]::new()

                    Try
                    {

                        $_StorageSystem = Send-HPOVRequest -Uri $_member.storageSystemUri -ApplianceConnection $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Get associated volumes to volume sets
                    $_uri = '{0}?name=STORAGE_VOLUME_SET_TO_STORAGE_VOLUME&parentUri={1}' -f $AssociationsUri, $_member.uri

                    Try
                    {

                        [Array]$_StorageVolumeResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                        if (-not $_StorageVolumeResourcesFromIndexCol.Count)
                        {

                            [Array]$_StorageVolumeResourcesFromIndexCol = @()

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_NimbleVolumeSetDeviceSpecificAttributes = New-Object HPOneView.Storage.NimbleVolumeSetDeviceSpecificAttributes ($_member.deviceSpecificAttributes.appSync, 
                                                                                                                                      $_member.deviceSpecificAttributes.totalSnapshots, 
                                                                                                                                      $_member.deviceSpecificAttributes.replicationPartner, 
                                                                                                                                      $_member.deviceSpecificAttributes.lastSnapshotCollection)
                    
                    New-Object HPOneView.Storage.VolumeSet ($_member.name,
                                                            $_StorageVolumeResourcesFromIndexCol,
                                                            $_StorageSystem,
                                                            $_NimbleVolumeSetDeviceSpecificAttributes,
                                                            $_member.status,
                                                            $_member.state,
                                                            $_member.eTag,
                                                            $_member.uri,
                                                            $_member.ApplianceConnection)

                }

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Get-HPOVStorageVolumeTemplate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('TemplateName')]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $False)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_StorageVolumeTemplateCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    { 

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                "[{0}] Filtering for Label: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Label | Write-Verbose

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category=storage-volume-templates'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {
                
                "[{0}] No Storage Volume Template with '{1}' name found on '{2}' appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose
                
                $ExceptionMessage = "No Storage Volume with '{0}' name found on '{1}' appliance connection. Please check the name or use New-HPOVStorageVolumeTemplate to create the volume template." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException StorageVolumeResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            elseif ($_ResourcesFromIndexCol -eq 0) 
            {

                "[{0}] No Storage Volume Templates found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.Storage.VolumeTemplate')

                    $_member

                }

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function New-HPOVStorageVolumeTemplate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [Alias ('TemplateName')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Storage.StoragePool]$StoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Storage.StoragePool]$SnapshotStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$LockSnapShotStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [ValidateNotNullOrEmpty()]
        [object]$StorageSystem,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory, ParameterSetName = "Nimble")]
        [ValidateScript({$_ -ge 1})]
        [Alias ("size")]
        [int64]$Capacity,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockCapacity,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$Full,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Alias ('ProvisionType')]
        [ValidateSet ('Thin','Full','TPDD')]
        [String]$ProvisioningType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockProvisionType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$EnableDeduplication,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$LockEnableDeduplication,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$EnableCompression,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$LockEnableCompression,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$Shared,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockProvisionMode,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [ValidateSet ('NetworkRaid0None','NetworkRaid5SingleParity','NetworkRaid10Mirror2Way','NetworkRaid10Mirror3Way','NetworkRaid10Mirror4Way','NetworkRaid6DualParity')]
        [String]$DataProtectionLevel,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$LockProtectionLevel,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$EnableAdaptiveOptimization,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$LockAdaptiveOptimization,
        
        [Parameter (Mandatory, ParameterSetName = "Nimble")]
        [HPOneView.Storage.PerformancePolicy]$PerformancePolicy,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockPerformancePolicy,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$EnableEncryption,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockEnableEncryption,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$CachePinning,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockCachePinning,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [HPOneView.Storage.VolumeSet]$VolumeSet,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockVolumeSet,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$EnableIOPSLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateRange (256,4294967295)]
        [Int]$IOPSLimit = 256,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockIOPSLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$EnableDataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Int]$DataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockDataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [HPOneView.Storage.NimbleFolder]$Folder,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockFolder,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "Nimble")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSboundParameters['StoragePool']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

        if ($PSBoundParameters['Thin'])
        {

            $ExceptionMessage = 'The -Thin parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)
            
            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Thin'])

        }
        
        if ($PSBoundParameters['Full'])
        {

            $ExceptionMessage = 'The -Full parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Full'])

        }

        if ($PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = 'The -ProvisioningType "TPDD" value is being deprecated. Please update your script(s) to use the "Thin" value and -EnableCompression $True parameter.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']
            $PSBoundParameters.Add('EnableDeduplication', $True)
            
            # If LockProvisionType is set to true, then also lock Deduplication
            if ($PSBoundParameters.Keys -Contains 'LockProvisionType')
            {

                $PSBoundParameters.Add('LockEnableDeduplication', $True)

            }
            
        }

        if ($PSBoundParameters['StorageSystem'])
        {

            $ExceptionMessage = "The -StorageSystem is deprecated. Please update your script(s) to use Get-HPOVStoragePool to get the specific pool object."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        # Need to generate an error
        if ($PSBoundParameters['Family'] -eq 'Nimble' -and $PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = "The provided ProvisioningType policy '{0}' is not supported by Nimble. Please update your script to use either 'Thin' or 'Full'. Setting ProvisioningType parameter to 'Thin'." -f $ProvisioningType
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'ProvisioningType' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']

        }

    }

    Process 
    {

        if ($StoragePool -isnot [PSCustomObject])
        {

            Try
            {

                "[{0}] Getting and validating StoragePool parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_StoragePool = GetStoragePool -InputObject $StoragePool -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            "[{0}] StoragePool object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StoragePool.name | Write-Verbose
            "[{0}] StoragePool object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StoragePool.category | Write-Verbose
            "[{0}] StoragePool object URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StoragePool.uri | Write-Verbose
            $_StoragePool = $StoragePool.PSObject.Copy()

        }

        # Get Root Volume Template from Storage System
        Try
        {

            "[{0}] Getting storage system root volume template." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            $_Uri = '{0}/templates?filter=isRoot EQ true' -f $_StoragePool.storageSystemUri
            $_RootTemplate = (Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection).members[0]

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        "[{0}] Root template: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_RootTemplate.name | Write-Verbose
        "[{0}] Root template family: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_RootTemplate.family | Write-Verbose

        $_svt = NewObject -StorageVolumeTemplate
        $_svt.properties = $_RootTemplate.properties

        # Get the storage system to validate certain settings if they are available
        Try
        {

            $_StorageSystem = Send-HPOVRequest -Uri $_StoragePool.storageSystemUri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        switch ($_RootTemplate.family)
        {

            'Nimble'
            {

                if ($PSBoundParameters.Keys -Contains 'EnableEncryption')
                {

                    "[{0}] Enable Encryption: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableEncryption | Write-Verbose

                    $_svt.properties.isEncrypted.default = $EnableEncryption

                }

                if ($PSBoundParameters['LockEnableEncryption'])
                {

                    "[{0}] Locking EnableEncryption: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockEnableEncryption.IsPresent | Write-Verbose

                    $_svt.properties.isDeduplicated.meta.locked = $LockEnableEncryption.IsPresent

                }

                # PerformancePolicy parameter
                $_FilterDelegate = [Func[object,bool]]{ param ($p) return $p.id -eq $PerformancePolicy.Id }

                if ($_PerformancePolicy = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($_StorageSystem.deviceSpecificAttributes.performancePolicies, $_FilterDelegate)))
                {

                    "[{0}] Config PerformancePolicy: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PerformancePolicy | Write-Verbose

                    $_svt.properties.performancePolicy | Add-Member -NotePropertyName default -NotePropertyValue $_PerformancePolicy.id -Force

                    if ($PSBoundParameters['LockPerformancePolicy'])
                    {

                        "[{0}] Locking PerformancePolicy: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockPerformancePolicy.IsPresent | Write-Verbose

                        $_svt.properties.performancePolicy.meta.locked = $LockPerformancePolicy.IsPresent

                    }
                    
                    # Check for cache pinning
                    if ($PSBoundParameters.Keys -Contains 'CachePinning')
                    {

                        # Error that cache pinning is not supported by the Performance Policy chosen and the parameter was provided
                        if (-not $_PerformancePolicy.isCached)
                        {

                            "[{0}] Performance Policy '{1}' does not support cache pinning." -f $MyInvocation.InvocationName.ToString().ToUpper(), $PerformancePolicy | Write-Verbose

                            $ExceptionMessage = "The provided Nimble performance policy '{0}' does not allow Cache Pinning to be configured." -f $PerformancePolicy
                            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidCachePinningParameter InvalidOperation 'CachePinning' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        else
                        {

                            "[{0}] Config CachePinning: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $CachePinning | Write-Verbose

                            $_svt.properties.isCached = $CachePinning

                            if ($PSBoundParameters['LockCachePinning'])
                            {

                                "[{0}] Locking CachePinning: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockCachePinning.IsPresent | Write-Verbose

                                $_svt.properties.isCached.meta.locked = $LockCachePinning.IsPresent

                            }

                        }

                    }

                }

                else
                {

                    $ExceptionMessage = "The provided Nimble performance policy '{0}' is not found in '{1}' storage system." -f $PerformancePolicy, $_StorageSystem.name
                    $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidPerformancePolicyParameter InvalidOperation 'PerformancePolicy' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Volume set management
                if ($PSBoundParameters['VolumeSet'])
                {

                    "[{0}] Setting VolumeSet: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeSet | Write-Verbose

                    $_svt.properties.volumeSet.default = $VolumeSet.Uri

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockVolumeSet'])
                {

                    "[{0}] Locking VolumeSet: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockVolumeSet.IsPresent | Write-Verbose

                    $_svt.properties.volumeSet.meta.locked = $LockVolumeSet.IsPresent

                }

                # IOPSLimit management
                if ($PSBoundParameters['EnableIOPSLimit'])
                {

                    "[{0}] Setting IOPSLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IOPSLimit | Write-Verbose

                    $_svt.properties.iopsLimit.default = $IOPSLimit

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockIOPSLimit'])
                {

                    "[{0}] Locking IOPSLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockIOPSLimit.IsPresent | Write-Verbose

                    $_svt.properties.iopsLimit.meta.locked = $LockIOPSLimit.IsPresent

                }

                # DataTransferLimit management
                if ($PSBoundParameters['EnableDataTransferLimit'])
                {

                    if ($EnableDataTransferLimit -and $DataTransferLimit -lt $_RootTemplate.properties.dataTransferLimit.minimum -or $DataTransferLimit -gt $_RootTemplate.properties.dataTransferLimit.maximum)
                    {

                        $ExceptionMessage = "The provided Nimble DataTransferLimit '{0}' is not within the allowed '{1}' and '{2}' limit." -f $DataTransferLimit, $_RootTemplate.properties.dataTransferLimit.minimum, $_RootTemplate.properties.dataTransferLimit.maximum
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidDataTransferLimitParameter InvalidOperation 'DataTransferLimit' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                    }

                    "[{0}] Setting DataTransferLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DataTransferLimit | Write-Verbose

                    $_svt.properties.dataTransferLimit.default = $DataTransferLimit

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockDataTransferLimit'])
                {

                    "[{0}] Locking LockDataTransferLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockDataTransferLimit.IsPresent | Write-Verbose

                    $_svt.properties.dataTransferLimit.meta.locked = $LockDataTransferLimit.IsPresent

                }

                # NimbleFolder management
                if ($PSBoundParameters['Folder'])
                {

                    $_FilterDelegate = [Func[object,bool]]{ param ($p) return $p.id -eq $Folder.Id }

                    if ($_FolderLocation = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($_StoragePool.deviceSpecificAttributes.folders, $_FilterDelegate)))
                    {

                        "[{0}] Config Folder: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Folder | Write-Verbose

                        $_svt.properties.folder.default = $Folder.id

                    }

                    else
                    {

                        $ExceptionMessage = "The provided Nimble folder '{0}' is not found in '{1}' storage pool." -f $Folder, $_StoragePool.name
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidFolderParameter InvalidOperation 'Folder' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockFolder'])
                {

                    "[{0}] Locking LockFolder: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockFolder.IsPresent | Write-Verbose

                    $_svt.properties.folder.meta.locked = $LockFolder.IsPresent

                }

            }

            'StoreServ'
            {

                if ($PSBoundParameters['DataProtectionLevel'] -or $PSBoundParameters['LockProtectionLevel'])
                {

                    $ExceptionMessage = "The Storage System family of the Storage Pool, {0}, is not a StoreVirtual system. DataProtectionLevel is only supported with StoreVirtual class of storage systems." -f $_StoragePool.name
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
                
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

                if ($PSBoundParameters['EnableAdaptiveOptimization'] -or $PSBoundParameters['LockAdaptiveOptimization'])
                {

                    $ExceptionMessage = "The Storage System family of the Storage Pool, {0}, is not a StoreVirtual system. EnableAdaptiveOptimization is only supported with StoreVirtual class of storage systems." -f $_StoragePool.name
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'EnableAdaptiveOptimization' -TargetType $EnableAdaptiveOptimization.gettype().Name -Message $ExceptionMessage
                
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

                if ($PSboundParameters['SnapShotStoragePool'])
                {

                    Try
                    {

                        $_SnapShotStoragePool = GetStoragePool -InputObject $SnapShotStoragePool -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)
                        
                    }

                    "[{0}] Setting snapshot storage pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_SnapShotStoragePool.uri | Write-Verbose

                    $_svt.properties.snapshotPool.default = $_SnapShotStoragePool.uri

                }

                else 
                {            

                    "[{0}] No SnapShotStoragePool resource provided. Setting Snapshot Pool to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePool.name | Write-Verbose

                    $_svt.properties.snapshotPool.default = $_StoragePool.uri

                }

                if ($PSBoundParameters['LockStoragePool'])
                {

                    "[{0}] Locking Snapshot Storage Pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockSnapshotStoragePool.IsPresent | Write-Verbose

                    $_svt.properties.snapshotPool.meta.locked = $LockSnapshotStoragePool.IsPresent

                }

                if ($PSBoundParameters.Keys -Contains 'EnableDeduplication')
                {

                    "[{0}] Enable Deduplication: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSBoundParameters['EnableDeduplication'] | Write-Verbose

                    $_svt.properties.isDeduplicated.default = $PSBoundParameters['EnableDeduplication']

                    if ($PSBoundParameters['LockEnableDeduplication'])
                    {

                        "[{0}] Locking Deduplication: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockEnableDeduplication.IsPresent | Write-Verbose

                        $_svt.properties.isDeduplicated.meta.locked = $LockEnableDeduplication.IsPresent

                    }                    

                }
                
                if ($PSBoundParameters.Keys -Contains 'EnableCompression')
                {

                    "[{0}] Enable Compression: {1}" -f $MyInvocation.InvoctionName.ToString().ToUpper(), $PSBoundParameters['EnableCompression'] | Write-Verbose

                    $_svt.properties.isCompressed.default = $PSBoundParameters['EnableCompression']

                    if ($PSBoundParameters['LockEnableCompression'])
                    {

                        "[{0}] Locking Compression: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockEnableCompression.IsPresent | Write-Verbose

                        $_svt.properties.isCompressed.meta.locked = $LockEnableCompression.IsPresent

                    }

                }                

            }

            'StoreVirtual'
            {

                if ($PSBoundParameters['SnapShotStoragePool'])
                {

                    $ExceptionMessage = "The Storage System family of the Storage Pool, {0}, is not a StoreServ system. Snapshots are only supported with StoreServ class of storage systems." -f $_StoragePool.name
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'StoragePool' -TargetType $StoragePool.gettype().Name -Message $ExceptionMessage
                
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

                # Set AdaptiveOptimization and RedundancyMode
                if ($PSBoundParameters['DataProtectionLevel'])
                {

                    $_DataProtectionLevel = $_RootTemplate.properties.dataProtectionLevel.enum | Where-Object { $_ -eq $DataProtectionLevel }

                    if (-not $_DataProtectionLevel)
                    {

                        $ExceptionMessage = "The requested data protection level, {0}, is not supported with the storage system. Please correct the value with one of the following options: {1}" -f $DataProtectionLevel, ([String]::Join(', ', $_RootTemplate.properties.dataProtectionLevel.enum))
                        $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedProtectionLevelValue InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
                    
                        # Generate Terminating Error
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                    }

                    "[{0}] Setting StoreVirtual data protection level: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DataProtectionLevel | Write-Verbose

                    $_svt.properties.dataProtectionLevel.default = $_DataProtectionLevel

                }

                if ($PSBoundParameters['LockProtectionLevel'])
                {

                    "[{0}] Locking Protection Level: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProtectionLevel.IsPresent | Write-Verbose

                    $_svt.properties.dataProtectionLevel.meta.locked = $LockProtectionLevel.IsPresent

                }

                if ($PSBoundParameters.Keys -Contains 'EnableAdaptiveOptimization')
                {

                    "[{0}] Setting Adaptive optimization default value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableAdaptiveOptimization.IsPresent | Write-Verbose

                    $_svt.properties.isAdaptiveOptimizationEnabled.default = $EnableAdaptiveOptimization.IsPresent

                }

                if ($PSBoundParameters['LockAdaptiveOptimization'])
                {

                    "[{0}] Locking Adaptive optimization: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockAdaptiveOptimization.IsPresent | Write-Verbose

                    $_svt.properties.isAdaptiveOptimizationEnabled.meta.locked = $LockAdaptiveOptimization.IsPresent

                }

            }

        }

        # Set common values here
        $_svt.name            = $Name
        $_svt.description     = $description
        $_svt.rootTemplateUri = $_RootTemplate.uri

        switch ($PSBoundParameters.Keys)
        {

            'Capacity'
            {

                "[{0}] Setting capacity default value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [int64]($capacity * 1GB) | Write-Verbose

                $_svt.properties.size.default = [int64]($capacity * 1GB)

            }

            'LockCapacity'
            {

                "[{0}] Locking capacity: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockCapacity.IsPresent | Write-Verbose

                $_svt.properties.size.meta.locked = $LockCapacity.IsPresent

            }

            'StoragePool'
            {

                "[{0}] Setting Storage Pool default value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePool.uri | Write-Verbose

                $_svt.properties.storagepool | Add-Member -NotePropertyName default -NotePropertyValue $_StoragePool.uri

            }

            'LockStoragePool'
            {

                "[{0}] Locking Storage Pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockStoragePool.IsPresent | Write-Verbose

                $_svt.properties.storagepool.meta.locked = $LockStoragePool.IsPresent

            }

            'Full'
            {

                "[{0}] Setting Provisioning Type to Full: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Full.IsPresent | Write-Verbose

                $_svt.properties.provisioningType.default = if ($Full.IsPresent) { 'Full' } else { 'Thin' }
                
            }

            'ProvisioningType'
            {

                "[{0}] Setting Provisioning Type to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageVolumeProvisioningTypeEnum[$ProvisioningType] | Write-Verbose

                $_svt.properties.provisioningType.default = $StorageVolumeProvisioningTypeEnum[$ProvisioningType]

                if ($ProvisioningType -eq 'TPDD')
                {

                    "[{0}] Setting isDeduplicated: true" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_svt.properties.isDeduplicated.default = $true

                }

            }

            'LockProvisionType'
            {

                "[{0}] Locking provisioning type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProvisionType.IsPresent | Write-Verbose

                $_svt.properties.provisioningType.meta.locked = $LockProvisionType.IsPresent

                if ($ProvisioningType -eq 'TPDD')
                {

                    "[{0}] Locking Deduplication: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProvisionType.IsPresent | Write-Verbose

                    $_svt.properties.isDeduplicated.meta.locked = $LockProvisionType.IsPresent

                }

            }

            'Shared'
            {

                "[{0}] Setting Provisioning Type to Full: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Shared.IsPresent | Write-Verbose

                $_svt.properties.isShareable.default = $Shared.IsPresent
                
            }

            'LockProvisionMode'
            {

                "[{0}] Locking provisioning type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProvisionType.IsPresent | Write-Verbose

                $_svt.properties.isShareable.meta.locked = $LockProvisionType.IsPresent

            }

        }

        if ($PSBoundParameters['Scope'])
        {

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_svt.initialScopeUris.Add($_Scope.Uri)

            }

        }

        # Send the request
        Try
        {

            $_resp = Send-HPOVRequest -method POST -uri $StorageVolumeTemplateUri -body $_svt -Hostname $ApplianceConnection.Name
            $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Storage.VolumeTemplate')

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        $_resp

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVStorageVolumeTemplate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType ([HPOneView.Appliance.TaskResource])]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Nimble")]
        [Alias('SVT','Template')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [Alias ('TemplateName')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [object]$SnapshotStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$LockSnapShotStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateNotNullOrEmpty()]
        [object]$StorageSystem,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateScript({$_ -ge 1})]
        [Alias ("size")]
        [int64]$Capacity,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockCapacity,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$Thin,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$Full,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Alias ('ProvisionType')]
        [ValidateSet ('Thin','Full','TPDD')]
        [String]$ProvisioningType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$LockProvisionType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Bool]$Shared,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$LockProvisionMode,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [ValidateSet ('NetworkRaid0None','NetworkRaid5SingleParity','NetworkRaid10Mirror2Way','NetworkRaid10Mirror3Way','NetworkRaid10Mirror4Way','NetworkRaid6DualParity')]
        [String]$DataProtectionLevel,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$LockProtectionLevel,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$EnableAdaptiveOptimization,

        [Parameter (Mandatory = $false, ParameterSetName = "StoreVirtual")]
        [Switch]$LockAdaptiveOptimization,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [HPOneView.Storage.PerformancePolicy]$PerformancePolicy,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockPerformancePolicy,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$EnableEncryption,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockEnableEncryption,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$CachePinning,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockCachePinning,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")] # From Get-HPOVStorageVolumeSet
        [HPOneView.Storage.VolumeSet]$VolumeSet,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockVolumeSet,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$EnableIOPSLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [ValidateRange (256,4294967295)]
        [Int]$IOPSLimit = 256,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockIOPSLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Bool]$EnableDataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Int]$DataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockDataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [HPOneView.Storage.NimbleFolder]$Folder,

        [Parameter (Mandatory = $false, ParameterSetName = "Nimble")]
        [Switch]$LockFolder,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "StoreVirtual")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "Nimble")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process 
    {

        if ($PSBoundParameters['Thin'])
        {

            $ExceptionMessage = 'The -Thin parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)
            
            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Thin'])

        }
        
        if ($PSBoundParameters['Full'])
        {

            $ExceptionMessage = 'The -Full parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Full'])

        }

        if ($PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = 'The -ProvisioningType "TPDD" value is being deprecated. Please update your script(s) to use the "Thin" value and -EnableCompression $True parameter.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']
            $PSBoundParameters.Add('EnableCompression', $True)
            
        }

        if ($PSBoundParameters['StorageSystem'])
        {

            $ExceptionMessage = "The -StorageSystem is deprecated. Please update your script(s) to use Get-HPOVStoragePool to get the specific pool object."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        # Need to generate an error
        if ($InputObject.family -eq 'Nimble' -and $PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = "The provided ProvisioningType policy '{0}' is not supported by Nimble. Please update your script to use either 'Thin' or 'Full'. Setting ProvisioningType parameter to 'Thin'." -f $ProvisioningType
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'ProvisioningType' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']

        }

        "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
        "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
        "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection | Write-Verbose
        "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

        # Validate the object
        if ($InputObject.category -ne $ResourceCategoryEnum.StorageVolumeTemplate)
        {

            $ExceptionMessage = "Invalid InputObject parameter value. Expected Resource Category 'storage-volume-templates', received '{0}'." -f $InputObject.category
            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeTemplateResourceException InvalidStorageVolumeTemplateCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_InputObject = $InputObject.PSObject.Copy()

        "[{0}] ORIGINAL Storage Volume object properties: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

        switch ($_InputObject.family)
        {

            'StoreServ'
            {

                if ($PSBoundParameters['DataProtectionLevel'] -or $PSBoundParameters['LockProtectionLevel'])
                {

                    $ExceptionMessage = "The Storage System family of the volume template, {0}, is not a StoreVirtual system. DataProtectionLevel is only supported with StoreVirtual class of storage systems." -f $_InputObject.name
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
                
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

                if ($PSBoundParameters['EnableAdaptiveOptimization'] -or $PSBoundParameters['LockAdaptiveOptimization'])
                {

                    $ExceptionMessage = "The Storage System family of the volume template, {0}, is not a StoreVirtual system. EnableAdaptiveOptimization is only supported with StoreVirtual class of storage systems." -f $_InputObject.name
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'EnableAdaptiveOptimization' -TargetType $EnableAdaptiveOptimization.gettype().Name -Message $ExceptionMessage
                
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

                if ($PSboundParameters['SnapShotStoragePool'])
                {

                    Try
                    {

                        $_SnapShotStoragePool = GetStoragePool -InputObject $SnapShotStoragePool -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)
                        
                    }

                    Try
                    {

                        $_StoragePool = Send-HPOVRequest -Uri $_InputObject.storagePoolUri -Hostname $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    if ($_StoragePool.storageSystemUri -ne $_SnapShotStoragePool.storageSystemUri)
                    {

                        $ExceptionMessage = "The Storage Pool and SnapShot Storage Pool are not from the same Storage System. please correct the SnapshotStoragePool parameter value."
                        $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidSnapshotStoragePoolLocation InvalidOperation 'SnapShotStoragePool' -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    "[{0}] Setting snapshot storage pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_SnapShotStoragePool.uri | Write-Verbose

                    $_InputObject.properties.snapshotPool.default = $_SnapShotStoragePool.uri

                }

                if ($PSBoundParameters['LockStoragePool'])
                {

                    "[{0}] Locking Snapshot Storage Pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockSnapshotStoragePool.IsPresent | Write-Verbose

                    $_InputObject.properties.snapshotPool.meta.locked = $LockSnapshotStoragePool.IsPresent

                }

            }

            'StoreVirtual'
            {

                if ($PSBoundParameters['SnapShotStoragePool'])
                {

                    $ExceptionMessage = "The Storage System family of the Storage Pool, {0}, is not a StoreServ system. Snapshots are only supported with StoreServ class of storage systems." -f $_StoragePool.name
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'SnapShotStoragePool' -TargetType $SnapShotStoragePool.gettype().Name -Message $ExceptionMessage
                
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

                # Set AdaptiveOptimization and RedundancyMode
                if ($PSBoundParameters['DataProtectionLevel'])
                {

                    $_DataProtectionLevel = $_InputObject.properties.dataProtectionLevel.enum | Where-Object { $_ -eq $DataProtectionLevel }

                    if (-not $_DataProtectionLevel)
                    {

                        $ExceptionMessage = "The requested data protection level, {0}, is not supported with the storage system. Please correct the value with one of the following options: {1}" -f $DataProtectionLevel, ([String]::Join(', ', $_InputObject.properties.dataProtectionLevel.enum))
                        $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedProtectionLevelValue InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
                    
                        # Generate Terminating Error
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                    }

                    "[{0}] Setting StoreVirtual data protection level: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DataProtectionLevel | Write-Verbose

                    $_InputObject.properties.dataProtectionLevel.default = $_DataProtectionLevel

                }

                if ($PSBoundParameters['LockProtectionLevel'])
                {

                    "[{0}] Locking Protection Level: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProtectionLevel.IsPresent | Write-Verbose

                    $_InputObject.properties.dataProtectionLevel.meta.locked = $LockProtectionLevel.IsPresent

                }

                if ($PSBoundParameters['EnableAdaptiveOptimization'])
                {

                    "[{0}] Setting Adaptive optimization default value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableAdaptiveOptimization.IsPresent | Write-Verbose

                    $_InputObject.properties.isAdaptiveOptimizationEnabled.default = $EnableAdaptiveOptimization.IsPresent

                }

                if ($PSBoundParameters['LockAdaptiveOptimization'])
                {

                    "[{0}] Locking Adaptive optimization: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockAdaptiveOptimization.IsPresent | Write-Verbose

                    $_InputObject.properties.isAdaptiveOptimizationEnabled.meta.locked = $LockAdaptiveOptimization.IsPresent

                }

            }
            
            'Nimble'
            {

                if ($PSBoundParameters.Keys -Contains 'EnableEncryption')
                {

                    "[{0}] Enable Encryption: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableEncryption | Write-Verbose

                    $_InputObject.properties.isEncrypted.default = $EnableEncryption

                }
                
                if ($PSBoundParameters['LockEnableEncryption'])
                {

                    "[{0}] Locking EnableEncryption: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockEnableEncryption.IsPresent | Write-Verbose

                    $_InputObject.properties.isDeduplicated.meta.locked = $LockEnableEncryption.IsPresent

                }

                if ($PSBoundParameters['PerformancePolicy'])
                {

                    # PerformancePolicy parameter
                    $_FilterDelegate = [Func[object,bool]]{ param ($p) return $p.id -eq $PerformancePolicy.Id }

                    if ($_PerformancePolicy = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($_StorageSystem.deviceSpecificAttributes.performancePolicies, $_FilterDelegate)))
                    {

                        "[{0}] Config PerformancePolicy: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PerformancePolicy | Write-Verbose

                        $_InputObject.properties.performancePolicy | Add-Member -NotePropertyName default -NotePropertyValue $_PerformancePolicy.id -Force

                        # Check for cache pinning
                        if ($PSBoundParameters.Keys -Contains 'CachePinning')
                        {

                            # Error that cache pinning is not supported by the Performance Policy chosen and the parameter was provided
                            if (-not $_PerformancePolicy.isCached)
                            {

                                "[{0}] Performance Policy '{1}' does not support cache pinning." -f $MyInvocation.InvocationName.ToString().ToUpper(), $PerformancePolicy | Write-Verbose

                                $ExceptionMessage = "The provided Nimble performance policy '{0}' does not allow Cache Pinning to be configured." -f $PerformancePolicy
                                $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidCachePinningParameter InvalidOperation 'CachePinning' -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            else
                            {

                                "[{0}] Config CachePinning: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $CachePinning | Write-Verbose

                                $_InputObject.properties.isCached = $CachePinning

                                if ($PSBoundParameters['LockCachePinning'])
                                {

                                    "[{0}] Locking CachePinning: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockCachePinning.IsPresent | Write-Verbose

                                    $_InputObject.properties.isCached.meta.locked = $LockCachePinning.IsPresent

                                }

                            }

                        }

                    }

                    else
                    {

                        $ExceptionMessage = "The provided Nimble performance policy '{0}' is not found in '{1}' storage system." -f $PerformancePolicy, $_StorageSystem.name
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidPerformancePolicyParameter InvalidOperation 'PerformancePolicy' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                if ($PSBoundParameters['LockPerformancePolicy'])
                {

                    "[{0}] Locking PerformancePolicy: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockPerformancePolicy.IsPresent | Write-Verbose

                    $_InputObject.properties.performancePolicy.meta.locked = $LockPerformancePolicy.IsPresent

                }

                # Volume set management
                if ($PSBoundParameters['VolumeSet'])
                {

                    "[{0}] Setting VolumeSet: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeSet | Write-Verbose

                    $_InputObject.properties.volumeSet.default = $VolumeSet.Uri

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockVolumeSet'])
                {

                    "[{0}] Locking VolumeSet: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockVolumeSet.IsPresent | Write-Verbose

                    $_InputObject.properties.volumeSet.meta.locked = $LockVolumeSet.IsPresent

                }

                # IOPSLimit management
                if ($PSBoundParameters.Keys -Contains 'EnableIOPSLimit')
                {

                    "[{0}] Enable IOPSLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableIOPSLimit | Write-Verbose

                    if ($EnableIOPSLimit)
                    {

                        "[{0}] Setting IOPSLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IOPSLimit | Write-Verbose

                        $_InputObject.properties.iopsLimit.default = $IOPSLimit

                    }

                    else
                    {
                    
                        $_InputObject.properties.iopsLimit.default = $EnableIOPSLimit
                    
                    }

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockIOPSLimit'])
                {

                    "[{0}] Locking IOPSLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockIOPSLimit.IsPresent | Write-Verbose

                    $_InputObject.properties.iopsLimit.meta.locked = $LockIOPSLimit.IsPresent

                }

                # DataTransferLimit management
                if ($PSBoundParameters.Keys -Contains 'EnableDataTransferLimit')
                {

                    "[{0}] Enable DataTransferLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableDataTransferLimit | Write-Verbose

                    if ($EnableDataTransferLimit -and $DataTransferLimit -lt $_RootTemplate.properties.dataTransferLimit.minimum -or $DataTransferLimit -gt $_RootTemplate.properties.dataTransferLimit.maximum)
                    {

                        $ExceptionMessage = "The provided Nimble DataTransferLimit '{0}' is not within the allowed '{1}' and '{2}' limit." -f $DataTransferLimit, $_RootTemplate.properties.dataTransferLimit.minimum, $_RootTemplate.properties.dataTransferLimit.maximum
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidDataTransferLimitParameter InvalidOperation 'DataTransferLimit' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                    }

                    elseif ($EnableDataTransferLimit)
                    {


                        "[{0}] Setting DataTransferLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DataTransferLimit | Write-Verbose

                        $_InputObject.properties.dataTransferLimit.default = $DataTransferLimit 

                    }

                    else
                    {
                    
                        $_InputObject.properties.dataTransferLimit.default = $EnableDataTransferLimit 
                    
                    }

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockDataTransferLimit'])
                {

                    "[{0}] Locking LockDataTransferLimit: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockDataTransferLimit.IsPresent | Write-Verbose

                    $_InputObject.properties.dataTransferLimit.meta.locked = $LockDataTransferLimit.IsPresent

                }

                # NimbleFolder management
                if ($PSBoundParameters['Folder'])
                {

                    $_FilterDelegate = [Func[object,bool]]{ param ($p) return $p.id -eq $Folder.Id }

                    if ($_FolderLocation = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($_StorageSystem.deviceSpecificAttributes.folders, $_FilterDelegate)))
                    {

                        "[{0}] Config Folder: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Folder | Write-Verbose

                        $_InputObject.properties.folder.default = $Folder.id

                    }
                    
                    else
                    {

                        $ExceptionMessage = "The provided Nimble folder '{0}' is not found in '{1}' storage system." -f $Folder, $_StorageSystem.name
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidFolderParameter InvalidOperation 'Folder' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                # Since VS can be set to null, allow it to be locked.
                if ($PSBoundParameters['LockFolder'])
                {

                    "[{0}] Locking LockFolder: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockFolder.IsPresent | Write-Verbose

                    $_InputObject.properties.folder.meta.locked = $LockFolder.IsPresent

                }

            }

        }

        switch ($PSBoundParameters.Keys)
        {

            'Name'
            {

                $_InputObject.name = $Name

            }

            'Description'
            {

                $_InputObject.description = $description

            }

            'Capacity'
            {

                "[{0}] Setting capacity default value: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [int64]($Capacity * 1GB) | Write-Verbose

                $_InputObject.properties.size.default = [int64]($Capacity * 1GB)

            }

            'LockCapacity'
            {

                "[{0}] Locking capacity: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockCapacity.IsPresent | Write-Verbose

                $_InputObject.properties.size.meta.locked = $LockCapacity.IsPresent

            }

            'LockStoragePool'
            {

                "[{0}] Locking Storage Pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockStoragePool.IsPresent | Write-Verbose

                $_InputObject.properties.storagepool.meta.locked = $LockStoragePool.IsPresent

            }

            'LockProvisionType'
            {

                "[{0}] Locking provisioning type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProvisionType.IsPresent | Write-Verbose

                $_InputObject.properties.provisioningType.meta.locked = $LockProvisionType.IsPresent

            }

            'Shared'
            {

                "[{0}] Setting Provisioning Type to Full: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Shared.IsPresent | Write-Verbose

                $_InputObject.properties.isShareable.default = $Shared.IsPresent
                
            }

            'LockProvisionMode'
            {

                "[{0}] Locking provisioning type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LockProvisionType.IsPresent | Write-Verbose

                $_InputObject.properties.isShareable.meta.locked = $LockProvisionType.IsPresent

            }

        }
        
        "[{0}] Updated Storage Volume Template object properties: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_InputObject | out-string) | Write-Verbose

        "[{0}] Sending updated storage volume template to appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $Resp = Send-HPOVRequest -Uri $_InputObject.uri -Method PUT -Body $_InputObject -Hostname $ApplianceConnection | Wait-HPOVTaskComplete

            $Resp

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVStorageVolumeTemplate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('uri', 'name', 'templateName', 'Template')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Switch]$Force
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
                
        if (-not($PSBoundParameters['Template'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_SVTCollection  = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        foreach ($_svt in $InputObject) 
        {

            # SVT passed is a URI
            if (($_svt -is [String]) -and [System.Uri]::IsWellFormedUriString($_svt,'Relative')) 
            {

                "[{0}] Received URI: $($_svt)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Getting SVT object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if (($ApplianceConnection | Measure-Object).Count -gt 1)
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value when using a Storage Volume Template URI value. Please correct this and try again.'
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Try
                {

                    $_svtObject = Send-HPOVRequest $_svt -ApplianceConnection $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [void]$_SVTCollection.Add($_svtObject)

            }

            # SVT passed is the Name
            elseif (($_svt -is [String]) -and (-not $_svt.startsWith("/rest")))
            {

                "[{0}] Received SVT Name {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_svt | Write-Verbose

                "[{0}] Getting SVT object from Get-HPOVStorageVolumeTemplate" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                ForEach ($_appliance in $ApplianceConnection)
                {

                    "[{0}] Processing '$_appliance' Appliance Connection [of $($ApplianceConnection.count)]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_svtObject = Get-HPOVStorageVolumeTemplate $_svt -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                    }

                    Catch
                    {
                        
                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_svtObject | ForEach-Object {

                        "[{0}] Adding '$($_.name)' SVT to collection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_SVTCollection.Add($_)

                    }

                }

            }

            # SVT passed is the object
            elseif ($_svt -is [PSCustomObject]) 
            {

                "[{0}] SVT Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_svt.name | Write-Verbose
                "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_svt.uri | Write-Verbose
                "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_svt.ApplianceConnection.Name | Write-Verbose
                "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_svt.category | Write-Verbose

                if ($_svt.category -ieq 'storage-volume-templates')
                {

                    If (-not $_svt.ApplianceConnection)
                    {

                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Template:$($Template.Name)" -TargetType PSObject -Message "The Template resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }                    

                    [void]$_SVTCollection.Add($_svt)

                }

                else 
                {

                    $ExceptionMessage = "The InputObject parameter value {0} is not a supported object type. Only 'storage-volume-templates' resources are permitted." -f $_svt.Name
                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }                
            
            }

        }

    }

    End
    {

        "[{0}] Processing $($_SVTCollection.count) SVT resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process SVT Resources
        ForEach ($_svtObject in $_SVTCollection)
        {

            if ($PSCmdlet.ShouldProcess($_svtObject.name,"Remove SVT from appliance '$($_svtObject.ApplianceConnection.Name)'")) 
            {

                "[{0}] Removing SVT '$($_svtObject.name)' from appliance '$($_svtObject.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($PSBoundParameters['Force'])
                    {

                        $_svtObject.uri += "?force=true"

                    }

                    Send-HPOVRequest -Uri $_svtObject.Uri -Method DELETE -AddHeader @{'If-Match' = $_svtObject.eTag } -Hostname $_svtObject.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVStorageVolumeTemplatePolicy 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "default")]
    [OutputType ([HPOneView.Appliance.GlobalSetting])]
    Param 
    (
    
        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # $_SVTPolicyCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '$($_appliance.Name)' Appliance Connection [of $($ApplianceConnection.Count)]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            "[{0}] Getting global setting value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_Policy = Send-HPOVRequest $applStorageVolumeTemplateRequiredPolicy -Hostname $_appliance

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            New-Object HPOneView.Appliance.GlobalSetting ($_Policy.name,
                                                          $_Policy.value,
                                                          $_Policy.eTag,
                                                          $_Policy.created,
                                                          $_Policy.modified,
                                                          $_Policy.group,
                                                          $_Policy.settingCategory,
                                                          $_Policy.uri,
                                                          $_Policy.ApplianceConnection)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVStorageVolumeTemplatePolicy 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (
    
        [Parameter (Mandatory, ParameterSetName = "Enable")]
        [Switch]$Enable,
              
        [Parameter (Mandatory, ParameterSetName = "Disable")]
        [Switch]$Disable,

        [Parameter (Mandatory = $False, ParameterSetName = "Enable")]
        [Parameter (Mandatory = $False, ParameterSetName = "Disable")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SVTPolicyCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '$($_appliance.Name)' Appliance Connection [of $($ApplianceConnection.Count)]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_request = NewObject -GlobalSetting

            $_request.name = 'StorageVolumeTemplateRequired'

            switch ($PSCmdlet.ParameterSetName) 
            {

                'Enable' 
                {

                    "[{0}] User requested to ENABLE the policy" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_request.value = 'true'

                }

                'Disable' 
                {
                    
                    "[{0}] User requested to DISABLE the policy" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $_request.value = 'false'
            
                }

            }

            try
            {

                $_updatedpolicy = Send-HPOVRequest -Uri $applStorageVolumeTemplateRequiredPolicy -Method PUT -Body $_request -Hostname $_appliance 

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_updatedpolicy.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.GlobalSetting')

            [void]$_SVTPolicyCollection.Add($_updatedpolicy)

        }
        
    }

    End 
    {

        Return $_SVTPolicyCollection

    }

}

function Get-HPOVStorageVolume 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "InputObject")]
        [ValidateNotNullOrEmpty()]
        [Alias ('ServerProfile', 'ServerProfileTemplate')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('VolumeName')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('SVT')]
        [object]$StorageVolumeTemplate,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Available,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "InputObject")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        #$volumeCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    { 

        "[{0}] ParameterSetName: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSCmdlet.ParameterSetName | Write-Verbose
        
        if ($InputObject)
        {

            "[{0}] InputObject category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            switch ($InputObject.category)
            {

                ${ResourceCategoryEnum.ServerProfile}
                {

                    "[{0}] Processing Server Profile: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
                    "[{0}] Storage Volume Attachments: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.sanStorage.volumeAttachments.Count | Write-Verbose
                    
                    ForEach ($_VolumeAttachment in $InputObject.sanStorage.volumeAttachments)
                    {

                        Try
                        {

                            $_StorageVolume = Send-HPOVRequest -Uri $_VolumeAttachment.volumeUri -HostName $InputObject.ApplianceConnection

                            $_StorageVolume.PSobject.TypeNames.Insert(0,'HPOneView.Storage.Volume')

                            $_StorageVolume

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

                'storage-systems'
                {

                    "[{0}] Processing Storage System: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                    "[{0}] Getting associated Storage Pools with system" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_Uri = "{0}?filter=storageSystemUri EQ '{1}'&filter=isManaged EQ true" -f $StoragePoolsUri, $InputObject.uri
                        $_AssociatedPools = Send-HPOVRequest -Uri $_Uri -Hostname $InputObject.ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    "[{0}] Associated Storage Pools with system: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_AssociatedPools.count | Write-Verbose

                    if ($_AssociatedPools.members)
                    {

                        ForEach ($_AssociatedPool in $_AssociatedPools.members)
                        {

                            "[{0}] Getting associated storage volumes with pool: " -f $MyInvocation.InvocationName.ToString().ToUpper(), $_AssociatedPool.name | Write-Verbose

                            Try
                            {

                                $_Uri = "{0}?filter=storagePoolUri EQ '{1}'" -f $StorageVolumesUri, $_AssociatedPool.uri
                                $_AssociatedVols = Send-HPOVRequest -Uri $_Uri -Hostname $InputObject.ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            "[{0}] Associated storage vols with pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_AssociatedVols.count | Write-Verbose

                            if ($_AssociatedVols.members)
                            {

                                $_AssociatedVols.members | ForEach-Object {

                                    $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.Volume')
                                    $_

                                }

                            }

                        }

                    }

                }

                'storage-pools'
                {

                    "[{0}] Processing Storage Pool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                    Try
                    {

                        $_Uri = "{0}?filter=storagePoolUri EQ '{1}'" -f $StorageVolumesUri, $InputObject.uri
                        $_AssociatedVols = Send-HPOVRequest -Uri $_Uri -Hostname $InputObject.ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    if ($_AssociatedVols.members)
                    {

                        $_AssociatedVols.members | ForEach-Object {

                            $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.Volume')
                            $_

                        }

                    }

                }

                default
                {

                    $ExceptionMessage = "The InputObject parameter value is not supported. Only Server Profile, Storage System and Storage Pool objects are supports."
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'InputObject' -TargetType $InputObject.gettype().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                }

            }

        }

        else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                $_Query = [System.Collections.ArrayList]::new()

                # Handle default cause of AllResourcesInScope
                if ($Scope -eq 'AllResourcesInScope')
                {
    
                    "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                    $_Scopes = $_appliance.ActivePermissions | Where-Object Active
    
                    # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                    if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                    {
    
                        $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                        "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                    }
    
                    # Process ApplianceConnection ActivePermissions collection
                    else
                    {
    
                        Try
                        {
    
                            $_ScopeQuery = Join-Scope $_Scopes
    
                        }
    
                        Catch
                        {
    
                            $PSCmdlet.ThrowTerminatingError($_)
    
                        }
    
                        [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                    }
    
                }
    
                elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
                {
    
                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                elseif ($Scope -eq 'AllResources')
                {
    
                    "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                else
                {
    
                    Try
                    {
    
                        $_ScopeQuery = Join-Scope $Scope
    
                    }
    
                    Catch
                    {
    
                        $PSCmdlet.ThrowTerminatingError($_)
    
                    }
    
                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                }

                if ($Name)
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    if ($Name.Contains('*'))
                    {

                        [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                    }

                    else
                    {

                        [Void]$_Query.Add(("name:'{0}'" -f $Name))

                    }                
                    
                }

                if ($Label)
                {

                    "[{0}] Filtering for Label: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Label | Write-Verbose

                    [Void]$_Query.Add(("labels:'{0}'" -f $Label))

                }

                if ($PSBoundParameters['StorageVolumeTemplate'])
                {
                
                    "[{0}] Filtering for StorageVolumeTemplate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    switch ($StorageVolumeTemplate.GetType().Name)
                    {

                        'String'
                        {

                            Try
                            {

                                $_StorageVolumeTemplate = Get-HPOVStorageVolumeTemplate -Name $StorageVolumeTemplate -ApplianceConnection $_appliance -ErrorAction Stop

                            }

                            Catch
                            {

                                $PSCMdlet.ThrowTerminatingError($_)

                            }

                        }

                        'PSCustomObject'
                        {

                            if ($StorageVolumeTemplate.category -ne 'storage-volume-templates')
                            {

                                $ExceptionMessage = "The provided StorageVolumeTemplate {0} object is not the correct resource category Please check the value and try again." -f $StorageVolumeTemplate.Name
                                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidStorageVolumeTemplateResource InvalidArgument 'StorageVolumeTemplate' -TargetType $StorageVolumeTemplate.GetType().Name -Message $ExceptionMessage
                                $PSCMdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            $_StorageVolumeTemplate = $StorageVolumeTemplate.PSObject.Copy()

                        }

                    }

                    [Void]$_Query.Add(("volumeTemplateUri:'{0}'" -f $_StorageVolumeTemplate.uri))

                }

                $_Category = 'category=storage-volumes'

                # Build the final URI
                $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri, [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

                Try
                {

                    $_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($Available)
                {

                    "[{0}] Looking for available volumes to attach." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Label | Write-Verbose

                    if ($_ResourcesFromIndexCol -is [System.Collections.IEnumerable])
                    {

                        $_TempCollection = $_ResourcesFromIndexCol.Clone()

                    }

                    else
                    {

                        $_TempCollection = $_ResourcesFromIndexCol.PSObject.Copy()

                    }

                    ForEach ($_member in $_TempCollection)
                    {

                        if (-not $_member.isShareable)
                        {

                            # Check to see if there is an existing volume attachment
                            Try
                            {

                                $_uri = '{0}?childUri={1}&name=server_profiles_to_storage_volumes' -f $AssociationsUri, $_member.uri

                                $_VolAttachments = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            if ($_VolAttachments.count -gt 0)
                            {

                                "[{0}] Volume attachment found for {1}. Removing from final collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.name | Write-Verbose

                                $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object name -ne $_member.name

                            }                            

                        }

                    }

                }

                if ($_ResourcesFromIndexCol.Count -eq 0)
                {
                    
                    if ($Name) 
                    { 
                        
                        "[{0}] '{1}' Storage Volume found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                        $ExceptionMessage = "No Storage Volume with '{0}' name found on '{1}' appliance connection. Please check the name or use New-HPOVStorageVolume to create the volume." -f $Name, $_appliance.Name
                        $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException StorageVolumeResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage 
                        $PSCmdlet.WriteError($ErrorRecord)

                    }

                    else 
                    {

                        "[{0}] No Storage Volumes found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }
                            
                }
                    
                else 
                {

                    ForEach ($_member in $_ResourcesFromIndexCol)
                    { 

                        $_member.PSObject.TypeNames.Insert(0,"HPOneView.Storage.Volume") 
                        
                        $_member
                        
                    }     
                    
                }

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVStorageVolumeSnapShot
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Name', 'Volume')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process 
    { 
        
        # Generate error Volume is not an object
        if (-not($InputObject -is [PSCustomObject]) -and $InputObject.category -ne 'storage-volumes')
        {

            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageVolumeResource InvalidArgument 'Volume' -TargetType $Volume.GetType().Name -Message "The provided Volume Parameter value is not a supported type or object. Please provide a Storage Volume resource object and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }


        "[{0}] Processing Storage Volume: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        $uri = $InputObject.uri + '/snapshots'

        # Send the query
        Try
        {

            $_VolumeSnapshots = Send-HPOVRequest -Uri $uri -appliance $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not($_VolumeSnapshots.members))
        {

            "[{0}] No Storage Volume Snapshots found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        else 
        {

            $_VolumeSnapshots.members | ForEach-Object { 

                $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.VolumeSnapshot") 
                    
                $_
                    
            }     

        }

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVStorageVolumeSnapshot
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Volume')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false)]
        [String]$Name = '{volumeName}_{timestamp}',

        [Parameter (Mandatory = $false)]
        [String]$Description,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
    }

    Process 
    { 

        # Generate error Volume is not an object
        if ($InputObject -isnot [PSCustomObject] -and $InputObject.category -ne 'storage-volumes')
        {

            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageVolumeResource InvalidArgument 'Volume' -TargetType $Volume.GetType().Name -Message "The provided Volume Parameter value is not a supported type or object. Please provide a Storage Volume resource object and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Processing Storage Volume: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        # Validate the volume is a support volume to create a snapshot of
        # Get Storage Pool and associated SS
        Try
        {

            $_AssociatedPool = Send-HPOVRequest -Uri $InputObject.storagePoolUri -Hostname $ApplianceConnection
            $_AssociatedSS   = Send-HPOVRequest -Uri $_AssociatedPool.storageSystemUri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        # Validate SS family
        if ($_AssociatedSS.family -ne 'StoreServ')
        {

            $ExceptionMessage = "The Storage System {0} family ({1}) of the associated storage volume, {2}, is not a StoreServ system. Volume snapshots are supported with StoreServ class of storage systems." -f $_AssociatedSS.name, $_AssociatedPool.name, $InputObject.name
            $ErrorRecord = New-ErrorRecord ArgumentException InvalidArgumentType InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $uri = $InputObject.uri + '/snapshots'

        # Send the query
        Try
        {

            $_VolSnapshot = NewObject -VolSnapshot

            $_VolSnapshot.name        = $Name
            $_VolSnapshot.description = $Description

            $_VolumeSnapshotResp = Send-HPOVRequest -Uri $uri -Method POST -Body $_VolSnapshot -appliance $ApplianceConnection

        }

        Catch
        {

            # Return any task resources at this point, then generate error
            $_VolumeSnapshotCollection

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_VolumeSnapshotResp | Wait-HPOVTaskComplete

        }

        else
        {

            $_VolumeSnapshotResp

        }

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVStorageVolumeSnapshot
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Snapshot')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_VolumeSnapshotCollection = [System.Collections.ArrayList]::new()
        $_TaskCollection           = [System.Collections.ArrayList]::new()

    }

    Process 
    { 
        
        # Generate error Snapshot is not an object or correct object
        if (-not($InputObject -is [PSCustomObject]) -and $InputObject.category -ne 'storage-volumes' -and (-not($InputObject -match '/snapshots/')))
        {

            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageVolumeResource InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "The provided Volume Snapshot Parameter value is not a supported type or object. Please provide a Storage Volume Snapshot resource object and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Received Storage Volume Snapshot: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        [void]$_VolumeSnapshotCollection.Add($InputObject)

    }

    End 
    {

        "[{0}] Processing {1} Storage Volume Snapshot resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper(),$_VolumeSnapshotCollection.count | Write-Verbose 

        # Process Resources
        ForEach ($_resource in $_VolumeSnapshotCollection)
        {

            if ($PSCmdlet.ShouldProcess($_resource.ApplianceConnection.Name,("remove volume snapshot '{0}'" -f $_resource.name))) 
            {

                "[{0}] Removing resource '{1}' from appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_resource.name,$_resource.ApplianceConnection | Write-Verbose 

                Try
                {
                    
                    $_resp = Send-HPOVRequest -uri $_resource.Uri -Method DELETE -AddHeader @{'If-Match' = $_resource.eTag } -Hostname $_resource.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            if (-not $PSBoundParameters['Async'])
            {

                $_resp | Wait-HPOVTaskComplete

            }

            else
            {

                $_resp

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function ConvertTo-HPOVStorageVolume
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty ()]
        [Alias ('Snapshot')]
        [Object]$InputObject,

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty ()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty ()]
        [String]$Description,

        [Parameter (Mandatory = $false)]
        [ValidateSet ('Private', 'Shared')]
        [String]$SharingMode,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty ()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_VolumeSnapshotTaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    { 
        
        # Generate error Snapshot is not an object or correct object
        if (-not($InputObject -is [PSCustomObject]) -and $InputObject.category -ne 'storage-volumes' -and (-not($InputObject -match '/snapshots/')))
        {

            $ExceptionMessage = "The provided InputObject parameter value is not a supported type or object. Please provide a Storage Volume Snapshot resource object and try again."
            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageSnapshotResource InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Processing Storage Volume Snapshot: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        $_ConvertSnapshotToVol                        = NewObject -ConvertSnapshotToVol
        $_ConvertSnapshotToVol.properties.name        = $Name
        $_ConvertSnapshotToVol.properties.description = $Description
        $_ConvertSnapshotToVol.snapshotUri            = $InputObject.uri
        
        # Get parent volume snapshotUri value
        Try
        {

            $_ParentVol = Send-HPOVRequest -Uri $InputObject.storageVolumeUri -Hostname $InputObject.ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_ConvertSnapshotToVol.properties.snapshotPool     = $_ParentVol.deviceSpecificAttributes.snapshotPoolUri
        $_ConvertSnapshotToVol.properties.storagePool      = $_ParentVol.storagePoolUri
        $_ConvertSnapshotToVol.properties.provisioningType = $_ParentVol.provisioningType

        if (-not $_ParentVol.volumeTemplateUri) 
        {

            # Need to get root template from system via storage pool
            try
            {

                $_AssociatedPool = Send-HPOVRequest -Uri $_ParentVol.storagePoolUri -Hostname $InputObject.ApplianceConnection.Name

                "[{0}] Getting storage system root volume template." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $_Uri = '{0}/templates?filter=isRoot EQ true' -f $_AssociatedPool.storageSystemUri
                $_RootTemplate = (Send-HPOVRequest -Uri $_Uri -Hostname $InputObject.ApplianceConnection.Name).members[0]

                $_ConvertSnapshotToVol.templateUri = $_RootTemplate.uri

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            $_ConvertSnapshotToVol.templateUri = $_ParentVol.volumeTemplateUri    
            
        }

        if (-not $PSBoundParameters['SharingMode'])
        {

            $_ConvertSnapshotToVol.properties.isShareable = $_ParentVol.isShareable

        }

        else
        {

            $_ConvertSnapshotToVol.properties.isShareable = $SharingMode.IsPresent

        }
        
        # Send the query
        Try
        {

            $_VolumeSnapshotResp = Send-HPOVRequest -Uri $StorageVolumeFromSnapshotUri -Method POST -Body $_ConvertSnapshotToVol -appliance $InputObject.ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_VolumeSnapshotResp | Wait-HPOVTaskComplete

        }

        else
        {

            $_VolumeSnapshotResp

        }

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVStorageVolume 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "default")]
        [Parameter (Mandatory, ParameterSetName = "template")]
        [ValidateNotNullOrEmpty()]
        [Alias ("VolumeName")]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("pool","poolName")]
        [HPOneView.Storage.StoragePool]$StoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Storage.StoragePool]$SnapshotStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [object]$StorageSystem,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ValidateSet ('NetworkRaid0None','NetworkRaid5SingleParity','NetworkRaid10Mirror2Way','NetworkRaid10Mirror3Way','NetworkRaid10Mirror4Way','NetworkRaid6DualParity')]
        [String]$DataProtectionLevel,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Switch]$EnableAdaptiveOptimization,

        [Parameter (Mandatory, ParameterSetName = "template")]
        [ValidateNotNullOrEmpty()]
        [Alias ('template','svt')]
        [object]$VolumeTemplate,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ValidateScript({$_ -ge 1})]
        [Alias ("size")]
        [int64]$Capacity,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ALias ("ProvisionType")]
        [ValidateSet ('Thin', 'Full', 'TPDD')]
        [String]$ProvisioningType,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Bool]$EnableCompression,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Bool]$EnableDeduplication,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Switch]$Full,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Switch]$Shared,
        
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [HPOneView.Storage.PerformancePolicy]$PerformancePolicy,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Bool]$EnableEncryption,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Bool]$CachePinning,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [HPOneView.Storage.VolumeSet]$VolumeSet,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Bool]$EnableIOPSLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ValidateRange (256,4294967295)]
        [Int]$IOPSLimit = 256,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Bool]$EnableDataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Int]$DataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [HPOneView.Storage.NimbleFolder]$Folder,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "template")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "template")]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['StoragePool']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        if ($PSBoundParameters['Thin'])
        {

            $ExceptionMessage = 'The -Thin parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)
            
            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Thin'])

        }
        
        if ($PSBoundParameters['Full'])
        {

            $ExceptionMessage = 'The -Full parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Full'])

        }

        if ($PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = 'The -ProvisioningType "TPDD" value is being deprecated. Please update your script(s) to use the "Thin" value and -EnableCompression $True parameter.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']
            $PSBoundParameters.Add('EnableCompression', $True)
            
        }

        if ($PSBoundParameters['StorageSystem'])
        {

            $ExceptionMessage = "The -StorageSystem is deprecated. Please update your script(s) to use Get-HPOVStoragePool to get the specific pool object."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        # Need to generate an error
        if ($PSBoundParameters['Family'] -eq 'Nimble' -and $PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = "The provided ProvisioningType policy '{0}' is not supported by Nimble. Please update your script to use either 'Thin' or 'Full'. Setting ProvisioningType parameter to 'Thin'." -f $ProvisioningType
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'ProvisioningType' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']

        }

        $_AllowedNimbleParams    = "PerformancePolicy", "LockPerformancePolicy", "EnableEncryption", "CachePinning", "VolumeSet", "EnableIOPSLimit", "IOPSLimit", "EnableDataTransferLimit", "DataTransferLimit", "Folder"
        $_AllowedSSParams        = "EnableCompression", "EnableDeduplication", "SnapshotStoragePool"
        $_AllowedSVParams        = "DataProtectionLevel", "EnableAdaptiveOptimization"
        $_NotAllowedNimbleParams = $_AllowedSSParams + $_AllowedSVParams
        $_NotAllowedSSParams     = $_AllowedNimbleParams + $_AllowedSVParams
        $_NotAllowedVSParams     = $_AllowedSSParams + $_AllowedNimbleParams
        $_SafeParams             = "Name", "Description", "StoragePool", "StorageSystem", "VolumeTemplate", "Capacity", "ProvisioningType", "Full", "Shared", "Scope", "Async", "ApplianceConnection"

    }

    Process 
    {

        $ExceptionMessageString = "The provided {0} parameter is not supported by the {1} storage family."

        $_newVolume = NewObject -StorageVolume

        # Check to see if Storage Volume Template Global Setting is enabled
        Try
        {

            "[{0}] Checking for SVT Global Policy." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_storageVolumeTemplateRequiredGlobalPolicy = (Send-HPOVRequest $applStorageVolumeTemplateRequiredPolicy -Hostname $ApplianceConnection).value

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        if ($_storageVolumeTemplateRequiredGlobalPolicy -ieq "True" -and (-not $PSBoundParameters['VolumeTemplate'] -or -not $VolumeTemplate))
        { 
        
            $ExceptionMessage = "Storage Volumes cannot be created without providing a Storage Volume Template due to global policy setting. Please provide a Storage Volume Template and try again."
            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException StorageVolumeTemplateRequired InvalidArgument 'VolumeTemplate' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
        }

        # Figure out what type of Volume we will create
        if ($PSBoundParameters['VolumeTemplate'])
        {

            if ($VolumeTemplate.category -ne 'storage-volume-templates')
            {

                $ExceptionMessage = "The value provided for VolumeTemplate is not the allowed resource type, storage-volume-templates."
                $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeTemplateResourceException InvalidStorageVolumeTemplateResource InvalidArgument 'VolumeTemplate' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Storage Volume Template provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.name | Write-Verbose
            "[{0}] Storage Volume Template family: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.family | Write-Verbose

            $_Family = $VolumeTemplate.family

        }
        
        # Storage Pool was provided
        else
        {

            "[{0}] No Storage Volume Template provided. Processing StoragePool." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($StoragePool -is [String])
            {

                "[{0}] Locating storage pool resource: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StoragePool | Write-Verbose

                Try
                {

                    $StoragePool = GetStoragePool -Name $StoragePool -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection

                }
            
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            # Get Storage System
            Try
            {

                $_StorageSystem = Send-HPOVRequest -Uri $StoragePool.storageSystemUri -Hostname $StoragePool.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_StoragePool = $StoragePool.PSObject.Copy()

            $_StoragePool | Add-Member -NotePropertyName family -NotePropertyValue $_StorageSystem.family

            "[{0}] Storage Pool family: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePool.family | Write-Verbose

            $_Family = $_StoragePool.family

            # Need to get the root ST since none was provided
            Try
            {

                $_Uri = "{0}/templates?query=isRoot EQ true" -f $_StoragePool.storageSystemUri
                $_StorageSystemRootVolumeTemplate = Send-HPOVRequest -Uri $_Uri -ApplianceConnection $ApplianceConnection
                $VolumeTemplate = $_StorageSystemRootVolumeTemplate.members[0]

            }
        
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        # Look to see if $PSBoundParameters contains unallowed parameters
        ForEach ($_Param in $PSBoundParameters.Keys)
        {

            # First check if the param is not within the safe, allowed params for all
            if ($_SafeParams -notcontains $_Param)
            {

                $ExceptionMessage = $null

                switch ($_Family)
                {

                    'Nimble'
                    {

                        # Generate an error that the parameter is not supported by the storage system family
                        if ($_NotAllowedNimbleParams -contains $_Param)
                        {

                            $ExceptionSource = 'Invalid{0}Parameter' -f $_Param
                            $ExceptionMessage = $ExceptionMessageString -f $_Param, $_Family
                            
                        }

                    }

                    'StoreVirtual'
                    {

                        # Generate an error that the parameter is not supported by the storage system family
                        if ($_NotAllowedVSParams -contains $_Param)
                        {

                            $ExceptionSource = 'Invalid{0}Parameter' -f $_Param
                            $ExceptionMessage = $ExceptionMessageString -f $_Param, $_Family

                        }

                    }

                    '3Par'
                    {

                        # Generate an error that the parameter is not supported by the storage system family
                        if ($_NotAllowedSSParams -contains $_Param)
                        {

                            $ExceptionSource = 'Invalid{0}Parameter' -f $_Param
                            $ExceptionMessage = $ExceptionMessageString -f $_Param, $_Family

                        }

                    }

                }

                if (-not [String]::IsNullOrEmpty($ExceptionMessage))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException $ExceptionSource InvalidOperation $_Param -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        $_newVolume = NewObject -StorageVolume

        "[{0}] Setting volume template uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.uri | Write-Verbose

        $_newVolume.templateUri = $VolumeTemplate.uri

        # Create properties hashtable specific to the volume template and associated storage system family
        ForEach ($_Prop in ($VolumeTemplate.properties.PSObject.Members | Where-Object MemberType -eq 'NoteProperty'))
        {

            $_PropName = $_Prop.Name

            "[{0}] Adding volume property to hashtable: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PropName | Write-Verbose
            $_newVolume.properties.Add($_PropName, $VolumeTemplate.properties.$_PropName.default)

        }

        # Set the values
        switch ($_newVolume.properties.GetEnumerator().Name)
        {

            # Common properties
            'name'
            {

                "[{0}] Setting volume name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose
                $_newvolume.properties.$_ = $Name

            }

            'description'
            {

                if ($PSBoundParameters['Description'])
                {

                    "[{0}] Setting volume description: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Description | Write-Verbose
                    $_newvolume.properties.$_ = $Description

                }                

            }

            'templateVersion'
            {

                "[{0}] Setting volume {1}: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.version | Write-Verbose
                $_newVolume.properties.$_ = $VolumeTemplate.version

            }

            'storagePool'
            {

                # If SVT enforces, set it
                if ($VolumeTemplate.properties.$_.meta.locked -or -not $PSBoundParameters['StoragePool'])
                {

                    "[{0}] Volume Template enforces StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.storagePool.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default
                    
                }

                else
                {

                    "[{0}] Setting StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePool.uri | Write-Verbose

                    $_newvolume.properties.storagePool = $_StoragePool.uri

                }

            }

            'size'
            {

                if ($VolumeTemplate.properties.size.meta.locked -or (-not $PSBoundParameters['Capacity'] -and -not $VolumeTemplate.properties.size.meta.locked))
                {

                    "[{0}] Volume Template enforces volume capacity: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.size.default | Write-Verbose

                    $_newvolume.properties.size = $VolumeTemplate.properties.size.default

                }
                
                else
                {

                    $_newvolume.properties.size = $Capacity * 1GB

                }

            }

            'provisioningType'
            {

                if ($VolumeTemplate.properties.provisioningType.meta.locked -or (-not $PSBoundParameters['Full'] -and -not $PSBoundParameters['ProvisioningType'] -and -not $VolumeTemplate.properties.provisioningType.meta.locked))
                {

                    "[{0}] Volume Template enforces volume provisioningType: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.provisioningType.default | Write-Verbose
                    $_newvolume.properties.provisioningType = $VolumeTemplate.properties.provisioningType.default

                }
                
                else
                {

                    if ($PSBoundParameters['ProvisioningType'])
                    {

                        "[{0}] Setting volume provisioningType via ProvisioningType param: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageVolumeProvisioningTypeEnum[$ProvisioningType] | Write-Verbose

                        $_newvolume.properties.provisioningType = $StorageVolumeProvisioningTypeEnum[$ProvisioningType]

                    }

                    else
                    {

                        "[{0}] Setting volume provisioningType via not full param: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageVolumeProvisioningTypeEnum['Thin'] | Write-Verbose

                        $_newvolume.properties.provisioningType = $StorageVolumeProvisioningTypeEnum['Thin']

                    }

                }

            }

            'isShareable'
            {

                if ($VolumeTemplate.properties.isShareable.meta.locked -or (-not $PSBoundParameters['Shared'] -and -not $VolumeTemplate.properties.isShareable.meta.locked))
                {

                    "[{0}] Volume Template enforces volume shareable state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isShareable.default | Write-Verbose

                    $_newvolume.properties.isShareable = $VolumeTemplate.properties.isShareable.default

                }
                
                else
                {

                    $_newvolume.properties.isShareable = $Shared.IsPresent

                }

            }

            # 3Par specific
            'snapshotPool'
            {

                "[{0}] Family is StoreServ, attempting to set snapshot pool" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # If SVT enforces, set it
                if ($VolumeTemplate.properties.snapshotPool.meta.locked)
                {

                    "[{0}] Volume Template enforces Snapshot StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.snapshotPool.default | Write-Verbose

                    $_newvolume.properties.snapshotPool = $VolumeTemplate.properties.snapshotPool.default
                    
                }

                else
                {

                    if ($PSBoundParameters['SnapshotStoragePool'])
                    {

                        if ($SnapshotStoragePool -is [String])
                        {

                            try
                            {

                                $SnapshotStoragePool = GetStoragePool -Name $SnapshotStoragePool -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        "[{0}] Setting SnapshotStoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $SnapshotStoragePool.uri | Write-Verbose
                        
                        $_newvolume.properties.snapshotPool = $SnapshotStoragePool.uri

                    }

                    elseif (-not $PSBoundParameters['SnapshotStoragePool'] -and -not $PSBoundParameters['StoragePool'])
                    {

                        "[{0}] Setting SnapshotStoragePool to StoragePool from Volume Template: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.snapshotPool.default | Write-Verbose

                        $_newvolume.properties.snapshotPool = $VolumeTemplate.properties.snapshotPool.default

                    }
                    
                    else
                    {

                        "[{0}] Setting SnapshotStoragePool to StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StoragePool.uri | Write-Verbose

                        $_newvolume.properties.snapshotPool = $StoragePool.uri

                    }                        

                }

            }

            'isDeduplicated'
            {

                "[{0}] Family is StoreServ, attempting to set Deduplicated" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # If SVT enforces, set it
                if ($VolumeTemplate.properties.isDeduplicated.meta.locked -or $PSBoundParameters.Keys -NotContains 'EnableDeduplication')
                {

                    "[{0}] Volume Template enforces Deduplicate: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.$_.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default
                    
                }

                else
                {

                    "[{0}] Setting Deduplicate: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableDeduplication | Write-Verbose

                    $_newvolume.properties.$_ = $EnableDeduplication

                }

            }

            'isCompressed'
            {

                "[{0}] Family is 3Par, attempting to set Compression" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # If SVT enforces, set it
                if ($VolumeTemplate.properties.$_.meta.locked -or $PSBoundParameters.Keys -NotContains 'EnableCompression')
                {

                    "[{0}] Volume Template enforces Compression: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isCompressed.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default
                    
                }

                else
                {

                    "[{0}] Setting compression: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableCompression | Write-Verbose

                    $_newvolume.properties.$_ = $EnableCompression

                }

            }

            # StoreVirtual specific
            'dataProtectionLevel'
            {

                if ($VolumeTemplate.properties.dataProtectionLevel.meta.locked -or (-not $PSBoundParameters['DataProtectionLevel'] -and -not $VolumeTemplate.properties.dataProtectionLevel.meta.locked))
                {

                    "[{0}] Volume Template enforces DataProtectionLevel: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.dataProtectionLevel.default | Write-Verbose

                    $_newvolume.properties.dataProtectionLevel = $VolumeTemplate.properties.dataProtectionLevel.default

                }
                
                else
                {

                    $_DataProtectionLevel = $VolumeTemplate.properties.dataProtectionLevel.enum | Where-Object { $_ -eq $DataProtectionLevel }

                    if (-not $_DataProtectionLevel)
                    {

                        $ExceptionMessage = "The requested data protection level, {0}, is not supported with the storage system. Please correctthe value with one of the following options: {1}" -f $DataProtectionLevel, ([String]::Join(', ', $VolumeTemplate.properties.dataProtectionLevel.enum))
                        $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedProtectionLevelValue InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
                    
                        # Generate Terminating Error
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                    }

                    $_newvolume.properties.dataProtectionLevel = $_DataProtectionLevel

                }

            }

            'isAdaptiveOptimizationEnabled'
            {

                if ($VolumeTemplate.properties.isAdaptiveOptimizationEnabled.meta.locked -or (-not $PSBoundParameters['EnableAdaptiveOptimization'] -and -not $VolumeTemplate.properties.isAdaptiveOptimizationEnabled.meta.locked))
                {

                    "[{0}] Volume Template enforces AdaptiveOptimizationEnabled: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isAdaptiveOptimizationEnabled.default | Write-Verbose

                    $_newvolume.properties.isAdaptiveOptimizationEnabled = $VolumeTemplate.properties.isAdaptiveOptimizationEnabled.default

                }
                
                else
                {

                    $_newvolume.properties.isAdaptiveOptimizationEnabled = $EnableAdaptiveOptimization.IsPresent

                }

            }

            # Nimble specific
            'performancePolicy'
            {

                if ($VolumeTemplate.properties.performancePolicy.meta.locked) # -or (-not $PSBoundParameters['PerformancePolicy'] -and -not $VolumeTemplate.properties.performancePolicy.meta.locked))
                {

                    "[{0}] Volume Template enforces performancePolicy state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.PerformancePolicy.default | Write-Verbose

                    $_newvolume.properties.performancePolicy = $VolumeTemplate.properties.performancePolicy.default

                }

                elseif (-not $PSBoundParameters['PerformancePolicy'])
                {
                
                    $_StorageSystemDefaultPerformancePolicy = $_StorageSystem.deviceSpecificAttributes.performancePolicies | ? name -eq $_StoragePool.name
                    
                    "[{0}] Volume Template does not enforce performancePolicy, setting default state: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StorageSystemDefaultPerformancePolicy.name, $_StorageSystemDefaultPerformancePolicy.id | Write-Verbose

                    $_newvolume.properties.performancePolicy = $_StorageSystemDefaultPerformancePolicy.id
                
                }
                
                else
                {

                    $_newvolume.properties.performancePolicy = $PerformancePolicy.Id

                }

            }

            'folder'
            {

                if ($VolumeTemplate.properties.folder.meta.locked -or (-not $PSBoundParameters['Folder'] -and -not $VolumeTemplate.properties.folder.meta.locked))
                {

                    "[{0}] Volume Template enforces folder state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.folder.default | Write-Verbose

                    $_newvolume.properties.folder = $VolumeTemplate.properties.folder.default

                }
                
                else
                {

                    $_newvolume.properties.folder = $Folder.Id

                }

            }

            'volumeSet'
            {

                if ($VolumeTemplate.properties.volumeSet.meta.locked -or (-not $PSBoundParameters['VolumeSet'] -and -not $VolumeTemplate.properties.volumeSet.meta.locked))
                {

                    "[{0}] Volume Template enforces volumeSet state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.volumeSet.default | Write-Verbose

                    $_newvolume.properties.volumeSet = $VolumeTemplate.properties.volumeSet.default

                }
                
                else
                {

                    $_newvolume.properties.volumeSet = $VolumeSet.Uri

                }

            }

            'isEncrypted'
            {

                if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'EnableEncryption' -and -not $VolumeTemplate.properties.$_.meta.locked))
                {

                    "[{0}] Volume Template enforces isEncrypted state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.$_.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default

                }
                
                else
                {

                    $_newvolume.properties.$_ = $EnableEncryption

                }

            }

            'isPinned'
            {

                if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'CachePinning' -and -not $VolumeTemplate.properties.$_.meta.locked))
                {

                    "[{0}] Volume Template enforces {1} state: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.properties.$_.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default

                }
                
                else
                {

                    $_newvolume.properties.$_ = $EnableEncryption

                }

            }

            'iopsLimit'
            {

                if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'EnableIOPSLimit' -and -not $VolumeTemplate.properties.$_.meta.locked))
                {

                    "[{0}] Volume Template enforces {1} state: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.properties.$_.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default

                }
                
                else
                {

                    $_newvolume.properties.$_ = $IOPSLimit

                }

            }

            'dataTransferLimit'
            {

                if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'EnableDataTransferLimit' -and -not $VolumeTemplate.properties.$_.meta.locked))
                {

                    "[{0}] Volume Template enforces {1} state: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.properties.$_.default | Write-Verbose

                    $_newvolume.properties.$_ = $VolumeTemplate.properties.$_.default

                }
                
                else
                {

                    $_newvolume.properties.$_ = $DataTransferLimit

                }

            }

        }

        if ($PSBoundParameters['Scope'])
        {

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_newVolume.initialScopeUris.Add($_Scope.Uri)

            }

        }

        # Send the request
        Try
        {

            $_Resp = Send-HPOVRequest -Uri $StorageVolumesUri -Method POST -Body $_newVolume -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-Not $PSBoundParameters['Async'])
        {

            $_Resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_Resp

        }

    }

    End 
    {
        
        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function GetStoragePool
{

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("pool","poolName",'Name', 'StoragePool')]
        [Object]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [object]$StorageSystem,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection

    )

    Process
    {

        switch ($InputObject.Gettype().Name) 
        {

            "String" 
            { 
                        
                # Parameter is correct URI
                if ($InputObject.StartsWith($StoragePoolsUri))
                {

                    "[{0}] StoragePool URI provided by caller." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Sending request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                                       
                    Try
                    {

                        $_sp = Send-HPOVRequest -Uri $InputObject -Hostname $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                                                
                }

                # Parameter is incorrect URI value
                elseif ($InputObject.StartsWith("/rest")) 
                {

                    # Invalid Parameter value, generate terminating error.
                    $ExceptionMessage = "Invalid StoragePool Parameter value: {1}. Please correct and try again." -f $InputObject
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidArgumentValue InvalidArgument 'InputObject' -Message 
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Parameter is Storage Pool name
                else 
                {
                                
                    "[{0}] StoragePool Name provided by caller." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                
                    # Get specific storage pool from provided StorageSystem
                    if ($InputObject) 
                    { 

                        # First look for the StorageSystem Parameter value, and get the StoragePool by filtering on the StorageSystem value.
                        Try
                        {
                                        
                            $_sp = Get-HPOVStoragePool -Name $InputObject -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection -ErrorAction Stop
                                        
                        }
                                    
                        Catch
                        {
                                    
                            $PSCmdlet.ThrowTerminatingError($_)
                                    
                        }

                    }

                    else 
                    {
                                        
                        Try
                        {
                                            
                            $_sp = Get-HPOVStoragePool -Name $InputObject -ApplianceConnection $ApplianceConnection -ErrorAction Stop
                                    
                        }
                                    
                        Catch
                        {
                                    
                            $PSCmdlet.ThrowTerminatingError($_)
                                    
                        }
                                    
                    }
                                    
                    # If multiple Storage Pool Resources are returned that are of the same name, generate error and indicate the -StorageSystem Parameter is needed.
                    # Validate that the storage pool object is unique and not a collection
                    if(($_sp | Measure-Object).Count -gt 1)
                    {
                                    
                        "[{0}] Multiple Storage Pool resources of the name '$InputObject'. $($_sp.count) resources found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                        
                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidStoragePoolResource ObjectNotFound 'InputObject' -TargetType 'Array' -Message "Multiple Storage Pools it the '$tmpStoragePool' name were found. Please use the -StorageSystem Parameter to specify the Storage System the Pool is associated with, or use the Get-HPOVStoragePool cmdlet to get the Storage Pool resource and pass as the -StoragePool Parameter value."
                                        
                        # Generate Terminating Error
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                                    
                }

            }

            'StoragePool'
            {

                $_sp = $InputObject

            }

            "PSCustomObject" 
            { 
                        
                # Validate the object
                if ($InputObject.category -eq 'storage-pools') 
                { 
                                
                    # Check the StoragePool object to make sure the ApplianceConnection property matches the ApplianceConnection Parameter from caller
                    if ($InputObject.ApplianceConnection.Name -ne $ApplianceConnection.Name)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStoragePoolObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided StoragePool object does not appear to originate from the same ApplianceConnection specified - ApplianceConnection: $($ApplianceConnection.Name) StorageVolume ApplianceConnection $($StorageVolume.ApplianceConnection.Name)."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                                
                    $_sp = $InputObject.PSObject.Copy()
                            
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStoragePoolCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "Invalid StoragePool Parameter value. Expected Resource Category 'storage-pools', received '$($VolumeTemplate.category)'."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }                        
                        
            }

        }

    }

    End
    {

        Return $_sp

    }

}

function Add-HPOVStorageVolume 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [object]$StorageSystem,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("volid","id","wwn")]
        [String]$VolumeID,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$StorageDeviceName,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("Name")]
        [String]$VolumeName,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [String]$Description = "",

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Shared,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['StorageSystem']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        if ($PSBoundParameters['VolumeID'])
        {

            Write-Warning 'The -VolumeID parameter is now deprecated and is no longer used.'

        }

    }

    Process 
    {


        $_addVolume = NewObject -AddStorageVolume
        $_addVolume.deviceVolumeName = $StorageDeviceName
        $_addVolume.name             = $VolumeName
        $_addVolume.description      = $Description
        $_addVolume.isShareable      = $Shared.IsPresent

        Switch ($StorageSystem.GetType().Name) 
        {

            "String" 
            {
                            
                if ($StorageSystem.StartsWith($StorageSystemsUri))
                {

                    "[{0}] StorageSystem URI provided by caller." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Sending request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose   
                                         
                    Try
                    {

                        $_ss = Send-HPOVRequest -Uri $StorageSystem -Hostname $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

                elseif ($StorageSystem.StartsWith("/rest")) 
                {

                    # Invalid Parameter value, generate terminating error.
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidArgumentValue InvalidArgument 'StorageSystem' -Message "Invalid StorageSystem Parameter value: $($StorageSystem | out-string)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else 
                {
                                
                    "[{0}] StorageSystem Name provided by caller." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Sending request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get the storage volume template resource. Terminating error will throw from the Get-* if no resource is found.
                    Try
                    {

                        $_ss = Get-HPOVStorageSystem -SystemName $StorageSystem -ApplianceConnection $ApplianceConnection
                    
                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            "PSCustomObject" 
            {

                # Validate the object
                if ($StorageSystem.category -eq 'storage-systems' -and $StorageSystem.ApplianceConnection.Name -eq $ApplianceConnection.Name) 
                { 
                    
                    "[{0}] Storage System Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($StorageSystem.name) | Write-Verbose

                    $_ss = $StorageSystem.PSObject.Copy()
                
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageSystemCategory InvalidArgument 'StorageSystem' -TargetType PSObject -Message "Invalid StorageSystem Parameter value. Expected Resource Category 'storage-systems', received '$($VolumeTemplate.category)'."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            default 
            {
            
                $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageSystemObject InvalidArgument 'StorageSystem' -TargetType $StorageSystem.GetType().Name -Message "Invalid StorageSystem Parameter value object type. Only [PSCustomObject] or [String] values are allowed."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }
        
        }

        $_addVolume.storageSystemUri = $_ss.uri

        if ($PSBoundParameters['Scope'])
        {

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                [void]$_addVolume.initialScopeUris.Add($_Scope.Uri)

            }

        }

        "[{0}] Add Storage Volume Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_addVolume | Out-String) | Write-Verbose
 
        # Send the request
        Try
        {

            $_Uri = '{0}/from-existing' -f $StorageVolumesUri

            Send-HPOVRequest -Uri $_Uri -Method POST -Body $_addVolume -Hostname $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        #[void]$colStatus.Add($_resp)
        
    }

    End 
    {

        # Return $colStatus
        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVStorageVolume 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('SourceVolume')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('VolumeName')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [String]$Description,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateScript ({$_ -ge 1})]
        [Alias ("size")]
        [int64]$Capacity,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnapShotStoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateSet ('NetworkRaid0None','NetworkRaid5SingleParity','NetworkRaid10Mirror2Way','NetworkRaid10Mirror3Way','NetworkRaid10Mirror4Way','NetworkRaid6DualParity')]
        [String]$DataProtectionLevel,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Bool]$PermitAdaptiveOptimization,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Bool]$Shared,

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        # Get Source Volume resource
        Switch ($InputObject.GetType().Name) 
        {

            "String" 
            { 
                 
                # Parameter is correct URI
                if ($InputObject.StartsWith($StorageVolumesUri))
                {

                    "[{0}] Storage Volume URI provided by caller: $InputObject" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting volume resource object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_InputObject = Send-HPOVRequest $InputObject -hostname $ApplianceConnection

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                            
                }

                # Parameter is incorrect URI value
                elseif ($InputObject.StartsWith("/rest")) 
                {

                    # Invalid Parameter value, generate terminating error.
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidArgumentValue InvalidArgument 'InputObject' -Message "Invalid Storage Volume Parameter value: $($InputObject | out-string). Please correct and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Parameter is Storage Pool name
                else 
                {
                                
                    "[{0}] Storage Volume Name provided by caller." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                
                    Try
                    {

                        $_InputObject = Get-HPOVStorageVolume $InputObject -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }
                
            }

            "PSCustomObject" 
            {

                "[{0}] Storage Volume Object provided by caller." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | ConvertTo-Json -Depth 99) | Write-Verbose

                # Validate the object
                if ('storage-volumes' -ne $InputObject.category)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStoragePoolCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "Invalid Storage Volume Parameter value. Expected Resource Category 'storage-volumes', received '$($InputObject.category)'."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }    

                $_InputObject = $InputObject.PSObject.Copy()
                
            }

        }

        "[{0}] ORIGINAL Storage Volume object properties: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | out-string) | Write-Verbose

        # Get the Storage Pool object to identify the family
        Try
        {

            $_AssociatedStoragePool = Send-HPOVRequest -Uri $InputObject.storagePoolUri -Hostname $InputObject.ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Get the SVT associated with the Volume
        if ($InputObject.volumeTemplateUri)
        {

            Try
            {

                $_SVT = Send-HPOVRequest -Uri $InputObject.volumeTemplateUri -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }    

            "[{0}] Volume is associated with Volume Template: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_SVT.name | Write-Verbose

        }            

        # Volume Object updates
        switch ($PSboundParameters.keys) 
        {

            'Name'
            { 
                
                $_InputObject.name = $Name 
            
            }

            'Description'
            { 
                
                $_InputObject.description = $Description 
            
            }

            'Capacity' 
            { 

                if (-not $_SVT.properties.size.meta.locked)
                {

                    [int64]$_Capacity = $Capacity * 1GB

                    if ([int64]$_Capacity -gt [int64]$InputObject.provisionedCapacity) 
                    { 
                        
                        $_InputObject.provisionedCapacity = $_Capacity 
                    
                    }

                    # Generate Terminating Error
                    else 
                    { 
                    
                        $ExceptionMessage = "Invalid 'capacity' Storage Volume Parameter value. The value '{0}' is less than the original volume size '{1}'. Volume capacity cannot be reduced, only increased." -f [int64]$capacity, [int64]$InputObject.provisionedCapacity
                        $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStorageVolumeCapacityValue InvalidArgument 'Capacity' -TargetType 'Int' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                }
            
                else
                {

                    $ExceptionMessage = "The associated Storage Volume Template does not allow modifying the Storage Volumes capacity."
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException UnableToModifyCapacity PermissionDenied 'Capacity' -TargetType 'Int' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }                

            }

            'SnapShotStoragePool'
            {

                if (-not $_SVT.properties.snapshotPool.meta.locked -and $_AssociatedStoragePool.family -ne 'StoreVirtual')
                {

                    Try
                    {

                        $_SnapShotStoragePool = GetStoragePool -StoragePool $SnapShotStoragePool -ApplianceConnection $SnapShotStoragePool.ApplianceConnection
                        
                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    $_InputObject.deviceSpecificAttributes.snapshotPoolUri = $_SnapShotStoragePool.uri

                }
            
                elseif ($_SVT.properties.snapshotPool.meta.locked)
                {

                    $ExceptionMessage = "The associated Storage Volume Template does not allow modifying the Snapshot Storage Pool resource."
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException UnableToModifySnapshotStoragePool PermissionDenied 'SnapShotStoragePool' -TargetType $SnapShotStoragePool.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif ($_AssociatedStoragePool.family -eq 'StoreVirtual')
                {

                    $ExceptionMessage = "The associated Storage System family is a StoreVirtual system. Snapshot Storage Pool assignment is not supported."
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException UnsupportedStorageSystemFamily InvalidOperation 'SnapShotStoragePool' -TargetType $SnapShotStoragePool.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            'Shared'
            { 
                
                if (-not $_SVT.properties.isShareable.meta.locked)
                {

                    $_InputObject.shareable = [Bool]$Shared 

                }
            
                else
                {

                    $ExceptionMessage = "The associated Storage Volume Template does not allow modifying the shareability of the Storage Volume resource."
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException UnableToModifyCapacity PermissionDenied 'Shared' -TargetType $Shared.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }                
            
            }

            'DataProtectionLevel'
            {

                $_InputObject.deviceSpecificProperties.dataProtectionLevel = $DataProtectionLevelEnum[$DataProtectionLevel]

            }

            'PermitAdaptiveOptimization'
            {

                $_InputObject.deviceSpecificProperties.isAdaptiveOptimizationEnabled = $PermitAdaptiveOptimization

            }
            
        }
        
        # "[{0}] Updated Storage Volume object properties: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_InputObject ) | Write-Verbose

        "[{0}] Sending updated storage volume to appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            Send-HPOVRequest -Uri $_InputObject.uri -Method PUT -Body $_InputObject -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
       
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVStorageVolume 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('uri', 'name', 'StorageVolume')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$ExportOnly,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,
    
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_TaskCollection    = [System.Collections.ArrayList]::new()
        $_VolumeCollection  = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject])
        {

            "[{0}] Storage Volume Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            If ($InputObject.category -eq 'storage-volumes')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message "The Storage Volume resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_VolumeCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject:$($InputObject.Name)" -TargetType PSObject -Message "The Storage Volume resource is not an expected category type [$($StorageVolume.category)]. Allowed resource category type is 'storage-volumes'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($_vol in $InputObject) 
            {

                # Volume passed is a URI
                if (($_vol -is [String]) -and [System.Uri]::IsWellFormedUriString($_vol,'Relative')) 
                {

                    "[{0}] Received URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_vol | Write-Verbose
                    "[{0}] Getting Volume object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if (($ApplianceConnection | Measure-Object).Count -gt 1)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value when using a Storage Volume Template URI value. Please correct this and try again.'
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Try
                    {

                        $_volObject = Send-HPOVRequest -Uri $_vol -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [void]$_VolumeCollection.Add($_volObject)

                }

                # Volume passed is the Name
                elseif (($_vol -is [String]) -and (-not($_vol.startsWith("/rest")))) 
                {

                    "[{0}] Received Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_vol | Write-Verbose
                    "[{0}] Getting Volume object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    ForEach ($_appliance in $ApplianceConnection)
                    {

                        "[{0}] Processing '$_appliance' Appliance Connection [of $($ApplianceConnection.count)]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_volObject = Get-HPOVStorageVolume -Name $_vol -ApplianceConnection $_appliance -ErrorAction Stop

                        }

                        Catch
                        {
                            
                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $_volObject | ForEach-Object {

                            "[{0}] Adding '$($_.name)' Volume to collection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            [void]$_VolumeCollection.Add($_)

                        }

                    }

                }

                # Volume passed is the object
                elseif ($_vol -is [PSCustomObject] -and $_vol.category -ieq 'storage-volumes') 
                {
                    
                    "[{0}] Volume Object provided.)"-f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
                    "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
                    "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
                    "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
                    "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

                    [void]$_VolumeCollection.Add($_vol)
                
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "Invalid Volume Parameter: $($_vol | Out-String)"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

        }

    }

    End
    {

        "[{0}] Processing {1} Volume resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumeCollection.count | Write-Verbose

        # Process Volume Resources
        ForEach ($_volObject in $_VolumeCollection)
        {

            $_Uri = $_volObject.uri

            $_Operation = "Remove"

            $_AdditionalParams = [System.Collections.ArrayList]::new()

            if ($PSBoundParameters['Force'])
            {

                [void]$_AdditionalParams.Add('force=true')

            }

            if ($PSBoundParameters['ExportOnly'])
            {

                $_Operation += " Export only"

                [void]$_AdditionalParams.Add('suppressDeviceUpdates=true')

            }

            if ($_AdditionalParams.Count -gt 0)
            {

                $_Uri = '{0}?{1}' -f $_Uri, [String]::Join('&', $_AdditionalParams.ToArray())

            }

            $_RemoveMessage = "{0} Storage Volume from appliance '{1}'" -f $_Operation, $_volObject.ApplianceConnection

            if ($PSCmdlet.ShouldProcess($_volObject.name, $_RemoveMessage)) 
            {

                "[{0}] {1} Volume '{2}' and Export from appliance '{3}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Operation, $_volObject.name, $_volObject.ApplianceConnection | Write-Verbose

                Try
                {
                    
                    $_resp = Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = $_volObject.eTag } -Hostname $_volObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $PSBoundParameters['Async'])
                {

                    $_resp | Wait-HPOVTaskComplete

                }

                else
                {

                    $_resp

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVSanManager 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('SanManager')]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $SanManagerCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $uri = '{0}?sort=name:asc' -f $fcSanManagersUri

            if ($Name)
            {
                
                $uri = '{0}&query=name like "{1}"' -f $uri, $Name.Replace("*","%25").Replace("&","%26")

            }

            # Send Request
            "[{0}] Getting list of SAN Managers" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_sanManagers = Send-HPOVRequest -Uri $uri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Generate Terminating Error if resource not found
            if (-not($_sanManagers.members) -and $Name) 
            {

                "[{0}] Requested Managed SAN '{1}' not found on {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "Request SAN Manager '{0}' not found on '{1}'. Please check the name and try again." -f $Name, $_appliance.Name 
                $ErrorRecord = New-ErrorRecord InvalidOperationException SanManagerResourceNotFound ObjectNotFound 'SanManager' -Message $ExceptionMessage
                    
                # Generate Terminating Error
                $PSCmdlet.WriteError($ErrorRecord)

            }
            
            elseif (-not($_sanManagers.members)) 
            {

                "[{0}] No SAN Managers found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
            }

            else 
            {

                $_sanManagers.members | ForEach-Object { 
                    
                    $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.SanManager") 
                
                    [void]$SanManagerCollection.Add($_)
                
                }

            }

        }

    }

    End 
    {

        Return $SanManagerCollection

    }

}

function Add-HPOVSanManager 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "BNA")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory, ParameterSetName = "Brocade")]
        [ValidateSet ("Brocade", "BNA", "Brocade Network Advisor", "BrocadeFOS", "FOS", "HP", "HPE", "Cisco")]
        [String]$Type,

        [Parameter (Mandatory, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory, ParameterSetName = "Brocade")]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1,65535)]
        [Int]$Port = 0,
         
        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory, ParameterSetName = "HPCisco")]
        [String]$SnmpUserName,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateSet ("None","AuthOnly","AuthAndPriv")]
        [ValidateNotNullOrEmpty()]
        [String]$SnmpAuthLevel = "None",

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateSet ("sha","md5")]    
        [ValidateNotNullOrEmpty()]
        [String]$SnmpAuthProtocol,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpAuthPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateSet ("aes-128","des56","3des")]    
        [ValidateNotNullOrEmpty()]
        [String]$SnmpPrivProtocol,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpPrivPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [Switch]$UseSsl,
        
        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ParameterSetName = "Brocade")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $TaskCollection = [System.Collections.ArrayList]::new()

        if ($SnmpAuthLevel -eq "AuthOnly" -and 
            (-not $SnmpAuthProtocol -or 
            -not $SnmpAuthPassword)) 
        {

            # Generate Terminateing error
            $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException MissingRequiredParameters InvalidArgument 'Add-HPOVSanManager' -Message "The -SnmpAuthLevel Parameter was set to 'AuthOnly', but did not include both -SnmpAuthProtocol and -SnmpAuthPassword Parameters."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($SnmpAuthLevel -eq "AuthAndPriv" -and (
            -not $SnmpAuthProtocol -or 
            -not $SnmpAuthPassword -or 
            -not $SnmpPrivProtocol -or 
            -not $SnmpPrivPassword )) 
        {

            # Generate Terminateing error
            $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException MissingRequiredParameters InvalidArgument 'Add-HPOVSanManager' -Message "The -SnmpAuthLevel Parameter was set to 'AuthAndPriv', but did not include -SnmpAuthProtocol, -SnmpAuthPassword, -SnmpPrivProtocol and -SnmpPrivPassword Parameters."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Cisco MDS/Nexus SNMP Auth Parameter validation
        if ($type -eq 'Cisco' -and $SnmpAuthLevel -eq 'None')
        {

            $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException UnsupportedSnmpAuthLevel InvalidArgument 'SnmpAuthLevel' -Message "The -SnmpAuthLevel Parameter value $($SnmpAuthLevel) is invalid for configuring a Cisco SAN Manager. Please specify either 'AuthOnly' or 'AuthAndPriv' and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Cisco MDS/Nexus SNMP Auth Parameter validation
        if ($type -eq 'Cisco' -and $SnmpPrivProtocol -eq '3DES')
        {

            $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException UnsupportedSnmpPrivProtocol InvalidArgument 'SnmpPrivProtocol' -Message "The -SnmpPrivProtocol Parameter value $($SnmpPrivProtocol) is invalid for configuring a Cisco SAN Manager. Please specify either 'des56' or 'aes-128' and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($Password -is [System.Security.SecureString])
        {

            $Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        if ($SnmpPrivPassword -is [SecureString])
        {

            $SnmpPrivPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SnmpPrivPassword))

        }

        if ($SnmpAuthPassword -is [SecureString])
        {

            $SnmpAuthPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SnmpAuthPassword))

        }

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username and -Password parameters are deprecated. Please transition your scripts to using the -Credential parameter."

            $_Username = $Username.clone()

            if ($Password -is [SecureString])
            {

                $_Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

            }

            else
            {

                $_Password = $Password.Clone()

            }

            $Credential = [System.Management.Automation.PSCredential]::new($_Username, (ConvertTo-SecureString -String $_Password -AsPlainText -Force))

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($Type -eq 'HP') { $Type = 'HPE' }

            "[{0}] SAN Manager Type requested: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Type | Write-Verbose

            #Basic SAN Manager Object
            $_sanmanager = NewObject -SanManager

            $_sanmanagerhostconnectinfo = NewObject -SanManagerConnectInfo
            $_sanmanagerhostconnectinfo.name = "Host"
            $_sanmanagerhostconnectinfo.Value = $Hostname
            [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

            # Get SAN Manager Providers
            "[{0}] Getting available SAN Manager Providers" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_SanManagerProviders = Send-HPOVRequest -Uri $FcSanManagerProvidersUri -Hostname $_appliance.Name

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            switch ($type) 
            {
                
                { @('Brocade','BNA','Brocade Network Advisor') -contains $_ } 
                { 
                    
                    if ($Port -eq 0) 
                    { 
                        
                        $Port = 5989 
                    
                    }

                    $_SanManagerProviderUri = ($_SanManagerProviders.members | Where-Object name -eq 'Brocade San Plugin').deviceManagersUri

                    $_sanmanagerhostconnectinfo = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name = "Username"
                    $_sanmanagerhostconnectinfo.Value = $Credential.Username
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    $_sanmanagerhostconnectinfo = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name = "Password"
                    $_sanmanagerhostconnectinfo.Value = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name  = "UseSsl"
                    $_sanmanagerhostconnectinfo.Value = [Bool]$UseSsl
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)
                    
                    $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name  = "Port"
                    $_sanmanagerhostconnectinfo.Value = $Port
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                }

                { "BrocadeFOS", "FOS" -contains $_ }
                {

                    $_SanManagerProviderUri = ($_SanManagerProviders.members | Where-Object name -eq 'FabricOS San Plugin').deviceManagersUri

                    $_sanmanagerhostconnectinfo = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name = "Username"
                    $_sanmanagerhostconnectinfo.Value = $Credential.Username
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    $_sanmanagerhostconnectinfo = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name = "Password"
                    $_sanmanagerhostconnectinfo.Value = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name  = "UseHttps"
                    $_sanmanagerhostconnectinfo.Value = [Bool]$UseSsl
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                }

                { @("HPE","Cisco") -contains $_ } 
                { 

                    if ($Port -eq 0) 
                    { 
                        
                        $Port = 161 
                    
                    }

                    $_SanManagerProviderUri = ($_SanManagerProviders.members | Where-Object name -eq ($Type + ' San Plugin')).deviceManagersUri

                    $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name  = "SnmpPort"
                    $_sanmanagerhostconnectinfo.Value = [Int]$Port
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name  = "SnmpUserName"
                    $_sanmanagerhostconnectinfo.Value = $SnmpUserName
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                    $_sanmanagerhostconnectinfo.name  = "SnmpAuthLevel"
                    $_sanmanagerhostconnectinfo.Value = $SnmpAuthLevelEnum[$SnmpAuthLevel].ToUpper()
                    [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    if ($SnmpAuthLevel -ne "None")
                    {

                        $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                        $_sanmanagerhostconnectinfo.name  = "SnmpAuthProtocol"
                        $_sanmanagerhostconnectinfo.Value = $SnmpAuthProtocolEnum[$SnmpAuthProtocol]
                        [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                        $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                        $_sanmanagerhostconnectinfo.name  = "SnmpAuthString"
                        $_sanmanagerhostconnectinfo.Value = $SnmpAuthPassword
                        [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)
                        
                    }

                    if ($SnmpAuthLevel -eq "AuthAndPriv")
                    {

                        $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                        $_sanmanagerhostconnectinfo.name  = "SnmpPrivProtocol"
                        $_sanmanagerhostconnectinfo.Value = $SnmpPrivProtocolEnum[$SnmpPrivProtocol]
                        [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                        $_sanmanagerhostconnectinfo       = NewObject -SanManagerConnectInfo
                        $_sanmanagerhostconnectinfo.name  = "SnmpPrivString"
                        $_sanmanagerhostconnectinfo.Value = $SnmpPrivPassword
                        [void]$_sanmanager.connectionInfo.Add($_sanmanagerhostconnectinfo)

                    }

                }

            }

            "[{0}] SAN Manager Provider URI: $($_SanManagerProviderUri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            try 
            {
            
                $resp = Send-HPOVRequest $_SanManagerProviderUri POST $_sanmanager -Hostname $_appliance.Name

                "[{0}] Received async task, calling Wait-HPOVTaskComplete" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $resp = Wait-HPOVTaskComplete $resp

            }

            catch 
            {

                if ($_.FullyQualifiedErrorId -eq 'RESOURCE_CONFLICT_ERROR')
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException SanManagerAlreadyExists ResourceExists 'Hostname' -Message "The SAN Manager $($Hostname) already exists on appliance $($_appliance.Name)." -InnerException $_.Exception

                }

                else
                {

                    $ErrorRecord = $_

                }
                
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$TaskCollection.Add($resp)

        }

    }

    End
    {

        Return $TaskCollection

    }

}

function Set-HPOVSanManager 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'BNA')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "BNA")]
        [Alias ('name','Resource')]
        [ValidateNotNullOrEmpty()]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ParameterSetName = "BNA")]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ParameterSetName = "BNA")]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1,65535)]
        [Int]$Port = 0,
         
        [Parameter (Mandatory, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory, ParameterSetName = "BNA")]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Mandatory, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory, ParameterSetName = "BNA")]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [String]$SnmpUserName,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateSet ("None","AuthOnly","AuthAndPriv")]
        [ValidateNotNullOrEmpty()]
        [String]$SnmpAuthLevel = "None",

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateSet ("sha","md5")]    
        [ValidateNotNullOrEmpty()]
        [String]$SnmpAuthProtocol,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpAuthPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateSet ("aes-128","des56","3des")]    
        [ValidateNotNullOrEmpty()]
        [String]$SnmpPrivProtocol,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpPrivPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "BNA")]
        [Switch]$EnableSsl,

        [Parameter (Mandatory = $false, ParameterSetName = "BNA")]
        [Switch]$DisableSsl,

        [Parameter (Mandatory = $false, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ParameterSetName = "BNA")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "HPCisco")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "BNA")]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ResourceUpdateStatus = [System.Collections.ArrayList]::new()

    }

    Process
    {

        switch ($InputObject.GetType().Name)
        {

            'PSCustomObject'
            {

                "[$($MyInvocation.InvocationName.ToString().ToUpper())] Object received: {0}" -f ($InputObject | Out-String) | Write-Verbose

                # Generate error if wrong resource type
                if ($InputObject.category -ne 'fc-device-managers')
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException InvalidSanManagerResource InvalidArgument 'InputObject' -TargetType 'PSObject' -Message ("The provided Resource object is not a SAN Manager resource. Expected resource category 'fc-device-managers'. Received reource category {0}. Please check the value and try again." -f $InputObject.category)

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Generate error if wrong resource type
                if (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException InvalidSanManagerResource InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided Resource object is missing the required ApplianceConnection property. Please check the value and try again."

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            'String'
            {

                "[$($MyInvocation.InvocationName.ToString().ToUpper())] Getting SAN Manager by resource Name: {0}" -f $InputObject | Write-Verbose

                Try
                {

                    $InputObject = Get-HPOVSanManager $InputObject -ApplianceConnection $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                

            }

        }

        $_UpdatedSanManager = [PSCustomObject]@{
            connectionInfo = [System.Collections.ArrayList]::new()
        }

        switch ($PSBoundParameters.keys)
        {

            'Hostname'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "Host"; value = $Hostname})

            }

            'Port'
            {
            
                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "Port"; value = $Port})
                    
            }

            'Username'
            {
            
                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "Username"; value = $Username})
            
            }

            'Password'
            {

                if ($Password -is [SecureString])
                {

                    $Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

                }

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "Password"; value = $Password})

            }

            'SnmpUserName'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "SnmpUserName"; value = $SnmpUserName})

            }

            'SnmpAuthLevel'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "SnmpAuthLevel"; value = $SnmpAuthLevel})

            }
            
            'SnmpAuthProtocol'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "SnmpAuthProtocol"; value = $SnmpAuthProtocol})

            }
            
            'SnmpAuthPassword'
            {

                if ($SnmpAuthPassword -is [SecureString])
                {

                    $SnmpAuthPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SnmpAuthPassword))

                }

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "SnmpAuthPassword"; value = $SnmpAuthPassword})

            }
            
            'SnmpPrivProtocol'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "SnmpPrivProtocol"; value = $SnmpPrivProtocol})

            }
            
            'SnmpPrivPassword'
            {

                if ($SnmpPrivPassword -is [SecureString])
                {

                    $SnmpPrivPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SnmpPrivPassword))

                }

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "SnmpPrivPassword"; value = $SnmpPrivPassword})

            }
            
            'DisableSsl'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "UseSsl"; value = $false})

            }
            
            'EnableSsl'
            {

                [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "UseSsl"; value = $true})

            }

        }

        # Add missing ConnectionInfo properties to complete request
        if (-not $PSBoundParameters['Hostname'])
        {

            [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "Host"; value = ($InputObject.connectionInfo | Where-Object Name -eq Host).value})

        }

        if (-not $PSBoundParameters['Port'])
        {

            [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "Port"; value = ($InputObject.connectionInfo | Where-Object Name -eq Port).value})
            
        }

        if (-not $PSBoundParameters['EnableSsl'] -and -not $PSBoundParameters['DisableSsl'] -and $InputObject.providerDisplayName -eq 'Brocade Network Advisor')
        {

            [void]$_UpdatedSanManager.connectionInfo.Add(@{name = "UseSsl"; value = ($InputObject.connectionInfo | Where-Object Name -eq UseSsl).value})
            
        }

        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Updated SAN Manager: {0}" -f ($_UpdatedSanManager | out-string) | Write-Verbose 

        "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $resp = Send-HPOVRequest $InputObject.uri PUT $_UpdatedSanManager -ApplianceConnection $InputObject.ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $resp = $resp | Wait-HPOVTaskComplete 

        }
     
        [void]$_ResourceUpdateStatus.Add($resp)
           
    }
        
    End
    {
        return $_ResourceUpdateStatus

    }

}

function Update-HPOVSanManager 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Name','SANManager')]
        [Object]$InputObject,
        
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])) -and (-not($PipelineInput)))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif (($ApplianceConnection | Measure-Object).Count -gt 1 -and (-not($PipelineInput)))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif (-not($PipelineInput))
        {

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_.Exception)

            }

        }

        $_SanManagerRefreshCollection = [System.Collections.ArrayList]::new()
    
    }

    Process 
    {

        $request = [PsCustomObject]@{refreshState = "RefreshPending"}

        # Validate input object type
        # Checking if the input is System.String and is NOT a URI
        if ($InputObject -is [String]) 
        {
            
            "[{0}] SANManager Name: $($SANManager)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $SANManager = Get-HPOVSanManager $SANManager -Hostname $ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Checking if the input is PSCustomObject, and the category type is server-profiles, which could be passed via pipeline input
        elseif (($InputObject -is [System.Management.Automation.PSCustomObject]) -and ($InputObject.category -ieq "fc-device-managers")) 
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] SANManager is an object: {0}" -f $InputObject.name | Write-Verbose 
        
        }

        else 
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "The Parameter 'InputObject' value is invalid. Please validate the 'InputObject' Parameter value you passed and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.isInternal)
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] '{0}' SAN Manager is internal. Skipping." -f $InputObject.name | Write-Verbose 

        }

        else
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Refreshing SAN Manager resource: {0}" -f $InputObject.name | Write-Verbose 
        
            Try
            {

                $_resp = Send-HPOVRequest $InputObject.uri PUT $request -Hostname $ApplianceConnection.Name
        
            }
        
            Catch
            {
        
                $PSCmdlet.ThrowTerminatingError($_)
        
            }

            $_resp

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVSanManager 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Name','SanManager')]
        [object]$InputObject,
    
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSboundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection       = [System.Collections.ArrayList]::new()
        $_SanManagerCollection = [System.Collections.ArrayList]::new()
   
    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] San Manager Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            If ('fc-device-managers' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException InvalidArgumentValue InvalidArgument "SanManager:$($InputObject.Name)" -TargetType PSObject -Message "The SanManager object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_SanManagerCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException InvalidArgumentValue InvalidArgument "SanManager:$($InputObject.Name)" -TargetType PSObject -Message "The SanManager object resource is not an expected category type [$($InputObject.category)]. The allowed resource category type is 'fc-device-managers'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            # Need to handle Name versus URI
            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing SanManager Name $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_SanManager = Get-HPOVSanManager $InputObject -ApplianceConnection $_appliance

                    $_SanManager | ForEach-Object {

                        [void]$_SanManagerCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }        

        }

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_sm in $_SanManagerCollection) 
        {

            if ($PSCmdlet.ShouldProcess($_sm.name,"Remove SAN Manager from appliance '$($_sm.ApplianceConnection.Name)'"))
            {   
             
                
                Try
                {
                    
                    $_task = Send-HPOVRequest -Uri $_sm.uri -Method DELETE -AddHeader @{'If-Match' = $_sm.eTag } -Hostname $_sm.ApplianceConnection.Name

                    [void]$_TaskCollection.Add($_task)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function Get-HPOVManagedSan 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Fabric')]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $ManagedSansCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSBoundParameters['Label'])
            {

                $_uri = '{0}?category:fc-sans&query=labels:{1}' -f $IndexUri, $Label

                Try
                {

                    $_IndexMembers = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                    # Loop through all found members and get full SVT object
                    ForEach ($_member in $_IndexMembers.members)
                    {

                        Try
                        {

                            $_member = Send-HPOVRequest -Uri $_member.uri -Hostname $_appliance

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }                        

                        $_member.PSObject.TypeNames.Insert(0,"HPOneView.Storage.ManagedSan")

                        $_member

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            else
            {

                $uri = $fcManagedSansUri + '?sort=name:asc'

                if ($Name)
                {

                    $Name = $Name -replace ("[*]","%25") -replace ("[&]","%26")

                    $uri += "&query=lower(name) like '{0}'" -f $Name.ToLower()

                }
                
                "[{0}] Getting list of Managed SANs" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                Try
                {

                    $_managedSans = Send-HPOVRequest $uri -Hostname $_appliance.Name

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($_managedSans.count -eq 0 -and $Name) 
                {

                    "[{0}] Woops! Requested Managed SAN '$($_managedSans)' not found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                    $ErrorRecord = New-ErrorRecord InvalidOperationException ManagedSanResourceNotFound ObjectNotFound 'Name' -Message "Request Managed SAN '$($Name)' not found on appliance $($_appliance.Name). Please check the name and try again."
                        
                    # Generate Terminating Error
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                else
                {

                    $_managedSans.members | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.ManagedSan")
                    
                        [void]$ManagedSansCollection.Add($_)

                    }

                }

            }

        }

    }

    End 
    {

        return $ManagedSansCollection 
    
    }

}

function Set-HPOVManagedSan 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Enable")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Enable")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Disable")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "DisableAlias")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Fabric','Name','ManagedSan','Resource')]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [Parameter (Mandatory = $false, ParameterSetName = "DisableAlias")]
        [Alias ('ZoningEnable','Enable')]
        [Switch]$EnableAutomatedZoning,

        [Parameter (Mandatory = $false, ParameterSetName = "Disable")]
        [Alias ('ZoningDisable','Disable')]
        [Switch]$DisableAutomatedZoning,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [Parameter (Mandatory = $false, ParameterSetName = "Disable")]
        [Parameter (Mandatory = $false, ParameterSetName = "DisableAlias")]
        [ValidateSet ('NoZoning', 'SingleInitiatorAllTargets','SingleInitiatorSingleStorageSystem','SingleInitiatorSingleTarget')]
        [ValidateNotNullOrEmpty()]
        [String]$ZoningPolicy = 'SingleInitiatorAllTargets',
      
        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [Switch]$EnableAliasing,

        [Parameter (Mandatory = $false, ParameterSetName = "DisableAlias")]
        [Switch]$DisableAliasing,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [ValidateNotNullOrEmpty()]
        [String]$InitiatorNameFormat,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [ValidateNotNullOrEmpty()]
        [String]$TargetGroupNameFormat,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [ValidateNotNullOrEmpty()]
        [String]$TargetNameFormat,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [ValidateNotNullOrEmpty()]
        [String]$ZoneNameFormat,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [Bool]$UpdateZoneNames,

        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [Bool]$UpdateInitiatorAliases,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Enable")]
        [Bool]$UpdateTargetAliases,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Enable")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Disable")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "DisableAlias")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ResourceUpdateStatus = [System.Collections.ArrayList]::new()

        if ($PSBoundParameters.Keys -Contains 'EnableAutomatedZoning')
        {

            Write-Warning "the -EnableAutomatedZoning parameter is being deprecated. Please update your scripts to use the -ZoningPolicy parameter."

        }

        if ($PSBoundParameters.Keys -Contains 'DisableAutomatedZoning')
        {

            Write-Warning "the -DisableAutomatedZoning parameter is being deprecated. Please update your scripts to use the -ZoningPolicy parameter."

        }

    }

    Process 
    {

        switch ($InputObject.GetType().Name)
        {

            'PSCustomObject'
            {

                "[$($MyInvocation.InvocationName.ToString().ToUpper())] Object received: {0}" -f ($InputObject | Out-String) | Write-Verbose

                # Generate error if wrong resource type
                if ($InputObject.category -ne 'fc-sans')
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.ManagedSanResourceException InvalidManagedSanResource InvalidArgument 'InputObject' -TargetType 'PSObject' -Message ("The provided Resource object is not a Managed SAN resource. Expected resource category 'fc-sans'. Received reource category {0}. Please check the value and try again." -f $InputObject.category)

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Generate error if wrong resource type
                if (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException InvalidSanManagerResource InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided Resource object is missing the required ApplianceConnection property. Please check the value and try again."

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
                
                if ($InputObject.isInternal)
                {

                    $ExceptionMessage = "The provided Resource object '{0}' is an Internal SAN Manager and unsupported with this Cmdlet. Please check the value and try again." -f $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneView.SanManagerResourceException InvalidSanManagerResource InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage

                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

            'String'
            {

                "[$($MyInvocation.InvocationName.ToString().ToUpper())] Getting Managed SAN by resource Name: {0}" -f $InputObject | Write-Verbose

                Try
                {

                    $InputObject = Get-HPOVManagedSan $InputObject -ApplianceConnection $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        # Needed in order to support ErrorAction
        if (-not $ErrorRecord)
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Processing '{0}'" -f $InputObject.name | Write-Verbose 

            # Disable zoning
            if ($DisableAutomatedZoning.IsPresent -or $ZoningPolicy -eq 'NoZoning')
            { 
                    
                $InputObject.sanPolicy.zoningPolicy = "NoZoning"

                # Need to disable Aliasing Support as well with the request
                $InputObject.sanPolicy.enableAliasing = $false
                        
            }

            else
            {

                $InputObject.sanPolicy.zoningPolicy = $ZoningPolicy

                if ($EnableAliasing.IsPresent -or $ZoningPolicy -ne 'NoZoning') 
                { 

                    $InputObject.sanPolicy.enableAliasing = $True

                    switch ($PSBoundParameters.Keys)
                    {
                        
                        'InitiatorNameFormat'    { $InputObject.sanPolicy.initiatorNameFormat    = $InitiatorNameFormat }
                        'TargetGroupNameFormat'  { $InputObject.sanPolicy.targetGroupNameFormat  = $TargetGroupNameFormat }
                        'TargetNameFormat'       { $InputObject.sanPolicy.targetNameFormat       = $TargetNameFormat }
                        'ZoneNameFormat'         { $InputObject.sanPolicy.zoneNameFormat         = $ZoneNameFormat }
                        'UpdateZoneNames'        { $InputObject.sanPolicy.renameZones            = $UpdateZoneNames }
                        'UpdateInitiatorAliases' { $InputObject.sanPolicy.renameInitiatorAliases = $UpdateInitiatorAliases }
                        'UpdateTargetAliases'    { $InputObject.sanPolicy.renameTargetAliases    = $UpdateTargetAliases }

                    }                
                        
                }
                
                elseif ($DisableAliasing.IsPresent -or $ZoningPolicy -eq 'NoZoning') 
                { 
                    
                    $InputObject.sanPolicy.enableAliasing = $false 
                
                }

            }

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Updated Managed SAN Object: {0}" -f ($InputObject | out-string) | Write-Verbose 

            Try
            {

                $_Resp = Send-HPOVRequest $InputObject.uri PUT $InputObject -Hostname $InputObject.ApplianceConnection.Name

                $_Resp | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.ManagedSan') }

                [void]$_ResourceUpdateStatus.Add($_Resp)

            }

            Catch
            {

                $_ResourceUpdateStatus

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {
        
        Return $_ResourceUpdateStatus

    }

}

function Show-HPOVSanEndpoint
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $False, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$SAN,

        [Parameter (Mandatory, ParameterSetName = 'WWN')]
        [ValidateNotNullOrEmpty()]
        [String]$WWN,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'WWN')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SANEndpointCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $uri = $SanEndpoints

        if ($SAN)
        {

            switch ($SAN.GetType().Name)
            {


                'String'
                {

                    $uri += '?query=sanName eq "{0}"' -f $SAN

                }

                'PSCustomObject'
                {

                    $uri += '?query=sanName eq "{0}"' -f $SAN.name

                }

            }

            Try
            {

                $_resp = Send-HPOVRequest $uri -Hostname $ApplianceConnection

                $_resp.members | ForEach-Object {

                    $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.San.Endpoint')

                    [void]$_SANEndpointCol.Add($_)

                }

            }

            Catch
            {

              $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {

            if ($WWN)
            {

                $uri += '?query=wwn eq "{0}"' -f $WWN

            }

            if ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                ForEach ($_appliance in $ApplianceConnection)
                {


                    Try
                    {

                        $_resp = Send-HPOVRequest $uri -Hostname $_appliance

                        $_resp.members | ForEach-Object {

                            $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.San.Endpoint')

                            [void]$_SANEndpointCol.Add($_)

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

            }

            else
            {

                Try
                {

                    $_resp = Send-HPOVRequest $uri -Hostname $ApplianceConnection

                    $_resp.members | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,'HPOneView.Storage.San.Endpoint')

                        [void]$_SANEndpointCol.Add($_)

                    }

                }

                Catch
                {

                  $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
        }

    }

    End
    {

        Return $_SANEndpointCol

    }

}

function Get-HPOVSanZone
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]

    Param 
    (

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$ManagedSan,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_FCZoneCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ($PSBoundParameters['ManagedSan'])
        {

            Switch ($ManagedSan.GetType().Name)
            {

                'PSCustomObject'
                {

                    if ($ManagedSan.category -ne 'fc-sans')
                    {

                        $ExceptionMessage = "The ManagedSan resource '{0}' is not an allowed resource category." -f $ManagedSan.category
                        $ErrorRecord = New-ErrorRecord HPOneView.ManagedSanResourceException InvalidManagedSanObject InvalidArgument 'ManagedSan' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                    }

                    else
                    {

                        Try
                        {

                            $_resp = Send-HPOVRequest $ManagedSan.zonesUri -Hostname $ManagedSan.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        ForEach ($_MemberZone in $_resp.members)
                        {

                            $_ZoneObject = NewObject -FCZone

                            $_ZoneObject.PSObject.TypeNames.Insert(0,'HPOneView.Storage.ManagedSan.Zone')

                            $_ZoneObject.Name                = $_MemberZone.name
                            $_ZoneObject.State               = $_MemberZone.state
                            $_ZoneObject.Status              = $_MemberZone.status
                            $_ZoneObject.ManagedSan          = $_MemberZone.sanName
                            $_ZoneObject.Created             = $_MemberZone.created
                            $_ZoneObject.Modified            = $_MemberZone.modified
                            $_ZoneObject.ApplianceConnection = $ManagedSan.ApplianceConnection

                            Try
                            {

                                $_Aliases = Send-HPOVRequest $_MemberZone.AliasesUri -Hostname $ManagedSan.ApplianceConnection.Name

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            ForEach ($_AliasMember in $_Aliases.members)
                            {

                                $_Alias = NewObject -FCAlias

                                $_Alias.PSObject.TypeNames.Insert(0,'HPOneView.Storage.ManagedSan.Zone.Alias')

                                $_Alias.Name = $_AliasMember.name
                                $_Alias.WWN = $_AliasMember.members

                                [void]$_ZoneObject.Members.Add($_Alias)

                            }

                            [void]$_FCZoneCollection.Add($_ZoneObject)

                        }

                    }

                }
                
                default
                {

                    $ExceptionMessage = "The ManagedSan resource data type '{0}' is not an PSCustomObject." -f $ManagedSan.GetType().FullName
                    $ErrorRecord = New-ErrorRecord HPOneView.ManagedSanResourceException InvalidManagedSanValue InvalidArgument 'ManagedSan' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                }

            }            

        }

        else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                Try
                {

                    $_resp = Send-HPOVRequest $FcZonesUri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                ForEach ($_MemberZone in $_resp.members)
                {

                    $_ZoneObject = NewObject -FCZone

                    $_ZoneObject.PSObject.TypeNames.Insert(0,'HPOneView.Storage.ManagedSan.Zone')

                    $_ZoneObject.Name                = $_MemberZone.name
                    $_ZoneObject.State               = $_MemberZone.state
                    $_ZoneObject.Status              = $_MemberZone.status
                    $_ZoneObject.ManagedSan          = $_MemberZone.sanName
                    $_ZoneObject.Created             = $_MemberZone.created
                    $_ZoneObject.Modified            = $_MemberZone.modified
                    $_ZoneObject.ApplianceConnection = [PSCustomObject]@{Name = $_appliance.Name; ID = $_appliance.ID}

                    Try
                    {

                        $_Aliases = Send-HPOVRequest $_MemberZone.AliasesUri -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    ForEach ($_AliasMember in $_Aliases.members)
                    {

                        $_Alias = NewObject -FCAlias

                        $_Alias.PSObject.TypeNames.Insert(0,'HPOneView.Storage.ManagedSan.Zone.Alias')

                        $_Alias.Name = $_AliasMember.name
                        $_Alias.WWN = $_AliasMember.members

                        [void]$_ZoneObject.Members.Add($_Alias)

                    }

                    [void]$_FCZoneCollection.Add($_ZoneObject)

                }

            }

        }

    }

    End
    {

        Return $_FCZoneCollection

    }

}

function Get-HPOVDriveEnclosure
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]

    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_DriveEnclosureCollection = [System.Collections.ArrayList]::new()
            
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($_appliance.ApplianceType -ne 'Composer')
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. This Cmdlet is only supported with Synergy Composers.' -f $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                if ($PSBoundParameters['Label'])
                {

                    $_uri = '{0}?category:drive-enclosures&query=labels:{1}' -f $IndexUri, $Label

                    Try
                    {

                        $_IndexMembers = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                        # Loop through all found members and get full SVT object
                        ForEach ($_member in $_IndexMembers.members)
                        {

                            Try
                            {

                                $_member = Send-HPOVRequest -Uri $_member.uri -Hostname $_appliance

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }                        

                            $_member.PSObject.TypeNames.Insert(0,"HPOneView.Storage.DriveEnclosure")

                            $_member.driveBays | ForEach-Object { 
                                
                                $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.DriveEnclosure.DriveBay") 

                                if ($_.drive)
                                {

                                    $_.drive.PSObject.TypeNames.Insert(0,'HPOneView.Storage.DriveEnclosure.DriveBay.Drive')

                                }
                                
                            }

                            $_member.ioAdapters | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.DriveEnclosure.IoAdapter") }

                            $_member

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                else
                {

                    $uri = $DriveEnclosureUri

                    if ($PSBoundParameters['Name'])
                    {

                        $_operator = '='

                        if ($Name -match '\*' -or $Name -match '\?')
                        {

                            $_operator = 'matches'

                        }

                        $uri += "?filter=name {0} '{1}'&sort:asc" -f $_operator, $name.Replace('*','%25')

                    }

                    Write-Verbose ("[$($MyInvocation.InvocationName.ToString().ToUpper())] Processing {0} Connection" -f $_appliance.Name)

                    "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_DriveEnclosures = Send-HPOVRequest -uri $uri -Hostname $_appliance.Name

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    if ($_DriveEnclosures.count -eq 0 -and (-not ($Name))) 
                    {  
                        
                        "[{0}] No unmanaged devices found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                    
                    }

                    elseif ($_DriveEnclosures.count -eq 0 -and $PSBoundParameters['Name']) 
                    { 

                        "[{0}] No drive enclosure reousrces with name found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ExceptionMessage = "The '{0}' Drive Enclosure resource was not found on '{1}' Appliance. Please check the name and try again." -f $Name, $_appliance.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.UnmanagedDeviceResourceException UnmangedDeviceResouceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                        $PSCmdlet.WriteError($ErrorRecord)
                            
                    }
                    
                    else
                    {

                        $_DriveEnclosures.members | ForEach-Object {

                            $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.DriveEnclosure")

                            $_.driveBays | ForEach-Object { 
                                
                                $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.DriveEnclosure.DriveBay") 

                                if ($_.drive)
                                {

                                    $_.drive.PSObject.TypeNames.Insert(0,'HPOneView.Storage.DriveEnclosure.DriveBay.Drive')

                                }
                                
                            }

                            $_.ioAdapters | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Storage.DriveEnclosure.IoAdapter") }

                            $_

                        }

                    }

                }

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVAvailableDriveType
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]

    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true
            
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not $ApplianceConnection)
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
            
    }

    Process 
    {

        if (($ConnectedSessions | Where-Object Name -eq $InputObject.ApplianceConnection.Name).ApplianceType -ne 'Composer')
        {

            $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. This Cmdlet is only supported with Synergy Composers.' -f $ApplianceConnection.Name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            switch ($InputObject.category)
            {

                'sas-logical-interconnects'
                {

                    $_SasLogicalInterconnect = $InputObject.PSObject.Copy()
                    $InputObject = [System.Collections.ArrayList]::new()

                    "[{0}] SAS Logical Interconnect provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_SasLogicalInterconnect.name | Write-Verbose
                    "[{0}] Getting all associated drive enclosures: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_SasLogicalInterconnect.driveEnclosureUris.count | Write-Verbose                

                    ForEach ($_DriveEnclosureUri in $_SasLogicalInterconnect.driveEnclosureUris)
                    {

                        Try
                        {

                            $_DriveEnclosure = Send-HPOVRequest -uri $_DriveEnclosureUri -Hostname $ApplianceConnection

                            $_DriveEnclosure | Add-Member -NotePropertyName sasLogicalInterconnectName -NotePropertyValue $_SasLogicalInterconnect.name

                            [void]$InputObject.Add($_DriveEnclosure)

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

                'drive-enclosures'
                {

                    "[{0}] Drive Enclosure provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                    $_uri = "{0}?category=sas-logical-interconnects&start=0&count=-1&name=DRIVE_ENCLOSURE_TO_SAS_LOGICAL_INTERCONNECT&parentUri={1}" -f $IndexAssociatedResourcesUri, $InputObject.uri

                    Try
                    {

                        $_associatedogicalInterconnect = Send-HPOVRequest -uri $_uri -Hostname $ApplianceConnection

                        $InputObject | Add-Member -NotePropertyName sasLogicalInterconnectName -NotePropertyValue $_associatedogicalInterconnect.members[0].childResource.name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                default
                {

                    # Generate error due to invalid object
                    if ($Inputobject -is [PSCustomObject])
                    {

                        $_InputObjectName = $InputObject.name

                    }

                    else
                    {

                        $_InputObjectName = $InputObject

                    }

                    $ExceptionMessage = "The specified '{0}' InputObject parameter value is not supported type. Only SAS Logical Interconnect or Disk Drive resources are allowed." -f $_InputObjectName
                    $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            ForEach ($_DriveEnclosure in $InputObject)
            {

                "[{0}] Processing drive enclosure: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DriveEnclosure.name | Write-Verbose

                $_uri = "{0}?category=drives&start=0&count=-1&userQuery='{1} AND available=yes'" -f $IndexUri, $_DriveEnclosure.uri

                Try
                {

                    $_AvailableDrives = Send-HPOVRequest -uri $_uri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_TempDriveCollection = [System.Collections.ArrayList]::new()

                ForEach ($_MemberDrive in $_AvailableDrives.members)
                {

                    $_AvailableDrive = $null

                    '[{0}] Collecting: {1} Type {2} Capacity' -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_MemberDrive.attributes.interfaceType + $_MemberDrive.attributes.mediaType), $_MemberDrive.attributes.capacityInGb | Write-Verbose

                    # Filter for the number of drives based on combined interfaceType and interfaceMedia
                    [Array]$NumberOfDrives = $_AvailableDrives.members | Where-Object { $_.attributes.interfaceType -eq $_MemberDrive.attributes.interfaceType -and $_.attributes.mediaType -eq $_MemberDrive.attributes.mediaType -and $_.attributes.capacityInGb -eq $_MemberDrive.attributes.capacityInGb }
                    
                    # Create temporary drive object to store values for compare and new object
                    $_DriveAttributes = [PSCustomObject]@{Type = ($_MemberDrive.attributes.interfaceType + $_MemberDrive.attributes.mediaType); Count = $NumberOfDrives.Count; Capacity = [Convert]::ToInt32($_MemberDrive.attributes.capacityInGb)}
                    
                    if ((-not ($_TempDriveCollection.Type | Where-Object { $_ -contains $_DriveAttributes.Type})) -or (($_TempDriveCollection.Type | Where-Object { $_ -contains $_DriveAttributes.Type}) -and -not ($_TempDriveCollection | Where-Object { $_.Capacity -contains $_DriveAttributes.Capacity})))
                    {

                        '[{0}] Adding drive type {1} and capacity {2} to collection' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DriveAttributes.Type, $_DriveAttributes.Capacity | Write-Verbose

                        $_AvailableDrive = New-Object HPOneView.Storage.AvailableDriveType($_DriveAttributes.Type, 
                                                                                           $_DriveAttributes.Capacity,
                                                                                           $_DriveAttributes.Count,
                                                                                           $_DriveEnclosure.name, 
                                                                                           $_DriveEnclosure.sasLogicalInterconnectName,                                                                                             
                                                                                           $ApplianceConnection)

                        [Void]$_TempDriveCollection.Add($_AvailableDrive)

                    }

                }

                $_TempDriveCollection | Sort-Object Type, Capacity

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Unmanaged Devices:
#

function Get-HPOVUnmanagedDevice 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]

    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ('report')]
        [Switch]$List,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        if ($PSBoundParameters['List'])
        {

            Write-Warning "The List Parameter has been deprecated. The CMDLET will now display object data in Format-List view."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_UnmanagedDevicesCollection = [System.Collections.ArrayList]::new()

        $uri = $UnmanagedDevicesUri

        if ($PSBoundParameters['Name'])
        {

            if ($Name.Contains('*'))
            {

                $uri += "&filter=name matches '{0}'" -f $Name.Replace('*','%25')

            }

            else
            {

                $uri += "&filter=name EQ '{0}'" -f $Name

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($PSBoundParameters['Label'])
            {

                $_uri = '{0}?category:unmanaged-devices&query=labels:{1}' -f $IndexUri, $Label

                Try
                {

                    $_IndexMembers = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                    # Loop through all found members and get full SVT object
                    ForEach ($_member in $_IndexMembers.members)
                    {

                        Try
                        {

                            $_member = Send-HPOVRequest -Uri $_member.uri -Hostname $_appliance

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }                        

                        $_member.PSObject.TypeNames.Insert(0,'HPOneView.UnmanagedResource')

                        $_member

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            else
            {

                "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_UnmanagedDevices = Send-HPOVRequest $uri -Hostname $_appliance.Name

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($_UnmanagedDevices.count -eq 0 -and (-not($Name))) 
                {  
                    
                    "[{0}] No unmanaged devices found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                
                }

                elseif ($_UnmanagedDevices.count -eq 0 -and $Name)
                {


                    "[{0}] No unmanaged devices with name found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ExceptionMessage = "The '{0}' Unmanaged Device resource was not found on '{1}' Appliance. Please check the name and try again." -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneview.UnmanagedDeviceResourceException UnmangedDeviceResouceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                else
                {

                    $_UnmanagedDevices.members | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,"HPOneView.UnmanagedResource")

                        $_

                    }

                }

            }
            
        }            

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVUnmanagedDevice 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]

    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Model,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$Height = 1,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$MaxPower,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$MacAddress,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateScript({if (-not([Net.IPAddress]::TryParse($_,[ref]$null))) { Throw 'The provided IPv4Address value does not appear to be a valid IPv4 Address.' } else { $True }})]
        [String]$IPv4Address,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateScript({if (-not([Net.IPAddress]::TryParse($_,[ref]$null))) { Throw 'The provided IPv6Address value does not appear to be a valid IPv6 Address.' } else { $True }})]
        [String]$IPv6Address,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_UnmanagedDeviceCreateResults = [System.Collections.ArrayList]::new()
    }

    Process 
    {
        
        $_NewDevice = NewObject -UnmanagedDevice

        [String]$_NewDevice.name        = $Name
        [String]$_NewDevice.model       = $Model
        [Int]$_NewDevice.height         = $Height
        [String]$_NewDevice.mac         = $MacAddress
        [String]$_NewDevice.IPv4Address = $IPv4Address
        [String]$_NewDevice.IPv6Address = $IPv6Address
        [Int]$_NewDevice.maxPwrConsumed = $MaxPower

        # "[{0}] New Unmanaged Device: $($newDevice)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $_resp = Send-HPOVRequest -Uri $unmanagedDevicesUri -Method POST -Body $_NewDevice -Hostname $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $_resp | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.UnmanagedResource") }

        [void]$_UnmanagedDeviceCreateResults.Add($_resp)

    }

    End
    {

        Return $_UnmanagedDeviceCreateResults

    }

}

function Remove-HPOVUnmanagedDevice 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]

    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name")]
        [object]$UnmanagedDevice,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$force,
    
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['UnmanagedDevice'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection            = [System.Collections.ArrayList]::new()
        $_UnmanagedDeviceCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] User Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            If ('unmanaged-devices' -contains $UnmanagedDevice.category)
            {

                If (-not($UnmanagedDevice.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.UnmanagedDeviceResourceException InvalidArgumentValue InvalidArgument "UnmanagedDevice:$($UnmanagedDevice.Name)" -TargetType PSObject -Message "The UnmanagedDevice object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_UnmanagedDeviceCollection.Add($UnmanagedDevice)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "UnmanagedDevice:$($UnmanagedDevice.Name)" -TargetType PSObject -Message "The UnmanagedDevice object resource is not an expected category type [$($UnmanagedDevice.category)]. The allowed resource category type is 'unmanaged-devices'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing Unmanaged Device Name $($UnmanagedDevice)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_UnmanagedDevice = Get-HPOVUnmanagedDevice $UnmanagedDevice -ApplianceConnection $_appliance

                    $_UnmanagedDevice | ForEach-Object {

                        [void]$_UnmanagedDeviceCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Processing $($_UnmanagedDeviceCollection.count) object resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Unmanaged Device Resources
        ForEach ($_device in $_UnmanagedDeviceCollection)
        {

            if ($PSCmdlet.ShouldProcess($_device.ApplianceConnection.Name,"Remove Unmanaged Device '$($_device.name)' from appliance")) 
            {

                "[{0}] Removing Unmanaged Device '$($_device.name)' from appliance '$($_device.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_device.Uri -Method DELETE -AddHeader @{'If-Match' = $_device.eTag } -Hostname $_device.ApplianceConnection

                    $_resp | Add-Member -NotePropertyName Name -NotePropertyValue $_device.name

                    $_resp

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Power Delivery Devices
#

function Get-HPOVPowerDevice 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateSet ('HPIpduCore', 'HPIpduAcModule', 'LoadSegment', 'HPIpduOutletBar', 'HPIpduOutlet')]
        [Array]$Type,
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_Query = [System.Collections.ArrayList]::new()

            # Commented out until corect Index API call can be found
            # if ($Type)
            # {

            # ForEach ($_type in $Type)
            # {

            # $_queryvalue = "pdd_type:'{0}'" -f $_type
            # # $_queryvalue = "deviceType:'{0}'" -f $_type
            # [void]$_Query.Add($_queryvalue)

            # }

            # }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            $_Category = 'category=power-devices'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ResourcesFromIndexCol.Count -eq 0)
            {
                
                if ($Name) 
                { 
                    
                    "[{0}] '{1}' Power Device not found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    $ExceptionMessage = "No power device with '{0}' name found on '{1}' appliance connection. Please check the name or use New-HPOVStorageVolume to create the volume." -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException StorageVolumeResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage 
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                else 
                {

                    "[{0}] No Power Device found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }
                        
            }
                
            else 
            {

                if ($Type)
                {

                    "[{0}] Filtering for {1} device type." -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', $Type) | Write-Verbose

                    $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object { $Type -contains $_.deviceType }

                }

                ForEach ($_member in ($_ResourcesFromIndexCol | Sort-Object name, deviceType))
                { 

                    switch ($_member.deviceType)
                    {
    
                        'HPIpduCore'
                        {

                            $_member.psobject.typenames.Insert(0,"HPOneView.PowerDeliveryDevice")
    
                        }

                        'HPIpduAcModule'
                        {

                            $_member.psobject.typenames.Insert(0,"HPOneView.PowerDeliveryDevice.PduAcModule")

                        }

                        'LoadSegment'
                        {

                            $_member.psobject.typenames.Insert(0,"HPOneView.PowerDeliveryDevice.LoadSegment")

                        }

                        'HPIpduOutletBar'
                        {

                            $_member.psobject.typenames.Insert(0,"HPOneView.PowerDeliveryDevice.OutletBar")

                        }
    
                        'HPIpduOutlet'
                        {

                            # Get power state
                            Try
                            {

                                $_PowerState = Send-HPOVRequest -Uri ($_member.uri + '/powerState') -ApplianceConnection $_member.ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            $_member | Add-Member -NotePropertyName power -NotePropertyValue $_PowerState -Force

                            $_member.psobject.typenames.Insert(0,"HPOneView.PowerDeliveryDevice.Outlet")

                        }
        
                    }

                    $_member
                    
                }     
                
            }         

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
    }

}

function Add-HPOVPowerDevice 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = "High")]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,
         
        [Parameter (Mandatory = $false)]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Mandatory = $false)]
        [Obsolete()]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false)]
        [Switch]$TrustLeafCertificate,

        [Parameter (Mandatory = $false)]
        [Switch]$Force,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            if  ($ApplianceConnection.Count -gt 1)
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)
            
        }

        elseif ($Password -is [SecureString])
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSBoundParameters['Password'])
        {

            $_DecryptPassword = $Password

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        else
        {

            $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters.'
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $colStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        # Locate the Enclosure Group specified
        "[{0}] - Starting" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if ($PSBoundParameters['TrustLeafCertificate'])
        {

            "[{0}] Caller provide the -TrustLeafCertificate switch. Adding SSL certificate to appliance trust store." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting SSL certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # This is not an async task operation
            Try
            {

                $_uri = '{0}/{1}' -f $RetrieveHttpsCertRemoteUri, $Hostname

                $_DeviceCertificate = Send-HPOVRequest -Uri $_uri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_DeviceCertificateToImport = NewObject -CertificateToImport
            $_DeviceCertificateToImport.certificateDetails[0].base64Data = $_DeviceCertificate.certificateDetails.base64Data
            $_DeviceCertificateToImport.certificateDetails[0].aliasName  = $_DeviceCertificate.certificateDetails.commonName

            Try
            {
                
                "[{0}] Adding SSL certificate to appliance trust store." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_uri = '{0}' -f $ApplianceTrustedSslHostStoreUri

                $_TaskResults = Send-HPOVRequest -Uri $_uri -Method POST -Body $_DeviceCertificateToImport -Hostname $ApplianceConnection | Wait-HPOVTaskComplete

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_TaskResults.taskErrors)
            {

                "[{0}] Task errors adding SSL certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($_TaskResults.taskErrors.errorCode -eq '409' -and $_TaskResults.taskErrors.message -match 'The certificate already exists for the alias')
                {

                    "[{0}] Certificate already exists." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else
                {

                    
                    $ErrorRecord = New-ErrorRecord InvalidOperationException $_TaskResults.taskErrors.errorCode InvalidResult 'Hostname' -Message $_TaskResults.taskErrors.message
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        $_import = NewObject -PowerDeliveryDeviceAdd
        
        $_import.hostname = $Hostname
        $_import.username = $Username
        $_import.password = $_DecryptPassword
        $_import.force    = $Force.IsPresent

        "[{0}] - Sending request to add iPDU." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $_resp = Send-HPOVRequest -Uri $PowerDevicesDiscoveryUri -Method POST -Body $_import -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        # Wait for task to get into Starting stage
        Try
        {

            $_resp = Wait-HPOVTaskStart $_resp

        }

        Catch
        {

             $PSCmdlet.ThrowTerminatingError($_)

         }
            
        "[{0}] Task response: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_resp.taskState, $_resp.erroCode | Write-Verbose

        # Check to see if the task errored, which should be in the Task Validation stage
        if ($_resp.taskState -ne "Running" -and $_resp.taskState -eq "Error" -and $_resp.stateReason -eq "ValidationError") 
        {

            "[{0}] Task error found {1} {2} " -f $MyInvocation.InvocationName.ToString().ToUpper(), $resp.taskState, $resp.stateReason | Write-Verbose

            if ($_resp.taskErrors | Where-Object { 'UNABLE_TO_VERIFY_CERTIFICATE', "CERTIFICATE_UNTRUSTED"-contains $_.errorCode })
            {

                $ExceptionMessage = 'The leaf certificate for {0} is untrusted by the appliance. Either provide the -TrustLeafCertificate parameter or manually add the certificate using the Add-HPOVApplianceTrustedCertificate Cmdlet.' -f $Hostname
                $ErrorRecord = New-ErrorRecord InvalidOperationException UntrustedLeafCertificate InvalidResult 'Hostname' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            }

            if ($_resp.taskerrors | Where-Object { $_.errorCode -eq "PDD_IPDU_TRAPRECEIVERACCOUNT_TAKEN" }) 
            {
                        
                $_errorMessage = $_resp.taskerrors | Where-Object { $_.errorCode -eq "PDD_IPDU_TRAPRECEIVERACCOUNT_TAKEN" }

                $_externalManagerIP = $_errorMessage.data.mgmtSystemIP

                Try
                {

                    $_externalManagerFQDN = [System.Net.DNS]::GetHostByAddress($_externalManagerIP)

                }

                Catch
                {

                    "[{0}] Couldn't resolve {1} to FQDN [{2}]." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_externalManagerIP, $_.Exception.Message | Write-Verbose

                    $_externalManagerFQDN = [PSCustomObject]@{HostName = $_externalManagerIP}

                }                

                "[{0}] Found iPDU '{1} is already being managed by {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname, $_externalManagerIP | Write-Verbose

                "[{0}] {1} resolves to {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_externalManagerIP, $_externalManagerFQDN.HostName | Write-Verbose

                "[{0}] iPDU '{1}' is already claimed by another management system {2} ({3})." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname, $_externalManagerIP, $_externalManagerFQDN.HostName | Write-Verbose

                if ($Force -and $PSCmdlet.ShouldProcess($Hostname,"iPDU is already claimed by another management system $_externalManagerIP ($($_externalManagerFQDN.HostName)). Force add?")) 
                {
                            
                    "[{0}] - iPDU is being claimed due to user chosing YES to force add." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $import.force = $true

                    Try
                    {
                        
                        $_resp = Send-HPOVRequest -Uri $PowerDevicesDiscoveryUri -Method POST -Body $_import -Hostnamme $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSCmdlet.ShouldProcess($Hostname,"iPDU is already claimed by another management system $_externalManagerIP ($($_externalManagerFQDN.HostName)). Force add?")) 
                {
                            
                    "[{0}] - iPDU is being claimed due to user chosing YES to force add." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $import.force = $true

                    Try
                    {
                        
                        $_resp = Send-HPOVRequest -Uri $PowerDevicesDiscoveryUri -Method POST -Body $_import -Hostnamme $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                else 
                {

                    if ($PSBoundParameters['whatif'].ispresent) 
                    { 
                            
                        "[{0}] -WhatIf was passed, would have force added '$Hostname' iPDU to appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_resp = $null
                            
                    }

                    else 
                    {

                        # If here, user chose "No", End Processing

                        "[{0}] Not importing iPDU {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname | Write-Verbose

                        $_resp = $Null

                    }

                }

            }

            elseif ($_resp.taskErrors)
            {

                $_errorMessage = $_resp.taskErrors

                if ($_errorMessage -is [System.Collections.IEnumerable]) 
                { 
                        
                    # Loop to find a Message value that is not blank.
                    $displayMessage = $_errorMessage.message | Where-Object { $null -ne $_ }

                    $ErrorRecord = New-ErrorRecord InvalidOperationException 'InvalidResultAddingPDU' InvalidResult 'Hostname' -Message $displayMessage
                
                }
                        
                else 
                { 
                    
                    $ErrorRecord = New-ErrorRecord InvalidOperationException $errorMessage.errorCode InvalidResult 'Hostname' -Message ($_errorMessage.details + " " + $_errorMessage.message) 
                
                }

                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_resp

        }
            
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# // TODO: DEVELOP DOCUMENTATION TEST
function New-HPOVPowerDevice
{

    Throw "Not implemented."

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Start-HPOVPowerDevice
{

    Throw "Not implemented."

    # Only allow HPIpduOutlet deviceType

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Stop-HPOVPowerDevice
{

    Throw "Not implemented."

    # Only allow HPIpduOutlet deviceType

}

function Remove-HPOVPowerDevice 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri", "name", 'PowerDevice')]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async,
    
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PowerDeviceCollection = [System.Collections.ArrayList]::new()
   
    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] PowerDevice Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            If ('power-devices' -contains $InputObject.category)
            {

                If (-not $InputObject.ApplianceConnection)
                {

                    $ExceptionMessage = "The PowerDevice object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.PowerDeviceResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_PowerDeviceCollection.Add($InputObject)

            }

            else
            {

                $ExceptionMessage = "The PowerDevice object resource is not an expected category type [{0}]. The allowed resource category type is 'power-devices'. Please check the object provided and try again." -f $InputObject.category
                $ErrorRecord = New-ErrorRecord HPOneView.PowerDeviceResourceException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Processing Power Device Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

                Try
                {

                    $_PowerDevice = Get-HPOVPowerDevice -Name $PowerDevice -ErrorAction Stop -ApplianceConnection $_appliance

                    $_PowerDevice | ForEach-Object {

                        [void]$_PowerDeviceCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }
        
    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_PowerDevice in $_PowerDeviceCollection) 
        {

            if ($PSCmdlet.ShouldProcess($_PowerDevice.name,"Remove Power Device from appliance '$($_PowerDevice.ApplianceConnection.Name)'"))
            {   
                             
                Try
                {
                    
                    $_task = Send-HPOVRequest -Uri $_PowerDevice.uri -Method DELETE -AddHeader @{'If-Match' = $_PowerDevice.eTag } -Hostname $_PowerDevice.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($PSBoundParameters['Async'])
                {

                    $_task

                }

                else
                {

                    $_task | Wait-HPOVTaskComplete

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

}

function Get-HPOVPowerPotentialDeviceConnection 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name")]
        [object]$PowerDevice,
    
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['PowerDevice'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PowerDeviceCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] PowerDevice Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            If ('power-devices' -contains $PowerDevice.category)
            {

                If (-not($PowerDevice.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.PowerDeviceResourceException InvalidArgumentValue InvalidArgument "PowerDevice:$($PowerDevice.Name)" -TargetType PSObject -Message "The PowerDevice object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Try
                {

                    $_resp = Send-HPOVRequest ($powerDevicePotentialConnections + $PowerDevice.uri)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

                if ($_resp)
                {

                    $_resp | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,'HPOneView.PowerDevice.PotentialPowerConnection')
                    
                        [void]$_PowerDeviceCollection.Add($_)

                    }

                }

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.PowerDeviceResourceException InvalidArgumentValue InvalidArgument "PowerDevice:$($PowerDevice.Name)" -TargetType PSObject -Message "The PowerDevice object resource is not an expected category type [$($PowerDevice.category)]. The allowed resource category type is 'power-devices'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing Power Device Name $($PowerDevice)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_PowerDevice = Get-HPOVPowerDevice $PowerDevice -ApplianceConnection $_appliance

                    $_resp = $_PowerDevice | ForEach-Object { Send-HPOVRequest ($powerDevicePotentialConnections + $_.uri) }

                    $_resp | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,'HPOneView.PowerDevice.PotentialPowerConnection')

                        [void]$_PowerDeviceCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End 
    {

        Return $_PowerDeviceCollection

    }

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Add-HPOVPowerDeviceConnection
{

    Throw "Not implemented."

}

#######################################################
# Networking and Connections
#

function New-HPOVNetwork 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Ethernet")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "FC")]
        [Parameter (Mandatory, ParameterSetName = "FCOE")]
        [Parameter (Mandatory, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory, ParameterSetName = "Ethernet")]
        [String]$Name, 

        [Parameter (Mandatory, ParameterSetName = "FC")]
        [Parameter (Mandatory, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [ValidateSet ("Ethernet", "FC", "FibreChannel", "Fibre Channel", "FCoE")]
        [String]$Type = "Ethernet",
        
        [Parameter (Mandatory, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")] 
        [validaterange(1,4095)]
        [int32]$VlanId,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")] 
        [Object[]]$NetworkSet,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")] 
        [Object]$Subnet,

        [Parameter (Mandatory, ParameterSetName = "VLANIDRange")]
        [String]$VlanRange,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")] 
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [ValidateSet ('Untagged','Tagged','Tunnel', IgnoreCase = $False)]
        [String]$VLANType = "Tagged", 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [ValidateSet ("General", "Management", "VMMigration", "FaultTolerance", 'ISCSI', IgnoreCase = $False)]
        [String]$Purpose = "General", 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [boolean]$SmartLink = $true, 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [boolean]$PrivateNetwork = $false, 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory = $false, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [validaterange(2,20000)]
        [int32]$TypicalBandwidth = 2500, 
        
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory = $false, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [validaterange(100,20000)]
        [int32]$MaximumBandwidth = 20000, 

        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [int32]$LinkStabilityTime = 30, 

        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [boolean]$AutoLoginRedistribution = $False,

        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [ValidateSet ("FabricAttach","FA", "DirectAttach","DA")]
        [String]$FabricType = "FabricAttach",

        [Parameter (Mandatory = $false, ParameterSetName = "FC", ValueFromPipeline)]
        [Parameter (Mandatory = $false, ParameterSetName = "FCOE", ValueFromPipeline)] 
        [ValidateNotNullOrEmpty()]
        [object]$ManagedSan,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory = $false, ParameterSetName = "importFile")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory = $false, ParameterSetName = "importFile")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FCOE")]
        [Parameter (Mandatory = $false, ParameterSetName = "VLANIDRange")]
        [Parameter (Mandatory = $false, ParameterSetName = "importFile")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory, ParameterSetName = "importFile")]
        [Alias ("i", "import")]
        [String]$ImportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

        # Validate Ethernet VLAN ID Setting if Type = 'Tagged'
        if ($PSBoundParameters['VLANType'] -eq 'Tunnel')
        {
            
            if ($PSBoundParameters['Subnet'])
            {

                # Generate Error
                $ExceptionMessage = "The -VLANType parameter 'Tunnel' cannot be assigned to a subnet. Remove the -Subnet parameter and try again."
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'VLANType' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($PSBoundParameters['NetworkSet'])
            {

                # Generate Error
                $ExceptionMessage = "The -VLANType parameter 'Tunnel' cannot be assigned to a NetworkSet. Remove the -NetworkSet parameter and try again."
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'VLANType' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        elseif ($PSBoundParameters['VLANType'] -eq 'Untagged' -and $PSBoundParameters['NetworkSet'])
        {

            # Generate Error
            $ExceptionMessage = "The -VLANType parameter 'Untagged' cannot be assigned to a NetworkSet. Remove the -NetworkSet parameter and try again."
            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'VLANType' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }
     
    Process 
    {

        # Validate Ethernet VLAN ID Setting if Type = 'Tagged'
        if ($PSBoundParameters['VLANType'] -eq 'Tagged' -and (-not($PSBoundParameters['VLANID'])))
        {

            # Generate Error
            $ExceptionMessage = "The -VLANType Parameter was used to specify a 'Tagged' Network, however the -VLANID Parameter was not provided. Please provide a VLANID to the Network resource you are creating."
            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'VLANType' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Validate Ethernet VLAN ID Setting if Network Type is FCoE
        if ($PSBoundParameters['Type'] -eq 'FCoE' -and (-not($PSBoundParameters['VlanId'])))
        {

            # Generate Error
            $ExceptionMessage = "The -Type Parameter was used to specify a 'FCoE' Network, however the -VLANID Parameter was not provided. Please provide a VLANID to the Network resource you are creating."
            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'Type' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Resolved Parameter Set Name: $($PSCmdlet.ParameterSetName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Processing CMDLET for '$($_appliance.name)' appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            If ($ImportFile) 
            {

                try 
                {

                    $network = [String]::Join("", (Get-Content $importfile -ErrorAction Stop)) | convertfrom-json -ErrorAction Stop

                }

                catch [System.Management.Automation.ItemNotFoundException] 
                {

                    $ErrorRecord = New-ErrorRecord System.Management.Automation.ItemNotFoundException InputFileNotFound ObjectNotFound 'New-HPOVNetwork' -Message "$importFile not found. Please check the filename or path is valid and try again."
                        
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                catch [System.ArgumentException] 
                {

                    $ErrorRecord = New-ErrorRecord System.ArgumentException InvalidJSON ParseError 'New-HPOVNetwork' -Message "JSON incorrect or invalid within '$importFile' input file."
                        
                    # Generate Terminating Error
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }
            
            else
            {
            
                "[{0}] Network Type Requested: $($Type)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                switch ($Type) 
                {

                    "Ethernet" 
                    {

                        if (-not($PSBoundParameters['VlanRange'])) 
                        {

                            "[{0}] Creating '$name' Ethernet Network" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $Network = NewObject -EthernetNetwork

                            $Network.vlanId              = $VlanId
                            $Network.ethernetNetworkType = $VLANType
                            $Network.purpose             = $EthernetNetworkPurposeEnum[$Purpose]
                            $Network.name                = $Name
                            $Network.smartLink           = $SmartLink
                            $Network.privateNetwork      = $PrivateNetwork

                            if ($PSBoundParameters['Subnet'])
                            {

                                ForEach ($_subnet in $Subnet)
                                {

                                    "[{0}] Subnet {1} was provided, validating." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_subnet.networkId | Write-Verbose

                                    # Genrate Error
                                    if (-not($_subnet -is [PSCustomObject]))
                                    {

                                        $Message = 'The Subnet Parameter value is not an Object. Please provide a valid Object by using the Get-HPOVAddressPoolSubnet Cmdlet.'
                                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidSubnetValue InvalidArgument 'Subnet' -TargetType $_subnet.Gettype().Name -Message $Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    # Genrate Error, invalid object type
                                    if ($ResourceCategoryEnum.IPv4Subnet, $ResourceCategoryEnum.IPv6Subnet -notcontains $_subnet.category)
                                    {

                                        $Message = "The Subnet Parameter value is not a valid IP Subnet object. The object category provided was {0}. Please provide a valid Object by using the Get-HPOVAddressPoolSubnet Cmdlet." -f $Subnet.category
                                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidSubnetObject InvalidArgument 'Subnet' -TargetType 'PSObject' -Message $Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    # Invalid object for the appliance connection
                                    if ($_subnet.ApplianceConnection.Name -ne $_appliance.Name)
                                    {

                                        $Message = "The Subnet Parameter value is missing the 'ApplianceConnection' property. Please provide a valid Object by using the Get-HPOVAddressPoolSubnet Cmdlet."
                                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'Subnet' -TargetType 'PSObject' -Message $Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    switch ($_subnet.category)
                                    {

                                        $ResourceCategoryEnum.IPv4Subnet
                                        {

                                            # Generate error that there are more than 1 IPv4 subnets provided, and only a singular subnet per type is allowed.
                                            if (-not [String]::IsNullOrEmpty($network.subnetUri))
                                            {

                                                $Message = "The Subnet parameter contains more than 1 IPv4 subnet. Only a single IPv4 address pool can be assigned to an Ethernet network."
                                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidSubnetOperation InvalidOperation 'Subnet' -TargetType 'PSObject' -Message $Message
                                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                            }

                                            $network.subnetUri = $_subnet.uri

                                        }

                                        $ResourceCategoryEnum.IPv6Subnet
                                        {

                                            # Generate error that there are more than 1 IPv4 subnets provided, and only a singular subnet per type is allowed.
                                            if (-not [String]::IsNullOrEmpty($network.ipv6SubnetUri))
                                            {

                                                $Message = "The Subnet parameter contains more than 1 IPv6 subnet. Only a single IPv6 address pool can be assigned to an Ethernet network."
                                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidSubnetOperation InvalidOperation 'Subnet' -TargetType 'PSObject' -Message $Message
                                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                                                
                                            }

                                            $network.ipv6SubnetUri = $_subnet.uri

                                        }

                                    }

                                }

                            }

                        }

                        else 
                        {
                    
                            "[{0}] Creating bulk '{1}' + '{2}' Ethernet Networks" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $VlanRange | Write-Verbose

                            $network = NewObject -BulkEthernetNetworks

                            $network.vlanIdRange                = $VlanRange
                            $network.purpose                    = $EthernetNetworkPurposeEnum[$Purpose]
                            $network.namePrefix                 = $Name
                            $network.smartLink                  = $SmartLink
                            $network.privateNetwork             = $PrivateNetwork
                            $network.bandwidth.typicalBandwidth = $TypicalBandwidth
                            $network.bandwidth.maximumBandwidth = $MaximumBandwidth
                                    
                        }

                    }
                    
                    { @("FC","FibreChannel","Fibre Channel") -contains $_ } 
                    {

                        "[{0}] Creating '$name' FC Network" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $network = NewObject -FCNetwork

                        $network.name                    = $Name
                        $network.linkStabilityTime       = $linkStabilityTime
                        $network.autoLoginRedistribution = $autoLoginRedistribution
                        $network.fabricType              = $FCNetworkFabricTypeEnum[$FabricType]
                        $network.connectionTemplateUri   = $null

                        Try
                        {

                            $network.managedSanUri  = if ($ManagedSan) { (VerifyManagedSan $ManagedSan $_appliance) } else { $null }

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        # If maxbandiwdth value isn't specified, 10Gb is the default value, must change to 8Gb
                        if ( $maximumBandwidth -eq 10000 ){ $maximumBandwidth = 8000 }

                    }

                    "FCOE" 
                    {

                        "[{0}] Creating '$name' FCOE Network" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $network = NewObject -FCoENetwork

                        $network.name                  = $Name
                        $network.vlanId                = $vlanId
                        $network.connectionTemplateUri = $null
                        
                        Try
                        {

                            $network.managedSanUri = if ($ManagedSan) { (VerifyManagedSan $ManagedSan $_appliance) } else { $null }

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }
            
            }

            if ($PSBoundParameters['Scope'])
            {

                ForEach ($_Scope in $Scope)
                {

                    "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                    [void]$network.initialScopeUris.Add($_Scope.Uri)

                }

            }

            foreach($net in $network) 
            {

                if ($net.type.StartsWith('ethernet-networks') -and $net.type -ne 'ethernet-networkV4') { $net.type = 'ethernet-networkV4' }

                if ($net.defaultTypicalBandwidth) 
                { 
                    
                    $typicalBandwidth = $net.defaultTypicalBandwidth 
                    $net = $net | Select-Object * -ExcludeProperty defaultTypicalBandwidth
                
                }
                
                if ($net.defaultMaximumBandwidth) 
                { 
                    
                    $maximumBandwidth = $net.defaultMaximumBandwidth 
                    $net = $net | Select-Object * -ExcludeProperty defaultMaximumBandwidth

                }

                if ($net.typicalBandwidth) { $typicalBandwidth = $net.typicalBandwidth }
                if ($net.maximumBandwidth) { $maximumBandwidth = $net.maximumBandwidth }
                if ($PSBoundParameters['ImportFile'] -and $net.fabricUri) { $net.fabricUri = $null }
                if ($PSBoundParameters['ImportFile'] -and $net.subnetUri) { $net.subnetUri = $null }
                if ($PSBoundParameters['ImportFile'] -and [Array]$net.scopeUris -gt 0) { [Array]$net.scopeUris = @() }
                if ($PSBoundParameters['ImportFile'] -and $net.connectionTemplateUri) { [Array]$net.connectionTemplateUri = $null }

                switch ($net.type) 
                {

                    {$_ -match "bulk-ethernet-network"}
                    {
                        
                        "[{0}] Creating bulk '{1}' + '{2}' Ethernet Networks" -f $MyInvocation.InvocationName.ToString().ToUpper(), $name, $vlanRange | Write-Verbose

                        $netUri = $EthernetNetworksUri + "/bulk"

                        break

                    }

                    {$_ -match "ethernet-network"}
                    {

                        "[{0}] Creating {1} Ethernet Network" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.name | Write-Verbose

                        $netUri = $EthernetNetworksUri

                        $net = $net | Select-Object * -ExcludeProperty uri

                    }

                    {$_ -match "fc-network"}
                    {

                        "[{0}] Creating {1} FC Network" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.name | Write-Verbose

                        $netUri = $FcNetworksUri

                        $net = $net | Select-Object * -ExcludeProperty uri

                    }

                    {$_ -match "fcoe-network"}
                    {

                        "[{0}] Creating {1} FCoE Network" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.name | Write-Verbose

                        $netUri = $FCoENetworksUri

                        $net = $net | Select-Object * -ExcludeProperty uri

                    }

                    # Should never get here. If so, this is an internal error we need to fix.
                    default 
                    {

                        $ErrorRecord = New-ErrorRecord System.ArgumentException InvalidNetworkType InvalidType 'type' -Message "(INTERNAL ERROR) The Network Resource Type $($net.type) is invalid for '$($net.name)' network."
                        
                        # Generate Terminating Error
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                $objStatus = [pscustomobject]@{ 
                    
                    Name      = $net.Name; 
                    Status    = $Null; 
                    Details   = $Null;
                    Exception = $Null;
                
                }

                $task = $null

                # Check if Network Type is Direct Attach and if ManagedFabric Parameter is being called at the same time.
                if (($fabricType -eq "DirectAttach" -or $fabricType -eq "DA") -and $managedfabric) 
                { 

                    $objStatus.Details = "You specified a DirectAttach Fabric Type and passed the ManagedSan Parameter. The ManagedSan Parameter is to be used for FabricAttach networks only."
                   
                }

                else 
                {
                     
                    Try
                    {

                        "[{0}] Sending request to create '$($net.name)' network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $task = Send-HPOVRequest -Uri $netUri -Method POST -Body $net -Hostname $_appliance 
                    
                    }    
                    
                    Catch
                    {

                        "[{0}] Exception caught when trying to create '$($net.name)' network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] Exception: $($_.Exception.Message.ToString())" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $objStatus.Status    = "Failed"
                        $objStatus.Details   = $_.exception.message
                        $objStatus.Exception = $_

                    }

                }

                if (-not $task.Uri) 
                {

                    "[{0}] Create Network Object '$($net.name)' request was rejected." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $objStatus.Status = "Failed"
                    
                    # Do not want to overwrite the details value from the Fabric Type check above.
                    if ($task) { $objStatus.Details = $task }

                }

                else 
                { 
                    
                    "[{0}] Create Network Object '$($net.name)' creating. Monitor task." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Wait for the network to be created
                    Try
                    {

                        $task = Wait-HPOVTaskComplete $task #-Appliance $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $objStatus.Status  = $task.taskState
                    $objStatus.Details = $task

                }

                [void] $colStatus.add($objStatus) #| Out-Null

                # Update Bandwidth allocation if set to different than default values, bypassing bulk network create
                if (($typicalBandwidth -or $maximumBandwidth) -and (-not($objStatus.Status -eq "Failed")) -and $net.type -ne $EthernetNetworkBulkType ) 
                {

                    "[{0}] Setting bandwidth to network object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Network object to retrieve ConnectionTemplate URI" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get network resource URI
                    Try
                    {

                        $net = Send-HPOVRequest $task.associatedResource.resourceUri -Hostname $_appliance

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    "[{0}] ConnectionTemplate URI '$($net.connectionTemplateUri)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($net -and $net.connectionTemplateUri) 
                    {

                        $ctUri = $net.connectionTemplateUri
                        
                        Try
                        {

                            $ct = Send-HPOVRequest -Uri $ctUri -Hostname $_appliance

                            if ($typicalBandwidth) { $ct.bandwidth.typicalBandwidth = $typicalBandwidth }

                            if ($maximumBandwidth) { $ct.bandwidth.maximumBandwidth = $maximumBandwidth }

                            $void = Send-HPOVRequest -Uri $ct.uri -Method PUT -Body $ct -Hostname $ct.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }        

                    }

                }

                if ($PSBoundParameters['NetworkSet'])
                {

                    ForEach ($_netset in $NetworkSet)
                    {

                        "[{0}] NetworkSet {1} was provided, validating." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_netset.name | Write-Verbose

                        # Genrate Error
                        if (-not($_netset -is [PSCustomObject]))
                        {

                            $Message = 'The NetworkSet Parameter value is not an Object. Please provide a valid Object by using the Get-HPOVNetworkSet Cmdlet.'
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidHPOVNetworkSetValue InvalidArgument 'NetworkSet' -TargetType $_subnet.Gettype().Name -Message $Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Genrate Error, invalid object type
                        if ($ResourceCategoryEnum.NetworkSet -ne $_netset.category)
                        {

                            $Message = "The NetworkSet Parameter value is not a valid IP Subnet object. The object category provided was {0}. Please provide a valid Object by using the Get-HPOVNetworkSet Cmdlet." -f $Subnet.category
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidHPOVNetworkSetObject InvalidArgument 'NetworkSet' -TargetType 'PSObject' -Message $Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Invalid object for the appliance connection
                        if ($_netset.ApplianceConnection.Name -ne $_appliance.Name)
                        {

                            $Message = "The NetworkSet Parameter value is missing the 'ApplianceConnection' property. Please provide a valid Object by using the Get-HPOVNetworkSet Cmdlet."
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidNetworkTypeOperation InvalidOperation 'NetworkSet' -TargetType 'PSObject' -Message $Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        Set-HPOVNetworkSet -InputObject $_netset -AddNetwork $net -ApplianceConnection $_appliance | Wait-HPOVTaskComplete | Out-Null

                    }

                }

            }

        }

    }

    End 
    {

        if ($colStatus | Where-Object { $_.Status -ne "Completed" }) 
        { 
            
            write-error "One or more networks failed the creation attempt!" 
        
        }

        Return $colStatus
        
    }

}

function VerifyManagedSan 
{

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Object]$managedSan,

        [Parameter (Mandatory)]    
        [ValidateNotNullorEmpty()]    
        [object]$Appliance
    
    )
    
    Process 
    {

        if ($managedSan -eq "" -or $Null -eq $ManagedSan) 
        {
           
            $managedSanUri = $Null

        }

        elseif ($managedSan -is [PSCustomObject] -and $managedSan.category -eq 'fc-sans') 
        { 
                    
            $managedSanUri = $managedSan.uri
                        
        }

        elseif ($managedSan -is [PSCustomObject] -and -not ($managedSan.category -eq 'fc-sans')) 
        { 
                    
            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidManagedSanUri InvalidArgument 'managedSan' -Message "The Managed SAN object category provided '$($managedSan.category)' is not the the expected value of 'fc-sans'. Please verify the Parameter value and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   
                        
        }
                   
        elseif ($managedSan -is [String] -and $managedSan.StartsWith('/rest/')) 
        { 
                    
            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidManagedSanUri InvalidArgument 'managedSan' -Message "The Managed SAN Uri provided '$managedSan' is incorrect. Managed SAN URI must Begin with '/rest/fc-sans/managed-sans'."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)                       
                    
        }
                    
        elseif ($managedSan -is [String] -and (-not($managedSan.StartsWith($script:fcManagedSansUri)))) 
        {

            # Get ManagedSan object
            Try { $managedSanUri = (Get-HPOVManagedSan $managedSan -appliance $Appliance).uri }

            # If specified ManagedSan object does not exist, generate trappable error
            catch 
            {
        
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidManagedSanName InvalidArgument 'managedSan' -Message "The Managed SAN Name provided '$managedSan' was not found."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

            }

        }

        else 
        {

            $managedSanUri = $managedSan

        }

        Return $managedSanUri

    }

}

function Get-HPOVNetwork 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (ParameterSetName = 'Default', ValueFromPipeline, Mandatory = $false)]
        [ValidateNotNullOrEmpty ()]
        [SupportsWildcards ()]
        [String]$Name,
        
        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ("Ethernet", "FC", "FibreChannel", "FCOE")]
        [String]$Type,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ("General", "Management", "VMMigration", "FaultTolerance", "ISCSI")]
        [String]$Purpose,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty ()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty ()]
        [String]$Label,
        
        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),
        
        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Alias ("x", "export")]
        [ValidateScript ({split-path $_ | Test-Path})]
        [String]$exportFile
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['type']))
        {

            "[{0}] -Type Parameter wasn't provided. Specifying all Network Resource Types." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            [Array]$Type = "Ethernet","FibreChannel","FCOE"

        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $NetworkCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($PSBoundParameters['Purpose'])
            {

                $Type = 'Ethernet'

            }

            $Found = [System.Collections.ArrayList]::new()

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Build the category to search for
            $_Category = New-Object System.Text.StringBuilder

            switch ($Type)
            {

                "Ethernet" 
                { 
                    
                    [void]$_Category.Append('category=ethernet-networks&')
                
                }
                
                "FibreChannel" 
                { 
                    
                    [void]$_Category.Append('category=fc-networks&')
                
                }
                
                "FCOE" 
                { 
                    
                    [void]$_Category.Append('category=fcoe-networks&')

                }

            }

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace(" ","?").Replace("*", "%2A")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            if ($Purpose)
            {

                [Void]$_Query.Add(("purpose:'{0}'" -f $Purpose))

            }

            # Build the final URI
            $_uri = '{0}?{1}sort=name:asc&query={2}' -f $IndexUri, $_Category.ToString(), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                $_NetworksFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_member in $_NetworksFromIndexCol)
            {

                switch ($_member.category)
                {

                    'ethernet-networks'
                    {

                        $_member.psobject.typenames.Insert(0,"HPOneView.Networking.EthernetNetwork")  

                    }

                    'fc-networks'
                    {

                        $_member.psobject.typenames.Insert(0,"HPOneView.Networking.FibreChannelNetwork")  

                    }

                    'fcoe-networks'
                    {

                        $_member.psobject.typenames.Insert(0,"HPOneView.Networking.FCoENetwork")  

                    }

                }

                "[{0}] Adding '{1}' to found collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.Name | Write-Verbose
                
                [void]$Found.Add($_member)

            }

            # If network not found, report error
            if ($Found.Count -eq 0 -and $Name)
            { 

                "[{0}] Network Resource Name was provided, yet no results were found. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = "The specified '{0}' Network resource was not found on '{1}' appliance connection. Please check the name and try again." -f $Name, $_appliance.Name 
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException NetworkResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_item in $Found)
                {

                    "[{0}] Adding '{1}' to final collection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Name | Write-Verbose
                
                    [void]$NetworkCollection.Add($_item)
                
                } 

            }            

        }

    }

    End 
    {

        if ($NetworkCollection) 
        {

            "[{0}] Results returned " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Networks Found: {1} " -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkCollection.Count | Write-Verbose

            "[{0}] Getting Network resource Connection Template Object to add bandwidth values to network objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($NetObject in $NetworkCollection) 
            {

                "[{0}] Processing '$($NetObject.Name)' Network resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($NetObject.connectionTemplateUri) 
                {

                    Try
                    {

                        $ct = Send-HPOVRequest -uri $NetObject.connectionTemplateUri -Hostname $NetObject.ApplianceConnection.Name

                    }

                    Catch
                    {

                      $PSCmdlet.ThrowTerminatingError($_)

                    }                    
            
                    Add-Member -InputObject $NetObject -NotePropertyName defaultMaximumBandwidth -NotePropertyValue $ct.bandwidth.maximumBandwidth -Force 
                    Add-Member -InputObject $NetObject -NotePropertyName defaultTypicalBandwidth -NotePropertyValue $ct.bandwidth.typicalBandwidth -Force

                }
        
            }

            "[{0}] Done. {1} network resource(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkCollection.Count | Write-Verbose 
            
            if ($exportFile) 
            { 
                
                "[{0}] Exporting JSON to $($exportFile)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
            
                $NetworkCollection | Sort-Object type,name | convertto-json > $exportFile
            
            }
            
            else
            {

                $NetworkCollection | Sort-Object type,name
            
            }
        
        }

        # No networks found
        else
        { 
            
            "[{0}] No Network resources found."  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
        
        }

    }

}

function Set-HPOVNetwork 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Ethernet")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [Alias ('net','Network')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [String]$Prefix,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [String]$Suffix,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ("General", "Management", "VMMigration", "FaultTolerance", "ISCSI")]
        [String]$Purpose,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Bool]$Smartlink, 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Bool]$PrivateNetwork, 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [validaterange(2,20000)]
        [int32]$TypicalBandwidth, 
        
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [validaterange(100,20000)]
        [int32]$MaximumBandwidth, 

        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateRange(1,1800)]
        [Alias ('lst')]
        [int32]$LinkStabilityTime, 

        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [Alias ('ald')]
        [Bool]$AutoLoginRedistribution,

        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [Object]$ManagedSan,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Object]$IPv4Subnet,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Object]$IPv6Subnet,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            "[{0}] Network resource passed via pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_NetworksToUpdate = [System.Collections.ArrayList]::new()
        $NetCollection     = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        #build collection of networks to modify
        foreach ($net in $InputObject) 
        {

            if ($PSBoundParameters['LinkStabilityTime'] -and $net.category -eq 'fcoe-networks')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'LinkStabilityTime' -TargetType 'Int' -Message "The -LinkStabilityTime Parameter is not supported with FCoE Network resources, only FibreChannel network resources. Please check your call and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($PSBoundParameters['AutoLoginRedistribution'] -and $net.category -eq 'fcoe-networks')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'AutoLoginRedistribution' -TargetType 'Boolean'  -Message "The -AutoLoginRedistribution Parameter is not supported with FCoE Network resources, only FibreChannel network resources. Please check your call and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Check the name Parameter value if the caller inadvertantly provided an object for name Parameter
            if ($name -and ($name -match "category=ethernet-networks" -or $name -match "category=fc-networks" -or $name -match "category=fcoe-networks"))
            { 
            
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Name' -Message "The -name Parameter value appears to have been passed the network resource object, which is converted to type [String] and is an invalid operation. Please verify that you provided the Network Name attribute in the -name Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

            elseif ($name -and $name.length -gt 255) 
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Name' -Message "The -name Parameter value is greater than 255 characters. Please check the -name Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            switch ($net.Gettype().Name) 
            {

                "PSCustomObject" 
                { 
    
                    if ($net -is [PSCustomObject] -and ($net.category -eq "ethernet-networks" -or $net.category -eq "fc-networks" -or $net.category -eq "fcoe-networks")) 
                    {

                        "[{0}] Collecting $($net.type) $($net.name) resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "[$($net.gettype().name)] is an unspported data type. Only [System.String] or [PSCustomObject] or an [Array] of [System.String] or [PSCustomObject] network resources are allowed. Please check the -network Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                    
                }

                "String" 
                { 
                
                    # User provided Network 'name' and 1 or more Appliance Connections
                    if ($net -is [String] -and (-not ($net.StartsWith('/rest/'))))
                    {
                    
                        ForEach ($_appliance in $ApplianceConnection)
                        {

                            "[{0}] Getting '$($net)' resource from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            Try 
                            {

                                $net = Get-HPOVNetwork -Name $net -type $PSCmdlet.ParameterSetName -ApplianceConnection $_appliance -ErrorAction Stop

                            }
                            
                            Catch [HPOneView.NetworkResourceException]
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                            
                            if ($net.count -gt 1)
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException NonUniqueNetworkName InvalidResult 'InputObject' -Message "Multiple '$_tempNet' Network resource found with the same name. Please check the value and try again, or provide the Network Resource Object instead of the name."
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }
                        
                    }

                    elseif ($net -is [String] -and ($net.StartsWith('/rest/ethernet-networks/') -or $net.StartsWith('/rest/fc-networks/'))) 
                    {
                    
                        "[{0}] Getting '$($net)' resource from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $net = Send-HPOVRequest -URi $net -Appliance $ApplianceConnection

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                    
                    }
                
                }

            }

            # Perform the work
            # Set Specific Network Type settings
            switch ($net.category) 
            {

                "ethernet-networks" 
                {

                    "[{0}] Updating $($net.name) Ethernet Network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    switch ($PSBoundParameters.keys) 
                    {

                        "purpose" 
                        { 
                        
                            "[{0}] Setting network Purpose to: $purpose" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $net.purpose = $EthernetNetworkPurposeEnum[$Purpose]
                            
                        }

                        "smartlink" 
                        {

                            "[{0}] Setting smartlink Enabled to: $([Bool]$smartlink)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $net.smartlink = [Bool]$Smartlink

                        }

                        "privateNetwork" 
                        { 

                            "[{0}] Setting privateNetwork Enabled to: $([Bool]$privateNetwork)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $net.privateNetwork = [Bool]$PrivateNetwork
                        
                        }

                        'IPv4Subnet'
                        {

                            if ($null -eq $PSBoundParameters['IPv4Subnet'])
                            {

                                "[{0}] Setting subnetUri to null" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $net.subnetUri = $null

                            }

                            else
                            {

                                if ($IPv4Subnet.category -ne $ResourceCategoryEnum.IPv4Subnet)
                                {

                                    "[{0}] Invalid IPv4 Address Pool resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ExceptionMessage = "An invalid IPv4 Address Pool resource object was provided. Please verify the Parameter value and try again."
                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4AddressPoolResource InvalidArgument 'IPv4Subnet' -TargetType 'PSObject' -Message $ExceptionMessage
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                $net.subnetUri = $IPv4Subnet.uri

                            }                            

                        }

                        'IPv6Subnet'
                        {

                            if ($null -eq $PSBoundParameters['IPv6Subnet'])
                            {

                                "[{0}] Setting subnetIPv6Uri to null" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $net.ipv6SubnetUri = $null

                            }

                            else
                            {

                                if ($IPv6Subnet.category -ne $ResourceCategoryEnum.IPv6Subnet)
                                {

                                    "[{0}] Invalid IPv6 Address Pool resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ExceptionMessage = "An invalid IPv6 Address Pool resource object was provided. Please verify the Parameter value and try again."
                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4AddressPoolResource InvalidArgument 'IPv6Subnet' -TargetType 'PSObject' -Message $ExceptionMessage
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                $net.ipv6SubnetUri = $IPv6Subnet.uri

                            }                            

                        }

                    }

                }

                "fc-networks" 
                {

                    switch ($PSBoundParameters.keys) 
                    {

                        "LinkStabilityTime" 
                        {

                            "[{0}] Setting LinkStabilityTime to '$LinkStabilityTime' seconds" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if ($net.fabricType -eq 'DirectAttach')
                            {

                                $ExceptionMessage = "Cannot set LinkStabilityTime value to a DirectAttach FibreChannel resource, {0}." -f $net.name
                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidFabricOperation InvalidOperation 'LinkStabilityTime' -TargetType $LinkStabilityTime.Gettype().Name -Message $ExeptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            $net.linkStabilityTime = [Int]$linkStabilityTime

                        }

                        "AutoLoginRedistribution" 
                        {

                            "[{0}] Setting AutoLoginRedistribution Enabled to: $([Bool]$AutoLoginRedistribution)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if ($net.fabricType -eq 'DirectAttach')
                            {

                                $ExceptionMessage = "Cannot set AutoLoginRedistribution value to a DirectAttach FibreChannel resource, {0}" -f $net.name
                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidFabricOperation InvalidOperation 'AutoLoginRedistribution' -TargetType $AutoLoginRedistribution.Gettype().Name -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }
                            
                            $net.autoLoginRedistribution = [Bool]$autoLoginRedistribution

                            if ($net.linkStabilityTime -eq 0 -and (-not($LinkStabilityTime)) -and [Bool]$AutoLoginRedistribution)
                            {

                                $ExceptionMessage = "The '{0}' FC Network resource is a Direct Attach fabric. The Managed SAN resource cannot be modified." -f $_net.name
                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidLinkStabilityTimeValue InvalidOperation 'AutoLoginRedistribution' -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }

                        "ManagedSan"
                        {

                            if ($null -eq $PSBoundParameters['ManagedSan'])
                            {

                                "[{0}] Setting managedSanUri to null" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $net.managedSanUri = $null

                            }

                            else
                            {

                                if ($net.fabricType -eq 'DirectAttach')
                                {

                                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidFabricOperation InvalidResult 'Network' -Message ("The '{0}' FC Network resource is a Direct Attach fabric. The Managed SAN resource cannot be modified." -f $net.name)
                                    $PSCmdlet.WriteError($ErrorRecord)

                                }

                                else
                                {

                                    "[{0}] Processing ManagedSAN for FC Network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    Try
                                    {

                                        $net.managedSanUri = (VerifyManagedSan $managedSan $net.ApplianceConnection.Name)

                                    }

                                    Catch
                                    {

                                        $PSCmdlet.ThrowTerminatingError($_)

                                    }

                                }

                            }
                            
                        }

                    }

                }

                "fcoe-networks"
                {
                    
                    switch ($PSBoundParameters.keys) 
                    {

                        "managedSan"
                        {

                            "[{0}] Processing ManagedSAN for FC Network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                            $net.managedSanUri = (VerifyManagedSan $managedSan $net.ApplianceConnection.Name)
                            
                        }

                    }

                }

            }

            # Shared Parameters for each Network Type
            if ($PSBoundParameters["name"]) 
            {
            
                "[{0}] Updating Network name to '$name'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Validate name Parameter is [String]
                $net.name = $name
                
            }
    
            if ($PSBoundParameters["prefix"]) 
            {
                
                "[{0}] Updating Network name to include '$prefix' prefix to Network Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Updated Network Name: $($prefix + $net.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Validate name Parameter is [String]
                $net.name = $prefix + $net.name
                
            }
    
            if ($PSBoundParameters["suffix"]) 
            {
                
                "[{0}] Updating Network name to include '$suffix' suffix to Network Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Updated Network Name: $($net.name + $suffix)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Validate name Parameter is [String]
                $net.name += $suffix
                
            }
    
            if ($PSBoundParameters["typicalBandwidth"] -or $PSBoundParameters["maximumBandwidth"]) 
            {
    
                "[{0}] Updating Network bandwidth assignment." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Getting Connection Template resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $ct = Send-HPOVRequest $net.connectionTemplateUri -Appliance $net.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                } 
                
                if ($PSBoundParameters["maximumBandwidth"]) 
                {
                
                    "[{0}] Original Maximum bandwidth assignment: $($ct.bandwidth.maximumBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] New Maximum bandwidth assignment: $maximumBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ct.bandwidth.maximumBandwidth = $maximumBandwidth
    
                }

                if($PSBoundParameters["typicalBandwidth"]) 
                {
    
                    "[{0}] Original Typical bandwidth assignment: $($ct.bandwidth.typicalBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] New Typical bandwidth assignment: $typicalBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ct.bandwidth.typicalBandwidth = $typicalBandwidth
                    
                }
    
                Try
                {

                    $ct = Send-HPOVRequest -Uri $ct.uri -Method PUT -Body $ct -Appliance $ct.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
    
            }

            $net = $net | Select-Object * -ExcludeProperty defaultTypicalBandwidth, defaultMaximumBandwidth, created, modified

            Try
            {

                $resp = Send-HPOVRequest -Uri $net.uri -Method PUT -Body $net -Appliance $net.ApplianceConnection.Name
            
            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $resp            

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

} 

function Remove-HPOVNetwork 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('uri', 'name', 'network','Resource')]
        [System.Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection    = [System.Collections.ArrayList]::new()
        $_NetworkCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Network Object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

            If ('ethernet-networks','fc-networks','fcoe-networks' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Network:$($InputObject.Name)" -TargetType PSObject -Message "The Network resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_NetworkCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Network:$($InputObject.Name)" -TargetType PSObject -Message "The Network resource is not an expected category type [$($InputObject.category)]. Allowed resource category types are 'ethernet-networks', 'fc-networks', or 'fcoe-networks'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($net in $InputObject) 
            {

                # Network passed is a URI
                if (($net -is [String]) -and [System.Uri]::IsWellFormedUriString($net,'Relative')) 
                {

                    "[{0}] Received URI: $($net)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Network Name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $net = Send-HPOVRequest -Uri $net -ApplianceConnection $ApplianceConnection

                    }

                    Catch
                    {

                      $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

                # Network passed is the Name
                elseif (($net -is [String]) -and (!$net.startsWith("/rest"))) 
                {

                    "[{0}] Received Network Name $($net)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Network object from Get-HPOVNetwork" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    # // NEED APPLIANCE NAME HERE with If Condition
                    $net = Get-HPOVNetwork -Name $net -ApplianceConnection $ApplianceConnection

                    if ($network.count -gt 1 ) 
                    { 

                        $ErrorRecord = New-ErrorRecord InvalidOperationException NetworkResourceNameNotUnique InvalidResult 'Remove-HPOVNetwork' -Message "Invalid Network Parameter: $net"
                        $PSCmdlet.WriteError($ErrorRecord)                
                    
                    }

                }

                # Network passed is the object
                elseif ($net -is [PSCustomObject] -and ('ethernet-networks', 'fc-networks', 'fcoe-networks' -match $net.category)) 
                {
                    
                    "[{0}] Network Object provided.)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.name | Write-Verbose
                    "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.uri | Write-Verbose
                    "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.ApplianceConnection.Name | Write-Verbose
                    "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $net.category | Write-Verbose
                
                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Network' -TargetType 'PSObject' -Message "Invalid Network Parameter: $($net )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                [void]$_NetworkCollection.Add($InputObject)

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_NetworkCollection.count) Network resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Network Resources
        ForEach ($_network in $_NetworkCollection)
        {

            if ($PSCmdlet.ShouldProcess($_network.name,"Remove Network from appliance '$($_network.ApplianceConnection.Name)'")) 
            {

                "[{0}] Removing Network '$($_network.name)' from appliance '$($_network.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($PSBoundParameters['Force'])
                    {

                        $_network.uri += "?force=true"

                    }

                    $_resp = Send-HPOVRequest -Uri $_network.Uri -Method DELETE -AddHeader @{'If-Match' = $_network.eTag } -Hostname $_network.ApplianceConnection.Name

                    [void]$_TaskCollection.Add($_resp)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function New-HPOVNetworkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [String]$Name,

        [Parameter (Mandatory)]
        [Alias ('networkUris')]
        [Object]$Networks,

        [Parameter (Mandatory = $False)]
        [Alias ('untagged','native','untaggedNetworkUri')]
        [Object]$UntaggedNetwork,

        [Parameter (Mandatory = $False)]
        [int32]$TypicalBandwidth = 2500,

        [Parameter (Mandatory = $False)]
        [int32]$MaximumBandwidth = 10000,
    
        [Parameter (Mandatory = $False)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_NetSetStatusCol = [System.Collections.ArrayList]::new()    

    }
    
    Process 
    {


        "[{0}] Processing '{1}' Appliance Connection" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ApplianceConnection.Name | Write-Verbose

        "[{0}] Building NetworkSet '{1}' object." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

        $_NewNetSet = Newobject -NetworkSet

        $_NewNetSet.name = $Name

        # Validate Networks if they are objects, and ApplianceConnection prop matches $_connection.Name value
        ForEach ($_net in $Networks)
        {

            switch ($_net.GetType().Name)
            {

                'String'
                {

                    # URI provided
                    if ($_net.StartsWith($EthernetNetworksUri))
                    {

                        "[{0}] Network resource is [String] and URI. Getting resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        try
                        {

                            $_net = Send-HPOVRequest -Uri $_net -Hostname $ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    # Name provided
                    else
                    {

                        "[{0}] Network resource is [String] and Name. Getting resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        try
                        {

                            $_originalnet = $_net.Clone()

                            $_net = Get-HPOVNetwork -Name $_net -ApplianceConnection $ApplianceConnection.Name -ErrorAction Stop

                            if ($_net.count -gt 1)
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException MultipleNetworkResourcesFound LimitsExceeded 'Networks' -Message "Network '$_originalnet' is not a unique resource name, as multiple Network resources were found. Please correct the Parameter value and try again."
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

                'PSCustomObject'
                {

                    "[{0}] Processing Object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.name | Write-Verbose
                    "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.uri | Write-Verbose
                    "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.ApplianceConnection.Name | Write-Verbose
                    "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.category | Write-Verbose

                    # Object must have the ApplianceConnection NoteProperty
                    if (-not($_net.ApplianceConnection))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException MissingApplianceConnectionNoteProperty InvalidArgument 'Networks' -TargetType 'PSObject' -Message "Network '$($_net.name)' does not contain the required 'ApplianceConnection' NoteProperty. Network objects must be retrieved from the appliance either using their unique URI or with Get-HPOVNetwork. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($_net.ApplianceConnection.Name -ne $ApplianceConnection.Name)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException ApplianceConnetionDoesNotMatchObject InvalidArgument 'Networks' -TargetType 'PSObject' -Message "Network '$($_net.name)' 'ApplianceConnection' NoteProperty {$($_net.ApplianceConnection.Name)}does not match the Appliance Connection currently Processing {$($ApplianceConnection.Name)}. Network objects must be retrieved from the appliance either using their unique URI or with Get-HPOVNetwork. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($_net.category -ne 'ethernet-networks')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException UnsupportedResourceCategory InvalidArgument 'Networks' -TargetType 'PSObject' -Message "Network '$($_net.name)' category {$($_net.category)} is not the supported type, 'ethernet-networks'. Network objects must be retrieved from the appliance either using their unique URI or with Get-HPOVNetwork using the -Type Ethernet Parameter. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                default
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException UnsupportedParameterValueType InvalidType 'Networks' -TargetType $_Net.GetType().Name -Message "The provided Networks Parameter value type '$($_Net.GetType().Name)' is not supported. Only String (Name or URI) or PSCustomObject types are allowed and supported. Please correct the Parameter value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            [void]$_NewNetSet.networkUris.Add($_net.uri)

        }

        if ($PSboundParameters['UntaggedNetwork'])
        {

            # Validate UntaggedNetwork if it is an object, and ApplianceConnection prop matches $_connection.Name value
            switch ($UntaggedNetwork.GetType().Name)
            {

                'String'
                {

                    # URI provided
                    if ($UntaggedNetwork.StartsWith($EthernetNetworksUri))
                    {

                        "[{0}] UntaggedNetwork resource is [String] and URI. Getting resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        try
                        {

                            $UntaggedNetwork = Send-HPOVRequest -Uri $UntaggedNetwork -Hostname $ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    # Name provided
                    else
                    {

                        "[{0}] UntaggedNetwork resource is [String] and Name. Getting resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        try
                        {

                            $UntaggedNetwork = Get-HPOVNetwork -Name $UntaggedNetwork -ApplianceConnection $ApplianceConnection.Name -ErrorAction Stop

                            if ($UntaggedNetwork.count -gt 1)
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException MultipleNetworkResourcesFound LimitsExceeded 'UntaggedNetwork' Message "Network '$_originalnet' is not a unique resource name, as multiple Network resources were found. Please correct theParameter value and try again."
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

                'PSCustomObject'
                {

                    "[{0}] Processing Untagged object." -f $MyInvocation.InvocationName.ToString().ToUpper(), $UntaggedNetwork.name | Write-Verbose
                    "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $UntaggedNetwork.name | Write-Verbose
                    "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $UntaggedNetwork.uri | Write-Verbose
                    "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $UntaggedNetwork.ApplianceConnection.Name | Write-Verbose
                    "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $UntaggedNetwork.category | Write-Verbose

                    # Object must have the ApplianceConnection NoteProperty
                    if (-not($UntaggedNetwork.ApplianceConnection))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException MissingApplianceConnectionNoteProperty InvalidArgument 'UntaggedNetwork' -TargetType 'PSObject' -Message "Network '$($UntaggedNetwork.name)' does not contain the required 'ApplianceConnection' NoteProperty. Networkobjects must be retrieved from the appliance either using their unique URI or with Get-HPOVNetwork. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($UntaggedNetwork.ApplianceConnection.Name -ne $ApplianceConnection.Name)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException ApplianceConnetionDoesNotMatchObject InvalidArgument 'UntaggedNetwork' -TargetType 'PSObject' -Message "Network '$($UntaggedNetwork.name)' 'ApplianceConnection' NoteProperty {$($UntaggedNetwork.ApplianceConnection.Name)}does notmatch the Appliance Connection currently Processing {$($ApplianceConnection.Name)}. Network objects must be retrieved from the appliance either using their unique URI or with Get-HPOVNetwork. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($UntaggedNetwork.category -ne 'ethernet-networks')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException UnsupportedResourceCategory InvalidArgument 'UntaggedNetwork' -TargetType'PSObject' -Message "Network '$($UntaggedNetwork.name)' category {$($UntaggedNetwork.category)} is not the supported type, 'ethernet-networks'. Network objects must be retrieved from the appliance either using their unique URI or with Get-HPOVNetwork using the -Type Ethernet Parameter.Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                default
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException UnsupportedParameterValueType InvalidType 'UntaggedNetwork' -TargetType    $UntaggedNetwork.GetType().Name -Message "The provided UntaggedNetwork Parameter value type '$($UntaggedNetwork.GetType().Name)' is not supported. Only String (Name or URI) or PSCustomObject types are allowed and supported. Please correct the Parameter value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            $_NewNetSet.nativeNetworkUri = $UntaggedNetwork.uri

        }

        # Caller is requesting different bandwidth settings. Need to handle async task to create network set.
        if ($PSBoundParameters['TypicalBandwidth'] -or $PSBoundParameters['MaximumBandwidth']) 
        {

            try 
            {

                $_task = Send-HPOVRequest -Uri $NetworkSetsUri -Method POST -Body $_NewNetSet -Hostname $ApplianceConnection.Name | Wait-HPOVTaskComplete

                if ($_task.taskStatus -eq "Created") 
                {

                    "[{0}] Network Set was successfully created" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Updating Network Set bandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Requested Typical bandwidth: $($typicalBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Requested Maximum bandwidth: $($maximumBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get Network Set Object
                    Try
                    {

                        $_NetSetObj = Send-HPOVRequest -Uri $_task.associatedResource.resourceUri -Hostname $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                        
                    # Update the associated connection template with max & typical bandwidth settings
                    Try
                    {

                        $_ct = Send-HPOVRequest -Uri $_NetSetObj.connectionTemplateUri -Hostname $ApplianceConnection.Name

                    }
                        
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                        

                    if ($PSBoundParameters['typicalBandwidth']) { $_ct.bandwidth.typicalBandwidth = $typicalBandwidth }

                    if ($PSBoundParameters['maximumBandwidth']) { $_ct.bandwidth.maximumBandwidth = $maximumBandwidth }
                        
                    # Update Connection Template Object
                    Try
                    {

                        $_ct = Send-HPOVRequest -Uri $_ct.uri -Method PUT -Body $_ct -Hostname $ApplianceConnection.Name

                    }
                        
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Get Network Set Object after CT has been updated
                    Try
                    {

                        $_NetSetObj = Send-HPOVRequest -Uri $_NetSetObj.uri -Hostname $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                        
                }

            }

            catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [void]$_NetSetStatusCol.Add($_NetSetObj)

        }

        else 
        {

            "[{0}] Sending request with default bandwidth." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_task = Send-HPOVRequest -Uri $NetworkSetsUri -Method POST -Body $_NewNetSet -Hostname $ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [void]$_NetSetStatusCol.Add($_task)

        }

    }

    End 
    {

        # Return Network Set collection status/objects
        Return $_NetSetStatusCol

    }

}

function Get-HPOVNetworkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Export")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$ExportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_NetworkSetCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category=network-sets'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # If network not found, report error
            if ($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            { 

                "[{0}] Network Set Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified '{0}' Network Set resource was not found on appliance {1}. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkSetResourceException NetworkSetResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    if ($_member.connectionTemplateUri) 
                    {

                        "[{0}] Getting Network Set resource Connection Template Object to add bandwidth values to network objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $ct = Send-HPOVRequest -uri $_member.connectionTemplateUri -Hostname $_appliance

                        }
                    
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        Add-Member -InputObject $_member -NotePropertyName maximumBandwidth -NotePropertyValue $ct.bandwidth.maximumBandwidth -Force 
                        Add-Member -InputObject $_member -NotePropertyName typicalBandwidth -NotePropertyValue $ct.bandwidth.typicalBandwidth -Force

                    }

                    $_member.PSObject.TypeNames.Insert(0,"HPOneView.Networking.NetworkSet")  

                    [void]$_NetworkSetCollection.Add($_member)

                }

            }

        }

    }

    End 
    {

        "[{0}] Done. {1} network set resource(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_NetworkSetCollection.Count | Write-Verbose 
        
        if ($ExportFile) 
        { 
            
            "{0}] Exporting JSON to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ExportFile | Write-Verbose 
        
            $_NetworkSetCollection | convertto-json > $exportFile
        
        }
        
        else
        {

            Return $_NetworkSetCollection
        
        }

    }

}

function Set-HPOVNetworkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [Alias ('NetSet', 'NetworkSet')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Object]$Networks,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Object[]]$AddNetwork,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Object[]]$RemoveNetwork,

        [Parameter (Mandatory = $False)]
        [Alias ('untagged','native','untaggedNetworkUri')]
        [ValidateNotNullorEmpty()]
        [Object]$UntaggedNetwork,

        [Parameter (Mandatory = $false)]
        [validaterange(2,20000)]
        [int32]$TypicalBandwidth, 
        
        [Parameter (Mandatory = $false)]
        [validaterange(100,20000)]
        [int32]$MaximumBandwidth,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                # Check for URI Parameters with multiple appliance connections
                if($ApplianceConnection.Count -gt 1)
                {

                    if ($InputObject -is [String] -and ($InputObject.StartsWith($NetworkSetsUri))) 
                    {
                    
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'InputObject' -Message "The InputObject Parameter as URI is unsupported with multiple appliance connections. Please check the -NetworkSet Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                    }

                    if (($Networks -is [String] -and $Networks.startswith($EthernetNetworksUri)) -or ($Networks -is [Array] -and ($Networks | ForEach-Object { $_.startswith($EthernetNetworksUri) })))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Networks' -TargetType $Networks.GetType().Name -Message "Networks Parameter contains 1 or more URIs that are unsupported with multiple appliance connections. Please check the -networks Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($UntaggedNetwork -is [String] -and $UntaggedNetwork.startswith($EthernetNetworksUri)) 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Untaggednetwork' -Message "Untaggednetwork Parameter as URI is unsupported with multiple appliance connections. Please check the -untaggednetwork Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        # Process Network Set input object is the correct resource and data type.
        switch ($InputObject.Gettype().Name) 
        {

            "PSCustomObject" 
            { 
    
                if ($InputObject.category -eq "network-sets")
                {

                    "[{0}] Processing $($InputObject.type) $($InputObject.name) resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkSetResourceException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided InputObject resource contains an unsupported category type, '$($NetworkSet.category)'. Only 'network-sets' resources are allowed. Please check the -NetworkSet Parameter value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
                
            }

            "String" 
            { 
                
                if (-not ($NetworkSet.StartsWith($NetworkSetsUri)))
                {
                    
                    "[{0}] Getting '$($InputObject)' resource from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $InputObject = Get-HPOVNetworkSet -Name $InputObject -ErrorAction Stop -appliance $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                        

                }

                elseif ($InputObject.StartsWith($NetworkSetsUri))
                {
                    
                    "[{0}] Getting '$($InputObject)' resource from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $InputObject = Send-HPOVRequest -Uri $InputObject -appliance $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }
                
            }

            default
            {
                    
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkSetResourceException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "[$($InputObject.gettype().name)] is an unsupported data type. Only [System.String] or [PSCustomObject] Network Set resources are allowed. Please check the -InputObject Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        $_UpdatedNetSet = $InputObject.PSObject.Copy()

        $_UpdatedNetSet.networkUris = [System.Collections.ArrayList]::new()

        # Rebuild the list of URIs
        ForEach ($_OriginalNetUri in $InputObject.networkUris)
        {

            [void]$_UpdatedNetSet.networkUris.Add($_OriginalNetUri)

        }

        # Process Network Set Name change
        if ($PSBoundParameters["Name"]) 
        {
            
            "[{0}] Updating Network Set name to '$name'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_UpdatedNetSet.name = $name
            
        }

        if ($PSBoundParameters["Networks"]) 
        {

            "[{0}] Processing $($Networks.count) network resources" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $i = 1

            "[{0}] Clearing out existing networkUris." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_UpdatedNetSet.networkUris = [System.Collections.ArrayList]::new()

            foreach ($_net in $Networks) 
            {

                switch ($_net.GetType().Name)
                {

                    'String'
                    {

                        if ($_net.startswith($EthernetNetworksUri)) 
                        {

                            "[{0}] Network [$i] is a URI: $_net" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                [void]$_UpdatedNetSet.networkUris.Add($_net)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        elseif ($_net -is [String]) 
                        {

                            "[{0}] Network [$i] is a Name: $_net" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_networkObject = Get-HPOVNetwork $_net -type Ethernet -appliance $ApplianceConnection

                                [void]$_UpdatedNetSet.networkUris.Add($_networkObject.uri)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                                
                        }

                    }

                    'PSCustomObject'
                    {

                        if ($_net.category -eq "ethernet-networks") 
                        {

                            "[{0}] Network [$i] is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$i] Name: $($_net.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$i] uri: $($_net.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Networks' -TargetType $_Net.GetType().Name -Message "Network '$($_net.name)' is not a supported type '$($_net.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        [void]$_UpdatedNetSet.networkUris.Add($_net.uri)

                    }

                    default
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Networks' -TargetType $_Net.GetType().Name -Message "The provided Network is not a supported type '$($_net.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                $i++
                    
            }

        }

        if ($PSBoundParameters['AddNetwork'])
        {

            $a = 1

            ForEach ($_NetToAdd in $AddNetwork)
            {

                switch ($_NetToAdd.GetType().Name)
                {

                    'String'
                    {

                        if ($_NetToAdd.startswith($EthernetNetworksUri)) 
                        {

                            "[{0}] Network [$a] is a URI: $_NetToAdd" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToAdd = Send-HPOVRequest -Uri $_NetToAdd -Appliance $ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        elseif ($_NetToAdd -is [String]) 
                        {

                            "[{0}] Network [$a] is a Name: $_NetToAdd" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToAdd = Get-HPOVNetwork -Name $_NetToAdd -type Ethernet -appliance $ApplianceConnection -ErrorAction Stop

                                # [void]$_UpdatedNetSet.networkUris.Add($_networkObject.uri)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                                
                        }

                    }

                    'PSCustomObject'
                    {

                        if ($_NetToAdd.category -eq "ethernet-networks") 
                        {

                            "[{0}] Network [$a] is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$a] Name: $($_NetToAdd.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$a] uri: $($_NetToAdd.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        {

                            $ExceptionMessage = "Network '{0}' is not a supported type '{1}'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again." -f $_NetToAdd.name, $_NetToAdd.gettype().fullname
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'AddNetwork' -TargetType $_NetToAdd.GetType().Name -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    default
                    {

                        $ExceptionMessage = "The provided Network is not a supported type '$($_NetToAdd.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'AddNetwork' -TargetType $_NetToAdd.GetType().Name -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                "[{0}] Adding network '{1}' to Network Set" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_NetToAdd.name | Write-Verbose

                [void]$_UpdatedNetSet.networkUris.Add($_NetToAdd.uri)

                $a++

            }

        }

        if ($PSBoundParameters['RemoveNetwork'])
        {

            $r = 1

            ForEach ($_NetToREmove in $RemoveNetwork)
            {

                switch ($_NetToRemove.GetType().Name)
                {

                    'String'
                    {

                        if ($_NetToRemove.startswith($EthernetNetworksUri)) 
                        {

                            "[{0}] Network [$r] is a URI: $_NetToRemove" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToRemove = Send-HPOVRequest -Uri $_NetToAdd -Appliance $ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        elseif ($_NetToRemove -is [String]) 
                        {

                            "[{0}] Network [$r] is a Name: $_NetToRemove" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToRemove = Get-HPOVNetwork -Name $_NetToRemove -type Ethernet -appliance $ApplianceConnection -ErrorAction Stop

                                # [void]$_UpdatedNetSet.networkUris.Add($_networkObject.uri)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                                
                        }

                    }

                    'PSCustomObject'
                    {

                        if ($_NetToRemove.category -eq "ethernet-networks") 
                        {

                            "[{0}] Network [$r] is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$r] Name: $($_NetToRemove.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$r] uri: $($_NetToRemove.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        {

                            $ExceptionMessage = "Network '{0}' is not a supported type '{1}'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again." -f $_NetToRemove.name, $_NetToRemove.gettype().fullname
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'RemoveNetwork' -TargetType $_NetToRemove.GetType().Name -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    default
                    {

                        $ExceptionMessage = "The provided Network is not a supported type '$($_NetToRemove.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'RemoveNetwork' -TargetType $_NetToRemove.GetType().Name -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                "[{0}] REmoving network '{1}' from Network Set" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_NetToRemove.name | Write-Verbose

                [void]$_UpdatedNetSet.networkUris.Remove($_NetToRemove.uri)

                $r++
            }

        }

        if ($PSBoundParameters["UntaggedNetwork"])
        {

            switch ($UntaggedNetwork.GetType().Name)
            {

                'String'
                {

                    if ($UntaggedNetwork.startswith($EthernetNetworksUri)) 
                    {

                        "[{0}] Untagged Network is a URI: $UntaggedNetwork" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_UpdatedNetSet.nativeNetworkUri = (Send-HPOVRequest $UntaggedNetwork -Hostname $ApplianceConnection).uri

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    elseif ($UntaggedNetwork -is [String]) 
                    {

                        "[{0}] Untagged Network is a Name: $UntaggedNetwork" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_networkObject = Get-HPOVNetwork -Name $UntaggedNetwork -type Ethernet -appliance $ApplianceConnection -ErrorAction Stop

                            $_UpdatedNetSet.nativeNetworkUri = $_networkObject.uri

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                                
                    }

                }

                'PSCustomObject'
                {

                    if ($UntaggedNetwork.category -eq "ethernet-networks") 
                    {

                        "[{0}] Native Network is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] Native Network Name: $($UntaggedNetwork.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] Native Network uri: $($UntaggedNetwork.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'UntaggedNetwork' -TargetType $UntaggedNetwork.GetType().Name -Message "The UntaggedNetwork '$($UntaggedNetwork.name)' is not a supported type '$($UntaggedNetwork.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_UpdatedNetSet.nativeNetworkUri = $UntaggedNetwork.uri

                }

                default
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'UntaggedNetwork' -TargetType $UntaggedNetwork.GetType().Name -Message "The provided UntaggedNetwork is not a supported type '$($UntaggedNetwork.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        # Process Network Set Bandwidth assignment change
        if ($PSBoundParameters["TypicalBandwidth"] -or $PSBoundParameters["MaximumBandwidth"]) 
        {

            "[{0}] Updating Network bandwidth assignment." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting Network Set Connection Template." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
            Try
            {

                $_ct = Send-HPOVRequest -Uri $_UpdatedNetSet.connectionTemplateUri -appliance $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
                
            if ($PSBoundParameters["MaximumBandwidth"]) 
            {
                
                "[{0}] Original Maximum bandwidth assignment: $($_ct.bandwidth.maximumBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] New Maximum bandwidth assignment: $MaximumBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ct.bandwidth.maximumBandwidth = $MaximumBandwidth

            }

            if($PSBoundParameters["TypicalBandwidth"]) 
            {

                "[{0}] Original Typical bandwidth assignment: $($_ct.bandwidth.typicalBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] New Typical bandwidth assignment: $TypicalBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ct.bandwidth.typicalBandwidth = $TypicalBandwidth
                    
            }

            Try
            {

                $_ct = Send-HPOVRequest -Uri $_UpdatedNetSet.connectionTemplateUri -Method PUT -Body $_ct -appliance $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_UpdatedNetSet = $_UpdatedNetSet | Select-Object * -ExcludeProperty typicalBandwidth, maximumBandwidth, created, modified, state, status
            
        Try
        {

            $_results = Send-HPOVRequest -Uri $_UpdatedNetSet.Uri -Method PUT -Body $_UpdatedNetSet -appliance $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        [void]$_TaskCollection.Add($_results)

    }

    End 
    {

        Return $_TaskCollection

    }

}

function Remove-HPOVNetworkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default" ,SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name")]
        [Object]$NetworkSet,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['NetworkSet']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                # Check for URI Parameters with multiple appliance connections
                if($ApplianceConnection.Count -gt 1)
                {

                    if (($NetworkSet -is [String] -and ($NetworkSet.StartsWith($NetworkSetsUri))) -or ($NetworkSet -is [Array] -and ($NetworkSet | ForEach-Object { $_.startswith($NetworkSetsUri) }))) 
                    {
                    
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'NetworkSet' -Message "The NetworkSet Parameter as URI is unsupported with multiple appliance connections. Please check the -NetworkSet Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                    }

                }


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_NetSetsToRemoveCol = [System.Collections.ArrayList]::new()

        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput)
        {

            "[{0}] Processing NetworkSet object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkSet.name | Write-Verbose
            "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkSet.uri | Write-Verbose
            "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkSet.ApplianceConnection.Name | Write-Verbose
            "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkSet.category | Write-Verbose

            if ($NetworkSet.category -ne 'network-sets')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkSetResourceException InvalidArgumentValue InvalidArgument 'NetworkSet' -TargetType 'PSObject' -Message "The provided Network Set {$($NetworkSet.Name)} is an unsupported object category, '$($NetworkSet.category)'. Only 'network-sets' category objects are supported. please chceck the Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$_NetSetsToRemoveCol.Add($NetworkSet)

        }

        Else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing $($_appliance.Name) appliance connection (of $($ApplianceConnection.Count))." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    "[{0}] Getting Network Set object from Get-HPOVNetworkSet." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $NetworkSet = Get-HPOVNetworkSet $NetworkSet -ApplianceConnection $_appliance

                    [void]$_NetSetsToRemoveCol.Add($NetworkSet)

                }

                Catch
                {


                    $PSCmdlet.ThrowTerminatingError($_)
                }

            }

        }

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_NetSet in $_NetSetsToRemoveCol) 
        {

            if ($PSCmdlet.ShouldProcess($_NetSet.name,"Remove Network Set from appliance '$($_NetSet.ApplianceConnection.Name)'"))
            {   
             
                
                Try
                {
                    
                    $_task = Send-HPOVRequest -Uri $_NetSet.uri -Method DELETE -AddHeader @{'If-Match' = $_NetSet.eTag } -Hostname $_NetSet.ApplianceConnection.Name

                    [void]$_TaskCollection.Add($_task)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function Get-HPOVAddressPool 
{  

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('VMAC', 'VWWN', 'VSN', 'IPv4', 'IPv6', 'All')]
        [String[]]$Type = "All",
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        "[{0}] Requested Address Pool type: $($Type) " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if ($Type -ieq "all") { $Type = @("VMAC", "VWWN", "VSN", "IPv4") }

        $_AddressPoolCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            switch ($Type) 
            {

                'IPv4'
                {

                    "[{0}] Retrieve IPv4 Address Pool details." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    # Get the VMAC Pool object
                    Try
                    {

                        $_IPv4Pool = Send-HPOVRequest -Uri $ApplianceIPv4PoolsUri -Hostname $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_IPv4Pool | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPool") 
                    
                        [void]$_AddressPoolCollection.Add($_)
                    
                    } 
                    
                }

                'IPv6'
                {

                    "[{0}] Retrieve IPv6 Address Pool details." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    # Get the VMAC Pool object
                    Try
                    {

                        $_IPv6Pool = Send-HPOVRequest -Uri $ApplianceIPv4PoolsUri -Hostname $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_IPv6Pool | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPool") 
                    
                        [void]$_AddressPoolCollection.Add($_)
                    
                    } 
                    
                }

                "vmac" 
                { 

                    "[{0}] Retrieve VMAC Address Pool details." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    # Get the VMAC Pool object
                    Try
                    {

                        $_VMACPool = Send-HPOVRequest $ApplianceVmacPoolsUri -Hostname $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_VMACPool | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPool") 
                    
                        [void]$_AddressPoolCollection.Add($_)
                    
                    } 

                }

                "vwwn" 
                { 

                    "[{0}] Retrieve VWWN Address Pool details." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose    
            
                    # Get the VWWN Pool object
                    Try
                    {

                        $_VWWNPool = Send-HPOVRequest $ApplianceVwwnPoolsUri -Hostname $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_VWWNPool | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPool") 
                    
                        [void]$_AddressPoolCollection.Add($_)
                    
                    } 
                    
                }
                
                "vsn" 
                {

                    "[{0}] Retrieve VSN Address Pool details." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get the VSN Pool object
                    Try
                    {

                        $_VWWNPool = Send-HPOVRequest -Uri $ApplianceVsnPoolsUri -Hostname $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_VWWNPool | ForEach-Object { 
                        
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPool") 
                    
                        [void]$_AddressPoolCollection.Add($_)
                    
                    } 

                }

            }

        }

    }

    End 
    {

        return $_AddressPoolCollection 

    }

}

function Get-HPOVAddressPoolRange 
{  

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [ValidateSet ('IPv4', 'vmac', 'vwwn', 'vsn', 'all')]
        [Alias('Pool')]
        [Object]$Type = 'all',

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Pipeline")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Pipeline")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_RangeList = [System.Collections.ArrayList]::new()
                    
    }

    Process 
    {

        if ($PipelineInput -or $PSBoundParameters['InputObject'])
        {

            if (($InputObject.category -match "id-pool-" -or $InputObject.category -eq $ResourceCategoryEnum.IPv4Subnet) -and $InputObject.ApplianceConnection) 
            {

                foreach ($_RangeUri in $InputObject.rangeUris) 
                {

                    Try
                    {

                        $_rangeObject = Send-HPOVRequest $_RangeUri -Hostname $InputObject.ApplianceConnection.Name

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_rangeObject | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPoolRange") } 
                    
                    [void]$_RangeList.Add($_rangeObject)

                }

            }

            elseif ($InputObject.category -match "id-pool-" -and -not($InputObject.ApplianceConnection))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException MissingApplianceConnectionProperty InvalidArgument 'InputObject' 'PSObject' -Message "The InputObject Parameter value does not contain an ApplianceConnection property. Did this object come from Get-HPOVAddressPool or Send-HPOVRequest? Please correct the Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else 
            {
            
                $ExceptionMessage = "The InputObject Parameter value is not a valid Poll ID object. Object Category '{0}', expected 'id-pool-vmac', 'id-pool-vwwn', or 'id-pool.vsn'. Please correct the Parameter value and try again." -f $InputObject.category
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }

        else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                Try
                {

                    $_AddressPoolCol = Get-HPOVAddressPool -Type $Type -ApplianceConnection $_appliance.Name -ErrorAction Stop

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                foreach ($_AddressPool in $_AddressPoolCol) 
                {

                    ForEach ($_RangUri in $_AddressPool.rangeUris)
                    {

                        Try
                        {

                            $_rangeObject = Send-HPOVRequest $_RangUri -Hostname $_AddressPool.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $_rangeObject | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AddressPoolRange") } 

                        [void]$_RangeList.Add($_rangeObject)

                    }

                }

            }

        }    

    }

    End 
    {

        Return $_RangeList

    }

}

function Get-HPOVAddressPoolSubnet
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$NetworkId,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SubnetCollection = [System.Collections.ArrayList]::new()
                    
    }

    Process 
    {


        $_Query = [System.Collections.ArrayList]::new()

        if ($PSBoundParameters['NetworkID'])
        {

            "[{0}] Filtering for NetworkID: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $NetworkID | Write-Verbose

            [Void]$_Query.Add(("name:'{0}'" -f $NetworkID))
            
        }

        $_Category = 'category={0}&category={1}' -f $ResourceCategoryEnum.IPv4Subnet, $ResourceCategoryEnum.IPv6Subnet

        # Build the final URI
        $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

        

        $uri = $ApplianceIPv4SubnetsUri

        ForEach ($_appliance in $ApplianceConnection)
        {

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                ForEach ($_resource in $_ResourcesFromIndexCol)
                { 
                
                    $_resource.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.IPAddressSubnet") 
            
                    $_resource

                } 

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($NetworkId -and $_ResourcesFromIndexCol.Count -eq 0)
            {

                $ExceptionMessage = "The NetworkID {0} was not found on appliance {1}." -f $NetworkId, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException ResourceNotFound ObjectNotFound 'NetworkId' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }        

        }

    }

    End 
    {

        Return $_SubnetCollection

    }

}

function New-HPOVAddressPoolSubnet
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (
    
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Net.IPAddress]$NetworkId,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Alias ("PrefixLength")]
        [ValidateNotNullorEmpty()]
        [String]$SubnetMask,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Net.IPAddress]$Gateway,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Domain,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Net.IPAddress[]]$DNSServers,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Validate Parameters before auth
        if (($SubnetMask -lt 1 -or $SubnetMask -gt 32) -and ($SubnetMask -notmatch $IPSubnetAddressPattern))
        {

            $Exceptionmessage = "The provided SubnetID {0} does not appear to be a valid Subnet Mask." -f $SubnetMask
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4SubnetMask InvalidArgument 'SubnetMask' -TargetType 'String' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SubnetCollection = [System.Collections.ArrayList]::new()
                    
    }

    Process
    {

        # Validate what the NetworkID AddressFamily is

        [IPAddress]$Address = $null;

        if ([IPAddress]::TryParse($NetworkId, [ref]$Address))
        {
    
            switch ($Address.AddressFamily)
            {
                
                # IPv4 AddressFamily
                'InterNetwork'
                {
    
                    Write-Verbose 'IPv4Address'

                    $_Uri = $ApplianceIPv4SubnetsUri

                    # $IPSubnetType = 'IPv4AddressSubnet'

                    # Calculate the CIDR bit value to the SubnetMask Address
                    if ($PSBoundParameters['SubnetMask'].Length -le 2)
                    {

                        Try
                        {

                            "[{0}] Converting Subnet CIDR Bit value to Subnet Mask Address." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            [Int64]$_Int64Value = ([convert]::ToInt64(('1' * $SubnetMask + '0' * (32 - $SubnetMask)), 2))

                            $SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($_Int64Value / 16777216)).ToString(),
                                                                ([math]::Truncate(($_Int64Value % 16777216) / 65536)).ToString(),
                                                                ([math]::Truncate(($_Int64Value % 65536)/256)).ToString(),
                                                                ([math]::Truncate($_Int64Value % 256)).ToString()

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    $_ExcludedIPSubnetIDBin  = (([Net.IPAddress]$ExcludedIPSubnetID).IPAddressToString -split '\.' | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}) -join ""
                    $_ExcludedIPSubnetEndBin = (([Net.IPAddress]$ExcludedIPSubnetEnd).IPAddressToString -split '\.' | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}) -join ""
                    $_NetworIdDecBin         = (([Net.IPAddress]$NetworkId.IPAddressToString).IPAddressToString -split '\.' | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}) -join ""

                    "[{0}] NetworkID overlaps with Reserved Address: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (($_NetworIdDecBin -eq $_ExcludedIPSubnetIDBin) -or (($_NetworIdDecBin -ge $_ExcludedIPSubnetIDBin) -and ($_NetworIdDecBin -le $_ExcludedIPSubnetEndBin))) | Write-Verbose
                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_NetworIdDecBin -eq $_ExcludedIPSubnetIDBin) | Write-Verbose
                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (($_NetworIdDecBin -ge $_ExcludedIPSubnetIDBin) -and ($_NetworIdDecBin -le $_ExcludedIPSubnetEndBin)) | Write-Verbose

                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_NetworIdDecBin | Write-Verbose
                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ExcludedIPSubnetIDBin | Write-Verbose
                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ExcludedIPSubnetEndBin | Write-Verbose

                    if (($_NetworIdDecBin -eq $_ExcludedIPSubnetIDBin) -or (($_NetworIdDecBin -ge $_ExcludedIPSubnetIDBin) -and ($_NetworIdDecBin -le $_ExcludedIPSubnetEndBin)))
                    {

                        "[{0}] The calculated SubnetID overlaps with the reserved IP Address range, 172.30.254.0/24." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4AddressPoolResource InvalidArgument 'NetworkId' -TargetType 'System.Net.IPAddress' -Message ("The provided SubnetID {0} overlaps with the reserved {1} subnet. Please choose a different IPv4 SubnetID." -f $NetworkId, $ExcludedIPSubnetID.IPAddressToString)
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_NewSubnet = NewObject -IPv4Subnet

                    $_NewSubnet.networkId  = $NetworkId.IPAddressToString
                    $_NewSubnet.subnetmask = $SubnetMask

                }
    
                # IPv6 AddressFamily
                'InterNetworkV6'
                {
    
                    Write-Verbose 'IPv6Address'
                    
                    $_Uri = $ApplianceIPv6SubnetsUri

                    # $IPSubnetType = 'IPv6AddressSubnet'

                    $_NewSubnet = NewObject -IPv6Subnet
                    $_NewSubnet.networkId    = $NetworkId.IPAddressToString
                    $_NewSubnet.prefixLength = $SubnetMask
    
                }
                    
    
                default
                {
    
                    $ExceptionMessage = "The provided NetworkID '{0}' did not parse as a valid IPv4 or IPv6 address." -f $NetworkdID

                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ExceptionMessage | Write-Verbose

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4AddressPoolResource InvalidArgument 'NetworkId' -TargetType 'System.Net.IPAddress' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
    
                }
    
            }

            if ($PSBoundParameters['Gateway'])
            {

                $_NewSubnet.gateway = $Gateway.IPAddressToString

            }

            if ($PSBoundParameters['Domain'])
            {

                $_NewSubnet.domain = $Domain

            }                
        
            if ($PSBoundParameters['DnsServers'])
            {

                ForEach ($_dnsServer in $DnsServers)
                { 

                    [void]$_NewSubnet.dnsServers.Add($_dnsServer.IPAddressToString)

                }
            
            }

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Sending request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose             

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_Uri -Method POST -Body $_NewSubnet -Hostname $_appliance

                    $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.IPAddressSubnet")

                    [void]$_SubnetCollection.Add($_resp)
                    
                    $_resp

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
    
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

    }

}

function Set-HPOVAddressPoolSubnet
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'IPv4')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "IPv4")]
        [Alias ('Subnet','IPv4Subnet')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "IPv4")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$SubnetMask,

        [Parameter (Mandatory = $false, ParameterSetName = "IPv4")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
            $_ -match [Net.IPAddress]$_})]
        [Net.IPAddress]$Gateway,

        [Parameter (Mandatory = $false, ParameterSetName = "IPv4")]
        [ValidateNotNullorEmpty()]
        [String]$Domain,

        [Parameter (Mandatory = $false, ParameterSetName = "IPv4")]
        [ValidateNotNullorEmpty()]
        [String[]]$DNSServers,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName , ParameterSetName = "IPv4")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {
            
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_SubnetCollection = [System.Collections.ArrayList]::new()
                    
    }

    Process
    {

        # Validate IPv4Subnet object
        if ($InputObject.category -ne $ResourceCategoryEnum.IPv4Subnet)
        {

            "[{0}] Invalid IPv4 Address Pool resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4AddressPoolResource InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "An invalid IPv4 Address Pool resource object was provided. Please verify the Parameter value and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        switch ($PSBoundParameters.keys)
        {

            'SubnetMask'
            {

                $InputObject.subnetMask = $SubnetMask.IPAddressToString

            }

            'Gateway'
            {

                $InputObject.gateway = $Gateway.IPAddressToString

            }

            'Domain'
            {

                $InputObject.domain = $Domain

            }

            'DNSServers'
            {

                $InputObject.DNSServers = [System.Collections.ArrayList]::new()

                $DNSServers | ForEach-Object { [void]$InputObject.DNSServers.Add($_) }

            }

        }

        # "[{0}] Defining new IPv4 Subnet object: {0}" -f ($InputObject ) | Write-Verbose

        "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $_resp = Send-HPOVRequest $InputObject.uri PUT $InputObject -Hostname $ApplianceConnection.Name

            $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.IPv4AddressSubnet")

            [void]$_SubnetCollection.Add($_resp)

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
    
    }

    End
    {

        Return $_SubnetCollection

    }

}

function Remove-HPOVAddressPoolSubnet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "IPv4",SupportsShouldProcess,ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "IPv4")]
        [Alias ('Subnet', 'IPv4Subnet')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName , ParameterSetName = "IPv4")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_InputObjectPoolsToRemoveCol = [System.Collections.ArrayList]::new()

        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput)
        {

            "[{0}] Processing pipeline input objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        if ($ResourceCategoryEnum.IPv4Subnet, $ResourceCategoryEnum.IPv6Subnet -notcontains $InputObject.category)
        {

            $ExceptionMessage = "The provided InputObject '{0}' is an unsupported object category, '{1}'. Only IPv4 or IPv6 address pool subnet objects are supported. Please chceck the Parameter value and try again." -f $InputObject.Name, $InputObject.category
            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressSubnetException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Begin resource removal Process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_Subnet in $InputObject) 
        {

            if ($PSCmdlet.ShouldProcess($_Subnet.ApplianceConnection.Name,("Remove IP NetworkID '{0}'" -f $_Subnet.networkId)))
            {   
             
                Try
                {
                    
                    Send-HPOVRequest -uri $_Subnet.uri -Method DELETE -AddHeader @{'If-Match' = $_Subnet.eTag } -Hostname $_Subnet.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# Need to enhance with IPv6subnet and pool
function New-HPOVAddressPoolRange 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "IPPool")]
        [Alias ('Subnet', 'IPv4Subnet', 'IPv6Subnet')]
        [ValidateNotNullorEmpty()]
        [Object]$IPSubnet,
    
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "Custom")]
        [ValidateSet ('vmac', 'vwwn', 'vsn')]
        [String]$PoolType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "Custom")]
        [ValidateSet ("Generated", "Custom")]
        [String]$RangeType = "Generated",

        [Parameter (Mandatory, ParameterSetName = "IPPool")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = "Custom")]
        [Parameter (Mandatory, ParameterSetName = "IPPool")]
        [ValidateNotNullorEmpty()]
        [String]$Start,

        [Parameter (Mandatory, ParameterSetName = "Custom")]
        [Parameter (Mandatory, ParameterSetName = "IPPool")]
        [ValidateNotNullorEmpty()]
        [String]$End,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Custom")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "IPPool")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | Out-String) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'IPv4' -and (-not($PSBoundParameters['IPSubnet'])))
        {

            $PipelineInput = $True

        }
        
        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_Collection = [System.Collections.ArrayList]::new()

        # Validate Parameter options here
        if ($PSCmdlet.ParameterSetName -eq 'Custom' -and $RangeType -ne 'Custom')
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectUriNoApplianceConnection InvalidArgument 'RangeType' -Message "Custom Address Range was provided, but the RangeType Parameter value was not set to 'Custom'. Please check to make sure your call is correct, and try again.."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Generate error when defining custom range and not a specific appliance
        if ($PSCmdlet.ParameterSetName -eq 'Custom' -and $ApplianceConnection.count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectUriNoApplianceConnection InvalidArgument 'ApplianceConnection' -Message "A Custom Address Range was provided with no Appliance Connection specified. Custom Address Pool Ranges should be unique per appliance connection. Please specify an Appliance Connection and try your call again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
    
    }

    Process 
    {

        if ($PSCmdlet.ParameterSetName -eq 'IPPool')
        {

            $_newRange = NewObject -IPIDPoolRange

            if ($IPSubnet.category -eq $ResourceCategoryEnum.IPv4Subnet)
            {

                $_subnetMask = $IPSubnet.subnetMask

                $_uri = $ApplianceIPv4PoolRangesUri

            }

            else
            {

                $_subnetMask = $IPSubnet.prefixLength

                $_uri = $ApplianceIPv6PoolRangesUri

                $_newRange.type = 'RangeIPv6'

            }

            # Validate IPSubnet value
            if ($ResourceCategoryEnum.IPv4Subnet, $ResourceCategoryEnum.IPv6Subnet -notcontains $IPSubnet.category)
            {

                "[{0}] Invalid IP Address Pool resource object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = "An invalid IP Address Pool resource object was provided. Please verify the Parameter value and try again."
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPv4AddressPoolResource InvalidArgument 'IPSubnet' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not [HPOneView.Appliance.AddressPool]::IsInSameSubnet($IPSubnet.networkId + '/' + $_subnetMask, $Start))
            {

                "[{0}] The Start address value {1} is not within the Subnet Network ID {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Start, $IPSubnet.networkId | Write-Verbose

                $ExceptionMessage = "The Start address value {0} is not within the Subnet Network ID {1}\{2}." -f $Start, $IPSubnet.networkId, $_subnetMask

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPAddressPoolResource InvalidArgument 'Start' -TargetType 'PSObject' -Message $Exceptionmessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not [HPOneView.Appliance.AddressPool]::IsInSameSubnet($IPSubnet.networkId + '/' + $_subnetMask, $End))
            {

                "[{0}] The End address value {1} is not within the Subnet Network ID {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $End, $IPSubnet.networkId | Write-Verbose

                $Exceptionmessage = "The End address value {0} is not within the Subnet Network ID {1}\{2}." -f $End, $IPSubnet.networkId, $_subnetMask

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolResourceException InvalidIPAddressPoolResource InvalidArgument 'End' -TargetType 'PSObject' -Message $Exceptionmessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Create Pool Range, then assign to Subnet
            
            $_newRange.name         = $Name
            $_newRange.subnetUri    = $IPSubnet.uri

            $_startStopFragments = NewObject -IDPoolStartStopFragment
            $_startStopFragments.startAddress = $Start
            $_startStopFragments.endAddress   = $End

            [void]$_newRange.startStopFragments.Add($_startStopFragments)

            "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_uri -Method POST -Body $_newRange -Hostname $ApplianceConnection.Name

                $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AddressPoolRange')

                $_resp

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        else
        {
                    
            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                # Get the correct URI to request a new Generated Address Range
                "[{0}] Creating new $($PoolType) type address range" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                switch ($PoolType) 
                {

                    "vmac" 
                    { 
            
                        $_newGenRangeUri  = $ApplianceVmacGenerateUri
                        $_newPoolRangeUri = $ApplianceVmacPoolRangesUri

                    }

                    "vwwn" 
                    { 
            
                        $_newGenRangeUri  = $ApplianceVwwnGenerateUri
                        $_newPoolRangeUri = $ApplianceVwwnPoolRangesUri
                
                    }

                    "vsn" 
                    { 
            
                        $_newGenRangeUri  = $ApplianceVsnPoolGenerateUri
                        $_newPoolRangeUri = $ApplianceVsnPoolRangesUri
            
                    }

                }

                switch ($RangeType) 
                {

                    "Generated" 
                    {
                    
                        "[{0}] Generating new address range" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                        # Send the request, and remove the fragmentType property as it's not a valid JSON pfield for the request.
                        Try
                        {

                            $_newRange = Send-HPOVRequest $_newGenRangeUri -Hostname $_appliance.Name | Select-Object -Property * -excludeproperty fragmentType

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        $_newRange | Add-Member -NotePropertyName type -NotePropertyValue "Range"
                        $_newRange | Add-Member -NotePropertyName rangeCategory -NotePropertyValue "GENERATED"

                    }
                
                    "Custom" 
                    {

                        "[{0}] Creating custom new address range" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] Starting Address: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Start | Write-Verbose
                        "[{0}] End Address: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $End | Write-Verbose

                        switch ($PoolType) 
                        {
                        
                            "vmac" 
                            {
                            
                                if (-not $MacAddressPattern.Match($Start).Success) 
                                { 
                                
                                    $ExceptionMessage = "The provided Start address {0} does not conform to a valid MAC Address value." -f $Start

                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolRangeException InvalidMacStartAddress InvalidArgument 'Start' -Message $ExceptionMessage 
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                if (-not $MacAddressPattern.Match($End).Success) 
                                { 
                                
                                    $ExceptionMessage = "The provided End address {0} does not conform to a valid MAC Address value." -f $End

                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolRangeException InvalidMacendAddress InvalidArgument 'End' -Message $ExceptionMessage 
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                                }

                            }
                        
                            "vwwn" 
                            {
                        
                                if (-not $WwnAddressPattern.Match($Start).Success) 
                                { 
                                
                                    $ExceptionMessage = "The provided Start address {0} does not conform to a valid WWN Address value." -f $Start

                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolRangeException InvalidWwnStartAddress InvalidArgument 'Start' -Message $ExceptionMessage 
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                                }

                                if (-not $WwnAddressPattern.Match($End).Success) 
                                { 
                                
                                    $ExceptionMessage = "The provided End address {0} does not conform to a valid WWN Address value." -f $End

                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolRangeException InvalidWwnendAddress InvalidArgument 'End' -Message $ExceptionMessage 
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                                }
                        
                            }

                            "vsn" 
                            {
                        
                                if (-not $Start.StartsWith('VCU')) 
                                { 
                                
                                    $ExceptionMessage = "The provided Start address {0} does not conform to a valid Serial Number value." -f $Start

                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolRangeException InvalidSerialNumberStartAddress InvalidArgument 'Start' -Message $ExceptionMessage 
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                                }

                                if (-not $End.StartsWith('VCU')) 
                                { 
                                
                                    $ExceptionMessage = "The provided End address {0} does not conform to a valid Serial Number value." -f $End

                                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressPoolRangeException InvalidSerialNumberendAddress InvalidArgument 'End' -Message $ExceptionMessage 
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                                }
                        
                            }

                        }
                    
                        $_newRange = NewObject -IDPoolRange

                        $_newRange.startAddress = $Start
                        $_newRange.endAddress   = $End
                
                    }

                }

                "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_newPoolRangeUri -Method POST -Body $_newRange -Hostname $_appliance.Name

                    $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AddressPoolRange')

                    $_resp

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    End
    {

        "[{0}] Done."  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVAddressPoolRange
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Alias ('AddressPool')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName , ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_AddressPoolsToRemoveCol = [System.Collections.ArrayList]::new()

        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput)
        {

            "[{0}] Processing pipeline input objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        "[{0}] Processing object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
        "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
        "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.ApplianceConnection.Name | Write-Verbose
        "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose

        if ($InputObject.category -notmatch 'id-range-')
        {

            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AddressSubnetException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "The provided InputObject {$($InputObject.Name)} is an unsupported object category, '$($InputObject.category)'. Only 'id-range-VMAC', 'id-range-VWWN', 'id-range-VSN' or 'id-range-IPv4-subnet' category objects are supported."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        [void]$_AddressPoolsToRemoveCol.Add($InputObject)

    }

    End
    {

        "[{0}] Begin resource removal process." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_Pool in $_AddressPoolsToRemoveCol) 
        {

            if ($PSCmdlet.ShouldProcess($_Pool.ApplianceConnection.Name,("Remove address pool range '{0}-{1}'" -f $_Pool.startStopFragments.startAddress, $_Pool.startStopFragments.endAddress)))
            {   
                
                Try
                {
                    
                    Send-HPOVRequest -Uri $_Pool.uri -Method DELETE -AddHeader @{'If-Match' = $_Pool.eTag } -Hostname $_Pool.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] Caller passed -WhatIf Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] Caller selected NO to confirmation prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        # Return $_TaskCollection

    }

}

# // TODO: DOC UNITTEST
function Get-HPOVReservedVlanRange
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_FabricManagerCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($_appliance.ApplianceType -ne 'Composer')
            {
    
                $ExceptionMessage = 'The ApplianceConnection {0} is an HPE OneView Virtual Machine Appliance, which does not support SAS Logical Interconnect Group resources.' -f $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)
    
            }    

            else
            {

                # Get reserved vlan range from fabric
                try
                {

                    $_applianceFabrics = Send-HPOVRequest -Uri $DomainFabrics -Hostname $_appliance

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                ForEach ($_fabric in $_applianceFabrics.members)
                {

                    New-Object HPOneView.Networking.ReservedVlanRange($_fabric.reservedVlanRange.start,
                                                                      $_fabric.reservedVlanRange.length,
                                                                      $_fabric.reservedVlanRange.created,
                                                                      $_fabric.reservedVlanRange.modified,
                                                                      $_fabric.reservedVlanRange.etag,
                                                                      $_fabric.reservedVlanRange.uri,
                                                                      $_fabric.ApplianceConnection)
                    

                }

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# // TODO: UNITTEST
function Set-HPOVReservedVlanRange
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateRange(2, 4095)]
        [Int]$Start,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateRange(60, 128)]
        [Int]$Length,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_FabricManagerCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($_appliance.ApplianceType -ne 'Composer')
            {
    
                $ExceptionMessage = 'The ApplianceConnection {0} is an HPE OneView Virtual Machine Appliance, which does not support SAS Logical Interconnect Group resources.' -f $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)
    
            }    

            else
            {

                # Generate error that start and length is larger than allowed 4095
                if (($Start + $Length) -gt 4095)
                {

                    $ExceptionMessage = 'The provided Length value {0} will exceed the allowed range value beyond 4095. Specify a lower Start, or shorter Length value.' -f $Length
                    $ErrorRecord = New-ErrorRecord HPOneView.Networking.ReservedVlanRangeException  InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_UpdatedVlanRange = NewObject -ReservedVlanRange

                $_UpdatedVlanRange.start = $Start
                $_UpdatedVlanRange.length = $Length

                # Get reserved vlan range URI from appliance
                try
                {

                    $_applianceFabrics = Send-HPOVRequest -Uri $DomainFabrics -Hostname $_appliance

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                ForEach ($_fabric in $_applianceFabrics.members)
                {

                    $_uri = '{0}/reserved-vlan-range' -f $_fabric.uri
        
                    Send-HPOVRequest -Uri $_uri -Method PUT -Body $_UpdatedVlanRange -Hostname $_appliance | Wait-HPOVTaskComplete        

                }

            }

        }

    }
    
    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVFabricManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Name,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_FabricManagerCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.FabricManager

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] FabricManager Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified FabricManager '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Networking.FabricManagerResourceException FabricManagerResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage

                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    $_FabricManagerClusterNodes = New-Object 'System.Collections.Generic.List[HPOneView.Networking.FabricManager+ClusterNodeInfo]'
                    $_Tenants = New-Object "System.Collections.Generic.List[HPOneView.Networking.FabricManager+Tenant]";

                    # Loop through fabricManagerClusterNodeInfo
                    ForEach ($_ClusterNode in $_member.fabricManagerClusterNodeInfo)
                    {

                        $_ClusterNodeInfo = New-Object HPOneView.Networking.FabricManager+ClusterNodeInfo($_ClusterNode.id,
                                                                                                          $_ClusterNode.oobMgmtAddr,
                                                                                                          $_ClusterNode.nodeDN,
                                                                                                          $_ClusterNode.connected)

                        $_FabricManagerClusterNodes.Add($_ClusterNodeInfo)

                    }

                    # Loop through tenants
                    ForEach ($_tenant in $_member.tenants)
                    {

                        $_TenantInfo = New-Object HPOneView.Networking.FabricManager+Tenant($_tenant.name,
                                                                                            $_tenant.description,
                                                                                            $_tenant.dn,
                                                                                            $_tenant.uri,
                                                                                            $_tenant.complianceStatus,
                                                                                            $_tenant.state,
                                                                                            $_tenant.status,
                                                                                            $_tenant.preconfigured,
                                                                                            $_tenant.monitored)

                        $_Tenants.Add($_TenantInfo)

                    }

                    New-Object HPOneView.Networking.FabricManager($_member.name,
                                                                  $_member.uri,
                                                                  $_member.eTag,
                                                                  $_member.version,
                                                                  $_FabricManagerClusterNodes,
                                                                  $_Tenants,
                                                                  $_member.state,
                                                                  $_member.status,
                                                                  $_member.created,
                                                                  $_member.modified,
                                                                  $_member.applianceConnection)

                }

            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVFabricManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$ManagementAddress,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$SecondaryManagementAddress,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$TertiearyManagementAddress,

        [Parameter (ParameterSetName = 'Default', Mandatory)]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Switch]$TrustLeafCertificate,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($PSBoundParameters['TrustLeafCertificate'])
            {

                "[{0}] Caller provide the -TrustLeafCertificate switch. Adding SSL certificate to appliance trust store." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Getting SSL certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # This is not an async task operation
                Try
                {

                    $_uri = '{0}/{1}' -f $RetrieveHttpsCertRemoteUri, $ManagementAddress

                    $_DeviceCertificate = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_DeviceCertificateToImport = NewObject -CertificateToImport
                $_DeviceCertificateToImport.certificateDetails[0].base64Data = $_DeviceCertificate.certificateDetails.base64Data
                $_DeviceCertificateToImport.certificateDetails[0].aliasName  = $_DeviceCertificate.certificateDetails.commonName

                Try
                {
                    
                    "[{0}] Adding SSL certificate to appliance trust store." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_uri = '{0}' -f $ApplianceTrustedSslHostStoreUri

                    $_TaskResults = Send-HPOVRequest -Uri $_uri -Method POST -Body $_DeviceCertificateToImport -Hostname $_appliance | Wait-HPOVTaskComplete

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($_TaskResults.taskErrors)
                {

                    "[{0}] Task errors adding SSL certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($_TaskResults.taskErrors.errorCode -eq '409' -and $_TaskResults.taskErrors.message -match 'The certificate already exists for the alias')
                    {

                        "[{0}] Certificate already exists." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else
                    {
                        
                        $ErrorRecord = New-ErrorRecord InvalidOperationException $_TaskResults.taskErrors.errorCode InvalidResult 'Hostname' -Message $_TaskResults.taskErrors.message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            # Build the import object
            "[{0}] - Starting" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_import          = NewObject -AddFabricManager

            $_import.name                         = $Name;
            $_import.userName                     = $Credential.Username
            $_import.password                     = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

            $_FabricManagerClusterNode1 = NewObject -FabricManagerClusterNodeInfo

            $_FabricManagerClusterNode1.oobMgmtAddr = $ManagementAddress

            $_import.fabricManagerClusterNodeInfo.Add($_FabricManagerClusterNode1)

            if ($SecondaryManagementAddress)
            {

                "[{0}] Adding secondary management address." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_FabricManagerClusterNode2 = NewObject -FabricManagerClusterNodeInfo

                $_FabricManagerClusterNode2.oobMgmtAddr = $ManagementAddress

                $_import.fabricManagerClusterNodeInfo.Add($_FabricManagerClusterNode2)

            }

            if ($TertiearyManagementAddress)
            {

                "[{0}] Adding tertieary management address." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_FabricManagerClusterNode3 = NewObject -FabricManagerClusterNodeInfo

                $_FabricManagerClusterNode3.oobMgmtAddr = $ManagementAddress

                $_import.fabricManagerClusterNodeInfo.Add($_FabricManagerClusterNode3)

            }

            Try
            {

                $_resp = Send-HPOVRequest -Uri $FabricManagersUri -Method POST -Body $_import -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_resp.taskState -ne "Running" -and $_resp.taskState -eq "Error" -and $_resp.stateReason -eq "ValidationError") 
            {

                "[{0}] Task error found {1} {2} " -f $MyInvocation.InvocationName.ToString().ToUpper(), $resp.taskState, $resp.stateReason | Write-Verbose

                if ($_resp.taskErrors | Where-Object { $_.errorCode -eq "HYPERVISOR_MANAGER_SECURE_CONNECTION_FAILED" })
                {

                    $ExceptionMessage = 'The leaf certificate for {0} is untrusted by the appliance. Either provide the -TrustLeafCertificate parameter or manually add the certificate using the Add-HPOVApplianceTrustedCertificate Cmdlet.' -f $Hostname
                    $ErrorRecord = New-ErrorRecord InvalidOperationException UntrustedLeafCertificate InvalidResult 'Hostname' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                }

                elseif ($_resp.taskErrors)
                {

                    $_errorMessage = $_resp.taskErrors

                    $ErrorRecord = New-ErrorRecord InvalidOperationException $_errorMessage.errorCode InvalidResult 'Hostname' -Message ($_errorMessage.details + " " + $_errorMessage.message) 

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            if ($Async)
            {

                $_resp

            }

            else
            {

                $_resp | Wait-HPOVTaskComplete

            }        

        }        

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# // TODO: DEVELOP DOCUMENT TEST
function Update-HPOVFabricManager
{


}

function Remove-HPOVFabricManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Networking.FabricManager[]]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Switch]$Force,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ExceptionMessage = "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        Write-Warning "Removing the fabric manager will disassociate it's tenant from all logical interconnects, networks and networks sets. Inconsistencies with the APIC tenant configuration will no longer be monitored or remediated by OneView."

        $RemoveMessage = "remove '{0}' {1}" -f $InputObject.name, $ResourceCategoryEnum.FabricManager

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, $RemoveMessage))
        {

            "[{0}] Removing resource: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Out-String) | Write-Verbose
            "[{0}] URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose

            $_Uri = '{0}' -f $InputObject.uri

            if ($Force)
            {

                $_Uri += '?force=true'

            }

            try
            {

                Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['whatif']) 
        {

            "[{0}] -WhatIf was passed" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Interconnects and Uplinks
#

function Get-HPOVInterconnectType 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Name')]
    Param
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'PartNumber')]
        [ValidateNotNullorEmpty()]
        [String]$PartNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PartNumber')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $Collection = [System.Collections.ArrayList]::new()
        $NotFound   = [System.Collections.ArrayList]::new()
    
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $uri = $interconnectTypesUri + "?sort=name:descEnding"

            if ($PSboundParameters['Name']) 
            { 
                
                $uri += "&filter=name='$name'" 
            
            }
            
            elseif ($PSboundParameters['PartNumber']) 
            {
                
                $uri += "&filter=partNumber='$partNumber'" 
            
            }

            "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $resp = Send-HPOVRequest $uri -Appliance $_appliance

            }

            Catch
            {

              $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($resp.count -gt 0)
            {

                $resp.members | Sort-Object name | ForEach-Object {

                    $_interconnectType = $_

                    $_interconnectType | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.InterconnectType')}

                    [void]$Collection.Add($_interconnectType)

                }

            }

            else 
            {

                [Void]$NotFound.Add($_appliance.Name)

            }

        }

    }

    End 
    {

        if (((-not $Collection) -or ($NotFound.count -gt 1)) -and $Name) 
        {

            $Collection

            $ExceptionMessage = "No Interconnect Types with '{0}' name were found on appliance {1}." -f $Name, ($NotFound -join ", ")
            $ErrorRecord = New-ErrorRecord HPOneView.InterconnectResourceException InterconnectTypeNameResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        elseif (((-not $Collection) -or ($NotFound.count -gt 0)) -and $PartNumber) 
        {

            $Collection

            $ExceptionMessage = "No Interconnect Types with '{0}' partnumber were found on appliance {1}." -f $PartNumber, ($NotFound -join ", ")
            $ErrorRecord = New-ErrorRecord HPOneView.InterconnectTypeResourceException InterconnectTypePartnumberResourceNotFound ObjectNotFound 'PartNumber' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else 
        { 
        
            return $Collection

        }

    }

}

function Get-HPOVSasInterconnectType 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Name')]
    Param
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'PartNumber')]
        [ValidateNotNullorEmpty()]
        [String]$PartNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PartNumber')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $Collection = [System.Collections.ArrayList]::new()
        $NotFound   = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($_appliance.ApplianceType -ne 'Composer')
            {
    
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is an HPE OneView Virtual Machine Appliance, which does not support SAS Logical Interconnect Group resources.' -f $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)
    
            }    

            else
            {        

                $uri = $SasInterconnectTypeUri  + "?sort=name:descEnding"

                if ($PSboundParameters['Name']) 
                { 
                    
                    $uri += "&filter=name='$name'" 
                
                }
                
                elseif ($PSboundParameters['PartNumber']) 
                {
                    
                    $uri += "&filter=partNumber='$partNumber'" 
                
                }

                "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $resp = Send-HPOVRequest $uri -Appliance $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($resp.count -gt 0)
                {

                    $resp.members | Sort-Object name | ForEach-Object {

                        $_interconnectType = $_

                        $_interconnectType | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.SasInterconnectType')}

                        [void]$Collection.Add($_interconnectType)

                    }

                }

                elseif ($resp.count -eq 0 -and $Name)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.InterconnectResourceException SasInterconnectTypeNameResourceNotFound ObjectNotFound 'Name' -Message "No SAS Interconnect Types with '{0}' name were found on appliance '{1}'." -f $Name, $_appliance.Name
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                elseif ($resp.count -eq 0 -and $PartNumber)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.InterconnectResourceException InterconnectTypePartnumberResourceNotFound ObjectNotFound 'Name' -Message "No SAS Interconnect Types with '{0}' PartNumber were found on appliance '{1}'." -f $PartNumber, $_appliance.Name
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

        }

    }

    End 
    {

        return $Collection

    }

}

function Get-HPOVInterconnect 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false)]
        [Alias ("x", "exportFile")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$Export

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $InterconnectCollection   = [System.Collections.ArrayList]::new()
        $ApplianceInterconnectCol = [System.Collections.ArrayList]::new()
        $NotFound                 = [System.Collections.ArrayList]::new()
        
        $InterconnecUris = $SasInterconnectsUri, $InterconnectsUri
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            # Build the final URI
            $_uri = '{0}?category=interconnects&category=sas-interconnects&sort=name:asc&query={1}' -f $IndexUri, [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_member in $_ResourcesFromIndexCol)
            {

                "[{0}] Processing resource {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.name, $_ResourcesFromIndexCol.Count | Write-Verbose

                switch ($_member.category)
                {

                    'sas-interconnects'
                    {

                        # Add the Custom TypeName
                        $_member.PSObject.TypeNames.Insert(0,"HPOneView.Networking.SasInterconnect") 

                    }

                    'interconnects'
                    {

                        # Add the Custom TypeName
                        $_member.PSObject.TypeNames.Insert(0,"HPOneView.Networking.Interconnect") 

                        # Add the Custom Uplink/Stacking Link TypeName
                        $_member.ports | Where-Object { $_.portType -eq "Uplink" -or $_.portType -eq "Stacking" } | ForEach-Object { 
        
                            $_.PSObject.TypeNames.Insert(0,"HPOneView.Networking.Interconnect.UplinkPort") 

                            $_ | Add-Member -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($_appliance.Name, $_appliance.ConnectionID))

                        }
                
                        # Add the Custom Downlink Link TypeName
                        $_member.ports | Where-Object { $_.portType -eq "Downlink" } | ForEach-Object { 
        
                            $_.PSObject.TypeNames.Insert(0,"HPOneView.Networking.Interconnect.DownlinkPort") 

                            $_ | Add-Member -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($_appliance.Name, $_appliance.ConnectionID))

                        }
                    
                    }

                }

                [void]$InterconnectCollection.Add($_member)

            }

            # Generate final error if name wasn't found on appliance(s)
            if ($NotFound.count -gt 0 -and $Name -and $ApplianceInterconnectCol.count -eq 0) 
            {

                $ErrorRecord = New-ErrorRecord HPOneView.InterconnectResourceException InterconnectNameResourceNotFound ObjectNotFound 'Name' -Message "No Interconnect resources with '$Name' name were found on appliance $($NotFound -join ", ")."
                $PSCmdlet.WriteError($ErrorRecord)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if ($Export)
        { 
                
            "[{0}] Exporting to: $($Export)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $InterconnectCollection | convertto-json -Depth 99 | Set-Content -Path $Export -force -encoding UTF8
                
        }

        else
        {

            Return $InterconnectCollection | Sort-Object type, name

        }

    }
    
}

function Get-HPOVLogicalInterconnect 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (ParameterSetName = 'default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Switch]$NonCompliant,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,
        
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Alias ("x", "ExportFile")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$Export

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $LiCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($PSBoundParameters['NonCompliant'])
            {

                "[{0}] Filtering for non-compliant logical interconnects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Void]$_Query.Add("state:'Inconsistent'")

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category=logical-interconnects'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
                
            if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
            { 

                "[{0}] Logical Interconnect '{1}' resource not found on '{2}'. Adding to notfound collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "Specified Logical Interconnect '{0}' was not found on '{1}' appliance. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectGroupNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)  

            }

            elseif ($_ResourcesFromIndexCol.count -eq 0) 
            { 

                "[{0}] No Logical Interconnect resources found on '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.name | Write-Verbose

            }

            else 
            {

                "[{0}] Found {1} Logical Interconnect resource(s)." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ResourcesFromIndexCol.Count | Write-Verbose

                ForEach ($_LiObject in $_ResourcesFromIndexCol)
                {

                    $_LiObject.PSobject.TypeNames.Insert(0,"HPOneView.Networking.LogicalInterconnect")  # FORMAT DONE
                    $_LiObject.snmpConfiguration | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.SnmpConfiguration') } # FORMAT DONE
                    $_LiObject.snmpConfiguration.trapDestinations | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.SnmpConfiguration.Destinations') } # FORMAT DONE
                    $_LiObject.ethernetSettings | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.InterconnectSettings') }
                    $_LiObject.telemetryConfiguration | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.UtilizationSampleSettings') }
                    $_LiObject.portMonitor | ForEach-Object { $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.PortMonitorSettings') }
                
                    [void]$LiCollection.Add($_LiObject) 

                }
 
            }

        }
   
    }

    End 
    {
        
        "[{0}] Done. {1} logical interconnect group(s) found."  -f $MyInvocation.InvocationName.ToString().ToUpper(), $LiCollection.count | Write-Verbose

        if ($Export)
        {
            
            $LiCollection | convertto-json -Depth 99 | Set-Content -Path $Export -force -encoding UTF8 
        
        }
        
        else 
        {

             $LiCollection 
        
        }    

    }

}

function Get-HPOVLogicalInterconnectPortMonitoring
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('uri', 'li','name','Resource')]
        [object]$InputObject,
        
        [Parameter (ValueFromPipelineByPropertyName, ParameterSetName = "default", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        if (-not $InputObject)
        {

            $Pipeline = $true

        }

        else
        {

            "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

    }

    Process
    {

        # Validate input object is $ResourceCategoryEnum.LogicalInterconnect
        if ($InputObject.category -ne $ResourceCategoryEnum.LogicalInterconnect)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object "{0}" is not supported. Only Logical Interconnect resources are supported.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        Try
        {

            $Uri = '{0}/port-monitor' -f $InputObject.uri
            $LIPortMonitorConfigState = Send-HPOVRequest -Uri $Uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($null -ne $LIPortMonitorConfigState.analyzerPort)
        {

            $AnalyzerPort = New-Object HPOneView.Networking.AnalyzerPort($LIPortMonitorConfigState.analyzerPort.portName, 
                                                                         $LIPortMonitorConfigState.analyzerPort.portStatus,
                                                                         $LIPortMonitorConfigState.analyzerPort.portHealthStatus, 
                                                                         $LIPortMonitorConfigState.analyzerPort.interconnectName,
                                                                         $LIPortMonitorConfigState.analyzerPort.bayNumber,
                                                                         $LIPortMonitorConfigState.analyzerPort.interconnectUri, 
                                                                         $LIPortMonitorConfigState.analyzerPort.portUri, 
                                                                         $LIPortMonitorConfigState.ApplianceConnection)
        }

        $_MonitoredPorts = New-Object 'System.Collections.Generic.List[HPOneView.Networking.MonitoredPort]'

        ForEach ($_monitoredport in $LIPortMonitorConfigState.monitoredPorts)
        {

            # Get associated deployed connection
            $Uri = '{0}?name=CONNECTION_TO_INTERCONNECT&childUri={1}' -f $IndexAssociatedResourcesUri, $_monitoredport.interconnectUri

            Try
            {

                $_IndexResults = Send-HPOVRequest -Uri $Uri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_AssociatedConnection = $null

            # Get Connection object(s), and then filter for the associated connection we need
            ForEach ($_IndexEntry in $_IndexResults.members)
            {

                "[{0}] Get full object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_IndexEntry.name | Write-Verbose

                Try
                {

                    $_FullIndexEntry = Send-HPOVRequest -Uri $_IndexEntry.parentResource.uri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($_FullIndexEntry.interconnectPort -eq $_monitoredport.portName.Replace('d', $null))
                {

                    $_AssociatedConnection = $_FullIndexEntry.PSObject.Copy()
                    break;

                }

            }

            $_Vlans = New-Object 'System.Collections.Generic.List[Int]'

            if ($null -ne $_AssociatedConnection)
            {

                # Get list of VLANs
                            

                switch ($_AssociatedConnection.networkResourceUri)
                {

                    {$_.StartsWith($EthernetNetworksUri)}
                    {

                        $_Uri = '{0}' -f $_AssociatedConnection.networkResourceUri

                    }

                    {$_.StartsWith($NetworkSetsUri)}
                    {

                        $_Uri = '{0}/networkSetData' -f $_AssociatedConnection.networkResourceUri

                    }

                }

                Try
                {

                    $_AssociatedNetwork = Send-HPOVRequest -Uri $_Uri -hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                ForEach ($_Network in $_AssociatedNetwork)
                {

                    $_Vlans.Add($_Network.vlanId)

                }

                # Finally, get Server Profile object so we can get Connection ID
                $_ServerProfileUri = '{0}/{1}' -f $ServerProfilesUri, $_AssociatedConnection.containerId

                Try
                {

                    $_ServerProfile = Send-HPOVRequest -Uri $_ServerProfileUri -hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $deletgate = [Func[object,bool]]{ param ($c) return $c.mac -eq $_AssociatedConnection.macAddress }
                $_AssociatedServerProfileConnection = [System.Linq.Enumerable]::Where($_ServerProfile.connectionSettings.connections,$deletgate)

                $_PortDetails = New-Object HPOneView.Networking.MonitoredPort+PortDetails ($_AssociatedServerProfileConnection.connectionId,
                                                                                        $_AssociatedNetwork.name,
                                                                                        $_AssociatedConnection.macAddress,
                                                                                        $_Vlans)
            }        

            $_MonitoredPortConfig = New-Object HPOneView.Networking.MonitoredPort($_monitoredport.portName, 
                                                                                  $_monitoredport.portMonitorConfigInfo,
                                                                                  $_monitoredport.portStatus,
                                                                                  $_monitoredport.portHealthStatus, 
                                                                                  $_monitoredport.interconnectName,
                                                                                  $_monitoredport.bayNumber,
                                                                                  $_monitoredport.interconnectUri, 
                                                                                  $_monitoredport.portUri,
                                                                                  $_PortDetails,
                                                                                  $LIPortMonitorConfigState.ApplianceConnection)
        
            $_MonitoredPorts.Add($_MonitoredPortConfig)

        }

        New-Object HPOneView.Networking.LogicalInterconnect+PortMonitoringConfig($LIPortMonitorConfigState.enablePortMonitor,
                                                                                 $AnalyzerPort,
                                                                                 $_MonitoredPorts,
                                                                                 $LIPortMonitorConfigState.eTag,
                                                                                 $LIPortMonitorConfigState.ApplianceConnection)

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVLogicalInterconnectPortMonitoring
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('uri', 'li','name','Resource')]
        [object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Object]$AnalyzerPort,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Object]$MonitoredPorts,    
        
        [Parameter (ValueFromPipelineByPropertyName, ParameterSetName = "default", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        if (-not $InputObject)
        {

            $Pipeline = $true

        }

        else
        {

            "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($InputObject.category -ne $ResourceCategoryEnum.LogicalInterconnect)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object "{0}" is not supported. Only Logical Interconnect resources are supported.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ([Array]$MonitorPorts.Count -gt 16)
        {

            # Throw exception
            $ExceptionMessage = 'The provided number of monitored ports exceeds the allowed limited of 16. Please remove {0} or more from the MonitoredPorts parameter.' -f ([Array]$MonitorPorts.Count - 16)
            $ErrorRecord = New-ErrorRecord HPOneview.PortMonitorException MonitoredPortsCountExceeded LimitsExceeded "MonitorPorts" -TargetType 'Object' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_Uri = "{0}/port-monitor" -f $InputObject.uri

        # Process AnalyzerPort
        # Split string to get bay and port
        $_AnalyzerPort = $AnalyzerPort.Split(':')

        # Synergy uplink config
        if ($_AnalyzerPort.Count -ge 3)
        {

            '[{0}] Port configuration is Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_EnclosureID = [RegEx]::Replace($_AnalyzerPort[0], '(e|E)nclosure', '')

            # Remove bay so we just have the ID
            $_Bay = [RegEx]::Replace($_AnalyzerPort[1], '(b|B)ay', '')
            
            # Get faceplate portName (Need to make sure Synergy Uplink Port format which uses : instead of . for subport delimiter is replaced correctly)
            $_UplinkPort = [String]$_AnalyzerPort[2].Replace('\.',':')

            if ($_AnalyzerPort.Count -eq 4)
            {

                $_UplinkPort = '{0}.{1}' -f $_UplinkPort, $_AnalyzerPort[3]

            }

        }

        else
        {

            '[{0}] Port configuration is not Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Set the Enclosure ID value. FC type needs to be -1
            $_EnclosureID = "1"

            # Remove bay so we just have the ID
            $_Bay = [RegEx]::Replace($_AnalyzerPort[0], '(b|B)ay', '')
            
            # Get faceplate portName
            $_UplinkPort = $_AnalyzerPort[1]

        }

        '[{0}] Processing Frame "{1}", Bay "{2}", Port "{3}"' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_EnclosureID, $_Bay, $_UplinkPort | Write-Verbose

        # Can I simplify this next 4 lines into a single search call for either LI type (BL and SY)?
        $_EnclosureDeletgate = [Func[object,bool]]{ param ($e) return $e.enclosureIndex -eq $_EnclosureID }
        $_Enclosure = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($InputObject.interconnectMap.interconnectMapEntries, $_EnclosureDeletgate))

        $_InterconnectDelegate = [Func[object,bool]]{ param ($i) return $i.location.locationEntries.type -eq 'Bay' -and $i.location.locationEntries.value -eq $_Bay }
        $_PermittedIc = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($_Enclosure, $_InterconnectDelegate))
        
        "[{0}] Found permitted Interconnect URI {1} for Bay {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PermittedIc.interconnectUri, $_Bay | Write-Verbose

        # Generate error that Interconnect could not be found from the LI
        if ($null -eq $_PermittedIc)
        {

            $ExceptionMessage = 'The Interconnect Bay ID {0} could not be identified within the provided Logical Interconnect resource object.' -f $bay
            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedLogicalInterconnectResource InvalidArgument 'InputObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        # Building Port URI
        $_AnalyzerPortUri = '{0}/ports/{1}:{2}' -f $_PermittedIc.interconnectUri, [regex]::Match($_PermittedIc.interconnectUri, '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}').value, $_UplinkPort
        $_AnalyzerPortCfg = New-Object HPOneView.Networking.AnalyzerPortCfg($_AnalyzerPortUri)

        "[{0}] Adding monitored port {1} to config" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_AnalyzerPortCfg | Write-Verbose
        
        $_LogicalInterconnectPortMonitorConfig = New-Object HPOneView.Networking.PortMonitorCfg ($_AnalyzerPortCfg)

        foreach ($_p in $MonitoredPorts)
        {

            # Split string to get bay and port
            $_port = $_p.Port.Split(':')

            # Synergy uplink config
            if ($_port.Count -ge 3)
            {

                '[{0}] Port configuration is Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_EnclosureID = [RegEx]::Replace($_port[0], '(e|E)nclosure', '')

                # Remove bay so we just have the ID
                $_Bay = [RegEx]::Replace($_port[1], '(b|B)ay', '')
                
                # Get faceplate portName (Need to make sure Synergy Uplink Port format which uses : instead of . for subport delimiter is replaced correctly)
                $_MonitoredPortName = $_port[2].ToLower()

                if ($_port.Count -eq 4)
                {

                    $_MonitoredPortName = '{0}.{1}' -f $_UplinkPort, $_port[3]

                }

            }

            else
            {

                '[{0}] Port configuration is not Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Set the Enclosure ID value. FC type needs to be -1
                $_EnclosureID = "1"

                # Remove bay so we just have the ID
                $_Bay = [RegEx]::Replace($_port[0], '(b|B)ay', '')
                
                # Get faceplate portName
                $_MonitoredPortName = $_port[1].ToLower()

            }

            '[{0}] Processing Frame "{1}", Bay "{2}", Port "{3}"' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_EnclosureID, $_Bay, $_MonitoredPortName | Write-Verbose

            # Can I simplify this next 4 lines into a single search call for either LI type (BL and SY)?
            $_EnclosureDeletgate = [Func[object,bool]]{ param ($e) return $e.enclosureIndex -eq $_EnclosureID }
            $_Enclosure = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($InputObject.interconnectMap.interconnectMapEntries, $_EnclosureDeletgate))
            
            $_InterconnectDelegate = [Func[object,bool]]{ param ($i) return $i.location.locationEntries.type -eq 'Bay' -and $i.location.locationEntries.value -eq $_Bay }
            $_PermittedIc = [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($_Enclosure, $_InterconnectDelegate))
            
            "[{0}] Found permitted Interconnect URI {1} for Bay {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PermittedIc.interconnectUri, $_Bay | Write-Verbose

            # Generate error that Interconnect could not be found from the LI
            if ($null -eq $_PermittedIc)
            {

                $ExceptionMessage = 'The Interconnect Bay ID {0} could not be identified within the provided Logical Interconnect resource object.' -f $_Bay
                $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedLogicalInterconnectResource InvalidArgument 'InputObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            }
            
            $_MonitoredPortUri = '{0}/ports/{1}:{2}' -f $_PermittedIc.interconnectUri, [regex]::Match($_PermittedIc.interconnectUri, '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}').value, $_MonitoredPortName

            $_MonitoredPort = New-Object HPOneView.Networking.MonitoredPortCfg($_MonitoredPortUri, $_p.Direction)

            "[{0}] Adding monitored port {1} to config" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_MonitoredPort | Write-Verbose
                
            $_LogicalInterconnectPortMonitorConfig.MonitoredPorts.Add($_MonitoredPort)

        }

        Try
        {

            Send-HPOVRequest -Uri $_Uri -Method PUT -Body $_LogicalInterconnectPortMonitorConfig -Hostname $ApplianceConnection | Wait-HPOVTaskComplete

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVLogicalInterconnectPortMonitoring
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('uri', 'li','name','Resource')]
        [object]$InputObject,
        
        [Parameter (ValueFromPipelineByPropertyName, ParameterSetName = "default", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        if (-not $InputObject)
        {

            $Pipeline = $true

        }

        else
        {

            "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

    }

    Process
    {

        $_DisablePortMonitorConfig = New-Object HPOneView.Networking.PortMonitorCfg
        $_DisablePortMonitorConfig.DisableConfig()

        $_Uri = "{0}/port-monitor" -f $InputObject.uri

        Try
        {

            Send-HPOVRequest -Uri $_Uri -Method PUT -Body $_DisablePortMonitorConfig -Hostname $ApplianceConnection | Wait-HPOVTaskComplete

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVSasLogicalInterconnect 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,
        
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Alias ("x", "ExportFile")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$Export

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $LiCollection = [System.Collections.ArrayList]::new()
        $NotFound     = [System.Collections.ArrayList]::new()

        if (-not $PSBoundParameters['Type'])
        {

            $Type = 'Ethernet', 'FibreChannel', 'SAS'

        }
        
    }
    
    Process 
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            $_IndexLookup = $false

            $uri = $SasLogicalInterconnectsUri

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose        

            if ($PSBoundParameters['Name']) 
            {

                $Method = 'eq'

                if ($Name.Contains('*'))
                {

                    $Name = $Name.Replace('*', '%25')
                    $Method = 'matches'

                }    

                "[{0}] Logical Interconnect name provided: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                $uri = "{0}?filter=name {1} '{2}'" -f $uri, $Method, $Name

            }

            if ($PSBoundParameters['Label'])
            {

                $uri = "{0}?category:logical-interconnects&sort=name:asc&query=labels:{1}" -f $IndexUri, $Label

                if ($PSBoundParameters['Name'])
                {

                    $uri += '&query=name:{0}' -f $Name

                }

                $_IndexLookup = $true

            }

            Try
            {

                $resp = Send-HPOVRequest -Uri $uri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
                
            if ($resp.count -eq 0 -and $Name) 
            { 

                "[{0}] Logical Interconnect '{1}' resource not found on '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "Specified Logical Interconnect '{0}' was not found on '{1}' appliance. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException SASLogicalInterconnectGroupNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)  

            }

            elseif ($resp.count -eq 0) 
            { 

                "[{0}] No Logical Interconnect resources found on '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            }

            else 
            {

                "[{0})] Found {1} Logical Interconnect resource(s)." -f $MyInvocation.InvocationName.ToString().ToUpper(), $resp.count | Write-Verbose

                ForEach ($_LiObject in $resp.members)
                {

                    Try
                    {

                        if ($_IndexLookup)
                        {

                            "[{0}] Getting LI resource object for {1} (Indexed)." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LiObject.name | Write-Verbose

                            Try
                            {

                                $_LiObject = Send-HPOVRequest -Uri $_LiObject.uri -Hostname $_appliance.Name

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }                            

                        }                        

                        $_LiObject.PSobject.TypeNames.Insert(0,"HPOneView.Storage.SasLogicalInterconnect")  
                    
                        [void]$LiCollection.Add($_LiObject) 

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }
 
            }

        }
   
    }

    End 
    {
        
        "[{0}] Done. {1} logical interconnect(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LiCollection.count | Write-Verbose

        if ($Export)
        {
            
            $LiCollection | convertto-json -Depth 99 | Set-Content -Path $ExportFile -force -encoding UTF8 
        
        }
        
        else 
        {

             $LiCollection 
        
        }    

    }

}

function Update-HPOVLogicalInterconnect 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Reapply")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "FactoryReset")]
        [ValidateNotNullorEmpty()]
        [Alias ('uri', 'li','name','Resource')]
        [object]$InputObject,
        
        [Parameter (ValueFromPipelineByPropertyName, ParameterSetName = "default", Mandatory = $false)]
        [Parameter (ValueFromPipelineByPropertyName, ParameterSetName = "Reapply", Mandatory = $false)]
        [Parameter (ValueFromPipelineByPropertyName, ParameterSetName = "FactoryReset", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory, ParameterSetName = "Reapply")]
        [Switch]$Reapply,
        [Parameter (Mandatory, ParameterSetName = "FactoryReset")]
        [Switch]$FactoryReset

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_returntasks = [System.Collections.ArrayList]::new()
        $_liobjects   = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        "[{0}] Processing $($InputObject.count) LI objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_li in $InputObject) 
        {
            
            # Name provided
            if (($_li -is [String]) -and (-not($_li.StartsWith($LogicalInterconnectsUri))))
            {

                "[{0}] LI Name was provided '$($_li)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Loop through appliance connections to add LI objects to collection
                ForEach ($_appliance in $ApplianceConnection)
                {

                    Try 
                    {

                        Get-HPOVLogicalInterconnect -Name $_li -ApplianceConnection $_appliance.Name | ForEach-Object { [void]$_liobjects.Add($_) }

                    }
                        
                    Catch
                    {

                        "[{0}] $_.FullyQualifiedErrorId Error Caught: $($_.Exception.Message)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                "[{0}] Retrieved $($_liobjects.count) LI Objects" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            elseif (($_li -is [String]) -and ($_li.StartsWith($LogicalInterconnectsUri))) 
            {

                # User didn't provide an appliance connection during call
                if (-not($PSBoundParameters['ApplianceConnection']) -and $ApplianceConnection.Count -gt 1)
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectUriNoApplianceConnection InvalidArgument 'ApplianceConnection' -Message "A Logical Interconnect URI was provided in the -Resource Parameter, but no Appliance Connection specified. URI's are unique per appliance connection. Please specify an Appliance Connection and try your call again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
                
                # User provided more than 1 appliance connection, and LI URI, generate error
                elseif ($ApplianceConnection.Count -gt 1)
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectUriMultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message "A Logical Interconnect URI was provided in the -Resource Parameter, with multiple Appliance Connections specified. URI's are unique per appliance connection. Please specify an Appliance Connection and try your call again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] LI URI was provided $($_li)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try 
                {

                    Send-HPOVRequest $_li -HostName $ApplianceConnection.Name | ForEach-Object { [void]$_liobjects.Add($_) }

                }
                        
                Catch
                {

                    "[{0}] $_.FullyQualifiedErrorId Error Caught: $($_.Exception.Message)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif (($_li -is [PSCustomObject]) -and ($_li.category -ieq 'logical-interconnects')) 
            {

                "[{0}] LI Object was provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_li.name, $_li.uri | Write-Verbose

                [void]$_liobjects.Add($_li)

            }

            else 
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Resource' -TargetType $_li.GetType().Name -Message "An invalid Resource object was provided. $($_li.GetType()) $($_li.category) was provided. Only type String or PSCustomObject, and 'logical-interconnects' object category are permitted."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }

    End 
    {

        # Loop through liobject collection to perform action
        ForEach ($_liobject in $_liobjects)
        {

            "[{0}] Processing Logical Interconnect: $($_liobject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($PSboundParameters['Reapply'])
            { 

                "[{0}] Reapply LI configuration requested." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                if ($PSCmdlet.ShouldProcess($_liobject.name,"Reapply Logical Interconnect configuration. WARNING: Depending on this action, there might be a brief outage."))
                { 

                    Try
                    {

                        "[{0}] Sending request to reapply configuration" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                        $uri = $_liobject.uri + "/configuration"

                        $task = Send-HPOVRequest $uri PUT -Hostname $_liobject.ApplianceConnection.Name

                        [void]$_returntasks.Add($task)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSBoundParameters['WhatIf'])
                {
                    
                    "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else
                {

                    "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }
                
            }

            elseif ($PSboundParameters['FactoryReset'])
            { 

                "[{0}] FactoryReset LI configuration requested." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                if ($PSCmdlet.ShouldProcess($_liobject.name,"Factory reset Logical Interconnect configuration. WARNING: This will cause a complete outage and should only be performed during maintenance window."))
                { 

                    Try
                    {

                        "[{0}] Sending request to FactoryReset configuration" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                        $uri = $_liobject.uri # + "/factoryResetState"

                        $_PatchRequest = NewObject -PatchOperation
                        
                        $_PatchRequest.op    = 'replace'
                        $_PatchRequest.path  = '/factoryResetState'
                        $_PatchRequest.value = 'ReapplyConfiguration'

                        $task = Send-HPOVRequest -Uri $uri -Method PATCH -Body $_PatchRequest -Hostname $_liobject.ApplianceConnection.Name

                        [void]$_returntasks.Add($task)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSBoundParameters['WhatIf'])
                {
                    
                    "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else
                {

                    "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }
                
            }

            else 
            {
                
                # Do not Process LI if consistencyStatus is good.
                if ($_liobject.consistencyStatus -eq 'CONSISTENT')
                {

                    Write-Warning 'Logical Interconnect is Consistent with Policy. Nothing to do.'

                }

                else
                {

                    "[{0}] Update '$($liDisplayName)' Logical Interconnect from parent $($parentLig.name)." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_ligname = (Send-HPOVRequest $_liobject.logicalInterconnectGroupUri -HostName $_liobject.ApplianceConnection.Name).Name
                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                        
                    if ($PSCmdlet.ShouldProcess($_liobject.name,"Update Logical Interconnect from Group '$_ligname'. WARNING: Depending on the Update, there might be a brief outage."))
                    {    
                        
                        Try
                        {

                            "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $uri = $_liobject.uri + "/compliance"

                            $task = Send-HPOVRequest $uri PUT -Hostname $_liobject.ApplianceConnection.Name

                            [void]$_returntasks.Add($task)

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    elseif ($PSBoundParameters['WhatIf'])
                    {
                        
                        "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {
    
                            Compare-LogicalInterconnect -InputObject $_liobject
    
                        } 
    
                        Catch
                        {
    
                            $PSCmdlet.ThrowTerminatingError($_)
    
                        }
                    
                    }

                    else
                    {

                        "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                }

            }

        }

        return $_returntasks

    }

}

# // TODO: Need to make sure HPOneView.Library.CompareObject is Format-Table, and not Format-List?
Function Compare-LogicalInterconnect
{

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory, HelpMessage = "Please provide the Encloure or Logical Interconnect object.")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject

    )

    Begin
    {

        $ApplianceConnection = $InputObject.ApplianceConnection

        Try
        {
        
            'Getting all configured Uplink Set objects.' -f $_LigUplinkSet.name | Write-Verbose #-Verbose
            $UplinkSets = Get-HPOVUplinkSet -ApplianceConnection $ApplianceConnection.Name
            
            'Getting all Interconnect Types objects.' -f $_LigUplinkSet.name | Write-Verbose #-Verbose
            $InterconnectTypes = Get-HPOVInterconnectType -ApplianceConnection $ApplianceConnection.Name
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }

    }

    Process
    {


        $CompareObject            = [System.Collections.ArrayList]::new()
        $_LogicalInterconnects    = [System.Collections.ArrayList]::new()   # Logical Interconnect Uris; not sure what this is used for yet.
        $InterconnectMap          = [System.Collections.ArrayList]::new()   # Collection of Interconnects?
        $InterconnectMapTemplate  = [System.Collections.ArrayList]::new()
        $SideIndicator            = @{ Parent = '<='; Child = '=>'; NotEqual = '<=>'}

        function CompareInterconnects ($_LogicalInterconnect, $_LogicalInterconnectGroup) 
        {

            "Processing Logical Interconnect '{0}' and LIG '{1}'" -f $_LogicalInterconnect.name, $_LogicalInterconnectGroup.name | Write-Verbose #-Verbose

            #Build array of expected Interconnects within LIG
            foreach ($InterconnectMapEntryGroup in $_LogicalInterconnectGroup.interconnectMapTemplate.interconnectMapEntryTemplates) 
            {

                if ($InterconnectMapEntryGroup.permittedInterconnectTypeUri) 
                {

                    [void]$InterconnectMapTemplate.Add([PSCustomObject]@{
                        bayNumber           = ($InterconnectMapEntryGroup.logicalLocation.locationEntries | Where-Object type -eq "BAY").relativeValue; 
                        InterconnectTypeUri = $InterconnectMapEntryGroup.permittedInterconnectTypeUri
                    })
            
                }

            }

            
            #$InterconnectMap = [System.Collections.ArrayList]::new()
            #Build array of actual Interconnects in LI
            foreach ($_InterconnectMapEntry in $_LogicalInterconnect.InterconnectMap.interconnectMapEntries) 
            {

                if ($_InterconnectMapEntry.permittedInterconnectTypeUri) 
                {

                    [void]$InterconnectMap.Add([PSCustomObject]@{
                        bayNumber           = ($_InterconnectMapEntry.location.locationEntries | Where-Object type -eq "Bay").value; 
                        InterconnectTypeUri = $_InterconnectMapEntry.permittedInterconnectTypeUri
                    })

                }

            }

            $diff = Compare-Object -ReferenceObject $InterconnectMapTemplate -DifferenceObject $InterconnectMap -Property bayNumber, InterconnectTypeUri -IncludeEqual

            foreach ($d in $diff) 
            {

                'Processing LI with LIG DIFF' | Write-Verbose #-Verbose

                $InterconnectType = $InterconnectTypes | Where-Object { $_.uri -eq $d.InterconnectTypeUri }

                if ($d.SideIndicator -eq "==") 
                {

                    'Expected Interconnect in "{0}" matches Group for Interconnect bay "{1}" type "{2}"' -f $_LogicalInterconnect.name,  $d.bayNumber, $InterconnectType.name | Write-Verbose #-Verbose
               
                } 
                
                else 
                {

                    if ($d.SideIndicator -eq $SideIndicator.Parent) 
                    {

                        $_diff = New-Object HPOneView.Library.CompareObject($d.bayNumber,
                                                                            $SideIndicator.Child,
                                                                            $InterconnectType.name,
                                                                            $null,
                                                                            $_LogicalInterconnectGroup.name,
                                                                            $_LogicalInterconnect.name,
                                                                            'MISSING_MODULE')

                        [void]$CompareObject.Add($_diff)

                        '"{0}" Logical Interconnect is currently missing expected module "{1}" within Interconnect bay "{2}" ' -f $_LogicalInterconnect.name, $InterconnectType.name, $d.bayNumber | Write-Verbose
                        
                    }
                    
                    elseif ($d.SideIndicator -eq $SideIndicator.Child)  
                    {

                        $_diff = New-Object HPOneView.Library.CompareObject($d.bayNumber,
                                                                            $SideIndicator.Parent,
                                                                            $InterconnectType.name,
                                                                            $null,
                                                                            $_LogicalInterconnectGroup.name,
                                                                            $_LogicalInterconnect.name,
                                                                            'EXTRA_MODULE')

                        [void]$CompareObject.Add($_diff)

                        '"{0}" Logical Interconnect contains an extra module "{1}" within Interconnect bay "{2}" ' -f $_LogicalInterconnect.name, $InterconnectType.name, $d.bayNumber | Write-Verbose

                    }

                }

            }

            # Process Ethernet Settings
            $EthernetSettingsProperties = "enableIgmpSnooping", "igmpIdleTimeoutInterval", "enableFastMacCacheFailover", "macRefreshInterval", "enableNetworkLoopProtection", "enablePauseFloodProtection", "enableRichTLV", "enableTaggedLldp"
            $EthernetSettingsDiff = [System.Collections.ArrayList]::new()

            if ($_LogicalInterconnectGroup.category -ne 'sas-logical-interconnect-groups')
            {

                ForEach ($Property in $EthernetSettingsProperties)
                {

                    if ($_LogicalInterconnectGroup.ethernetSettings.$Property -ne $_LogicalInterconnect.ethernetSettings.$Property)
                    {

                        $_diff = New-Object HPOneView.Library.CompareObject($Property, 
                                                                            $SideIndicator.NotEqual, 
                                                                            $_LogicalInterconnectGroup.ethernetSettings.$Property, 
                                                                            $_LogicalInterconnect.ethernetSettings.$Property, 
                                                                            $_LogicalInterconnectGroup.name,
                                                                            $_LogicalInterconnect.name,
                                                                            'SETTING_MISMATCH')

                        [void]$EthernetSettingsDiff.Add($_diff)
                        [void]$CompareObject.Add($_diff)

                    }

                }

                ForEach ($diff in $EthernetSettingsDiff)
                {

                    'Logical Interconnect "{0}" Ethernet Setting "{1}" does not match the parent "{2}" setting.' -f $diff.InputObject, $diff.ChildSetting, $diff.ParentSetting | Write-Verbose

                }

            # }

            # if ($_LogicalInterconnectGroup.category -ne 'sas-logical-interconnect-groups')
            # {

                # Process QoS
                $_diff = Compare-Object -ReferenceObject $_LogicalInterconnectGroup.qosConfiguration.activeQosConfig.configType -DifferenceObject $_LogicalInterconnect.qosConfiguration.activeQosConfig.configType -PassThru

                if ($_diff.SideIndicator -eq $SideIndicator.Parent)
                {

                    $_diff = New-Object HPOneView.Library.CompareObject('ActiveQosConfig', 
                                                                        $SideIndicator.Parent, 
                                                                        $_LogicalInterconnectGroup.qosConfiguration.activeQosConfig.configType, 
                                                                        $_LogicalInterconnect.qosConfiguration.activeQosConfig.configType, 
                                                                        $_LogicalInterconnectGroup.name,
                                                                        $_LogicalInterconnect.name,
                                                                        'SETTING_MISMATCH')

                    [void]$CompareObject.Add($_diff)

                }

                elseif ($_diff.SideIndicator -eq $SideIndicator.Child)
                {

                    $_diff = New-Object HPOneView.Library.CompareObject('ActiveQosConfig', 
                                                                        $SideIndicator.Child, 
                                                                        $_LogicalInterconnectGroup.qosConfiguration.activeQosConfig.configType, 
                                                                        $_LogicalInterconnect.qosConfiguration.activeQosConfig.configType, 
                                                                        $_LogicalInterconnectGroup.name,
                                                                        $_LogicalInterconnect.name,
                                                                        'SETTING_MISMATCH')

                    [void]$CompareObject.Add($_diff)
                    
                }

            }

        }
        
        function GetUplinkSets ($_LI, $_LIG) 
        {

            'Processing Uplink Set objects' | Write-Verbose #-Verbose
            'LI: {0} [{1}]' -f $_LI.name,$_LI.uri | Write-Verbose #-Verbose
            'LIG: {0}' -f $_LIG.name | Write-Verbose #-Verbose
            'Number of LIG Uplink Sets: {0}' -f $_LIG.uplinkSets.count | Write-Verbose #-Verbose
            'Number of matched Uplink Sets to LI: {0}' -f ($UplinkSets | Where-Object logicalInterconnectUri -eq $_LI.uri).Count | Write-Verbose #-Verbose
            
            if (($UplinkSets | Where-Object logicalInterconnectUri -eq $_LI.uri).Count -gt $_LIG.uplinkSets.Count)
            {

                'Number of Unmatched Uplink Sets to LI: {0}' -f (($UplinkSets | Where-Object logicalInterconnectUri -eq $_LI.uri).Count - $_LIG.uplinkSets.Count) | Write-Verbose #-Verbose

            }

            else
            {

                'Number of Unmatched Uplink Sets to LIG: {0}' -f ($_LIG.uplinkSets.Count - ($UplinkSets | Where-Object logicalInterconnectUri -eq $_LI.uri).Count) | Write-Verbose #-Verbose
            
            }
            
            $myLUs = [System.Collections.ArrayList]::new()
            
            'Processing LIG policy for undefined Uplink Sets within LI.' -f $_LigUplinkSet.name | Write-Verbose #-Verbose
            
            ForEach ($_LigUplinkSet in $_LIG.uplinkSets)
            {

                'Looking for unprovisioned LIG Uplink Set: {0}' -f $_LigUplinkSet.name | Write-Verbose #-Verbose

                if (($UplinkSets | Where-Object logicalInterconnectUri -eq $_LI.uri).name -notcontains $_LigUplinkSet.name)
                {

                    '{0} is not provisioned within LI.' -f $_LigUplinkSet.name | Write-Verbose #-Verbose

                    $MissingUplinkSet = NewObject -liUplinkSetObject
                    $MissingUplinkSet.name = "Missing"
                    Add-Member -InputObject $MissingUplinkSet -NotePropertyName UplinkSetGroup -NotePropertyValue $null -Force
                    Add-Member -InputObject $MissingUplinkSet -NotePropertyName LogicalInterconnectName -NotePropertyValue $_LI.name
                    Add-Member -InputObject $MissingUplinkSet.UplinkSetGroup -NotePropertyName LogicalInterconnectGroupName -NotePropertyValue $_LIG.name                   
                    [void]$myLUs.Add($MissingUplinkSet)
                    
                }

            }

            # Inject LIG Uplink Set object into LI for further matching later
            foreach ($lu in ($UplinkSets | Where-Object logicalInterconnectUri -eq $_LI.uri)) 
            {

                "Match on: {0}" -f $lu.logicalInterconnectUri | Write-Verbose #-Verbose

                Add-Member -InputObject $lu -NotePropertyName UplinkSetGroup -NotePropertyValue $null -Force
                Add-Member -InputObject $lu -NotePropertyName LogicalInterconnectName -NotePropertyValue $_LI.name
                $lu.UplinkSetGroup = $_LIG.uplinkSets | Where-Object name -eq $lu.name
                
                # If LIG Uplink Set doesn't exist, add placebo
                if ($null -eq $lu.UplinkSetGroup)
                {

                    'Uplink Set "{0}" is not defined in the LIG.' -f $_LigUplinkSet.name | Write-Verbose #-Verbose
                    
                    $MissingLIGUplinkSet = MissingUplinkSetFromLIG
                    $MissingLIGUplinkSet.UplinkSetGroup               = $_LigUplinkSet
                    $MissingLIGUplinkSet.LogicalInterconnectUri       = $_LI.uri
                    $MissingLIGUplinkSet.LogicalInterconnectName      = $_LI.name
                    $MissingLIGUplinkSet.LogicalInterconnectGroupName = $_Lig.name

                }

                else
                {

                    'Uplink Set "{0}" exists in both LI and LIG.' -f $_LigUplinkSet.name | Write-Verbose #-Verbose

                    Add-Member -InputObject $lu.UplinkSetGroup -NotePropertyName LogicalInterconnectGroupName -NotePropertyValue $_LIG.name

                }
                
                [void]$myLUs.Add($lu)

            }
            
            # Need to add a check here for when the LIG Uplink Set(s) differe from LI, not what matches from LI to global Uplink Sets
            return $myLUs
            
        }

        function GetPortName ($bay, $portNumber) 
        {
            
            'Getting name for port Bay: {0}; Port Number: {1}' -f $Bay, $PortNumber | Write-Verbose #-Verbose
            

            # This function uses the Interconnect map Group set up in CompareInterconnects
            $InterconnectMapEntry = $InterconnectMapTemplate | Where-Object bayNumber -eq $bay
            "InterconnectType: {0}" -f $InterconnectMapEntry | Write-Verbose #-Verbose

            $InterconnectModuleType = $InterconnectTypes | Where-Object uri -eq $InterconnectMapEntry.InterconnectTypeUri
            "Interconnect Module Type: {0}" -f $InterconnectModuleType | Write-Verbose #-Verbose

            "Uplink Port Name: {0}" -f ($InterconnectModuleType.portInfos | Where-Object portNumber -eq $PortNumber).portName | Write-Verbose #-Verbose
            Return ($InterconnectModuleType.portInfos | Where-Object portNumber -eq $PortNumber).portName

        }

        function CompareNetworks ($lu, $lut) 
        {

            'Examining Networks associated with Uplink Set "{0}"' -f $lu.name | Write-Verbose #-Verbose

            switch ($lu.networkType)
            {

                'FibreChannel'
                {

                    'Processing Fibre Channel Uplink Set' | Write-Verbose #-Verbose

                    if ($lu.fcNetworkUris.Count -ne $lut.networkUris.Count) 
                    {

                        '{0} currently has {1} FC networks, Group has {2}' -f $lu.name, $lu.fcNetworkUris.Count, $lut.networkUris.Count | Write-Verbose
                    
                    }
                    
                    if ($null -eq $lut.fcNetworkUris) 
                    {

                        $diff = [PSCustomObject]@{InputObject = $lu.fcNetworkUris; SideIndicator = "=>"}

                    }

                    elseif ($null -eq $lu.fcNetworkUris) 
                    {

                        $diff = [PSCustomObject]@{InputObject = $lut.fcNetworkUris; SideIndicator = "<="}

                    }

                    else
                    {

                        $diff = Compare-Object -ReferenceObject $lu.fcNetworkUris -DifferenceObject $lut.networkUris

                    }

                }

                'Ethernet'
                {

                    'Processing Ethernet Uplink Set' | Write-Verbose #-Verbose

                    if ($lu.networkUris.Count -ne $lut.networkUris.Count) 
                    {
                        
                        '{0} currently has {1} Ethernet networks, Group has {2}' -f $lu.name, $lu.networkUris.Count, $lut.networkUris.Count | Write-Verbose
                        
                    }
                    
                    if ($null -eq $lut.networkUris) 
                    {

                        $diff = [PSCustomObject]@{InputObject = $lu.networkUris; SideIndicator = "=>"}

                    }

                    elseif ($null -eq $lu.networkUris) 
                    {

                        $diff = [PSCustomObject]@{InputObject = $lut.networkUris; SideIndicator = "<="}

                    }

                    else
                    {

                        $diff = Compare-Object -ReferenceObject $lu.networkUris -DifferenceObject $lut.networkUris

                    }                   

                }

            }
            
            foreach ($d in $diff) 
            {

                ForEach ($_uri in $d.InputObject)
                {

                    Try
                    {
                    
                        $net = Send-HPOVRequest -Uri $_uri -Hostname $ApplianceConnection
                    
                    }
                    
                    Catch
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }

                    if ($d.SideIndicator -eq $SideIndicator.Child)
                    {
    
                        $_diff = New-Object HPOneView.Library.CompareObject($lu.name, 
                                                                            $SideIndicator.Parent, 
                                                                            $net.name,
                                                                            $null, 
                                                                            $lut.LogicalInterconnectGroupName,
                                                                            $lu.LogicalInterconnectName,
                                                                            'MISSING_NETWORK')
    
                        [void]$CompareObject.Add($_diff)
    
                        '{0} is currently missing network {1} VLAN {2}' -f $lu.name, $net.name, $net.vlanId | Write-Verbose
    
                    } 
                    
                    else 
                    {
    
                        $_diff = New-Object HPOneView.Library.CompareObject($lu.name, 
                                                                            $SideIndicator.Child, 
                                                                            $null,
                                                                            $net.name, 
                                                                            $lut.LogicalInterconnectGroupName,
                                                                            $lu.LogicalInterconnectName,
                                                                            'EXTRA_NETWORK')
                        [void]$CompareObject.Add($_diff)
    
                        '{0} currently has extra network {1} VLAN {2}' -f $lu.name, $net.name, $net.vlanId | Write-Verbose
    
                    }

                }

            }

        }

        function CompareLocalNetworks ($li, $lig) 
        {

            'Examining Internal Networks' | Write-Verbose #-Verbose

            if ($li.internalNetworkUris.Count -ne $lig.internalNetworkUris.Count) 
            {
                
                '{0} currently has {1} Internal Ethernet networks, Group has {2}' -f $li.name, $li.internalNetworkUris.Count, $lig.internalNetworkUris.Count | Write-Verbose
                
            }

            $diff = Compare-Object -ReferenceObject $lig.internalNetworkUris -DifferenceObject $li.internalNetworkUris

            
            foreach ($d in $diff) 
            {

                Try
                {
                
                    $net = Send-HPOVRequest $d.InputObject
                
                }
                
                Catch
                {
                
                    PSCmdlet.ThrowTerminatingError($_)
                
                }
                
                if ($d.SideIndicator -eq $SideIndicator.Parent) 
                {

                    $_diff = New-Object HPOneView.Library.CompareObject('InternalNetworks', 
                                                                        $SideIndicator.Child, 
                                                                        $net.name,
                                                                        $null,                                                                         
                                                                        $lig.name,
                                                                        $li.name,
                                                                        'MISSING_NETWORK')

                    [void]$CompareObject.Add($_diff)

                    '{0} is currently missing internal network {1} VLAN {2}' -f $li.name, $net.name, $net.vlanId | Write-Verbose

                } 
                
                else 
                {

                    $_diff = New-Object HPOneView.Library.CompareObject('InternalNetworks', 
                                                                        $SideIndicator.Parent, 
                                                                        $null,
                                                                        $net.name, 
                                                                        $lig.name,
                                                                        $li.name,
                                                                        'EXTRA_NETWORK')
                    [void]$CompareObject.Add($_diff)

                    '{0} currently has extra network {1} VLAN {2}' -f $li.name, $net.name, $net.vlanId | Write-Verbose

                }

            }

        }

        function ComparePorts ($lu, $lut) 
        {

            "Comparing ports" | Write-Verbose #-Verbose

            "Uplink Set Port count: {0}" -f $lu.portConfigInfos.Count | Write-Verbose #-Verbose
            "LIG Uplink Set Port count: {0}" -f $lut.logicalPortConfigInfos.Count | Write-Verbose #-Verbose

            if ($lu.portConfigInfos.Count -ne $lut.logicalPortConfigInfos.Count) 
            {

                '{0} currently has {1} ports, Group has {2}' -f $lu.name, $lu.portConfigInfos.Count, $lut.logicalPortConfigInfos.Count | Write-Verbose

            }

            #Build array of LU ports
            $luPorts = [System.Collections.ArrayList]::new()
            $lutPorts = [System.Collections.ArrayList]::new()

            # Process LIG Uplink Set Uplink Ports
            foreach ($upPorts in $lut.logicalPortConfigInfos) 
            {

                $Port = [PSCustomObject]@{ type = 'lut.portConfigInfos';bayNumber = $null; portNumber = $null; portName = $null; Speed = $null }

                foreach ($loc in $upPorts.logicalLocation.locationEntries) 
                {

                    $Port.Speed = $upPorts.desiredSpeed

                    if ($loc.type -eq "BAY") { $Port.bayNumber = $loc.relativeValue }

                    if ($loc.type -eq "PORT") { $Port.portNumber = $loc.relativeValue }

                }

                $Port.portName = GetPortName $Port.bayNumber $Port.portNumber

                [void]$lutPorts.Add($Port)

            }

            # // TODO: Logic here is incorrect and broken. Not identifying the corect ports.
            # Process LI Uplink Set Uplink Ports
            foreach ($upPorts in $lu.portConfigInfos) 
            {

                $Port = [PSCustomObject]@{ type = 'lu.portConfigInfos';bayNumber = $null; portNumber = $null; portName = $null; Speed = $null }

                foreach ($loc in $upPorts.Location.locationEntries) 
                {

                    $Port.Speed = $upPorts.desiredSpeed

                    if ($loc.type -eq "BAY") { $Port.bayNumber = $loc.Value }

                    if ($loc.type -eq "PORT") { $Port.portName = $loc.Value }

                }

                [void]$luPorts.Add($Port)

            }

            $PortLocationDiff = Compare-Object -ReferenceObject $lutPorts -DifferenceObject $luPorts -Property bayNumber, portName

            'PortLocationDiff Object: {0}' -f ($PortLocationDiff | Out-String) | Write-Verbose #-Verbose

            foreach ($d in $PortLocationDiff) 
            {

                $Property = 'Bay{0}:{1}' -f $d.bayNumber, $d.portName

                if ($d.SideIndicator -eq $SideIndicator.Parent) 
                {

                    $_diff = New-Object HPOneView.Library.CompareObject($lu.name, 
                                                                        $SideIndicator.Child, 
                                                                        $Property, 
                                                                        $null, 
                                                                        $lut.LogicalInterconnectGroupName,
                                                                        $lu.LogicalInterconnectName,
                                                                        'MISSING_UPLINKPORT')
                    
                    [void]$CompareObject.Add($_diff)
                    
                    '{0} is currently missing port bay {1} port ' -f $lu.name, $d.bayNumber, $d.portName | Write-Verbose
                
                } 
                
                elseif ($d.SideIndicator -eq $SideIndicator.Child)  
                {

                    $_diff = New-Object HPOneView.Library.CompareObject($lu.name, 
                                                                        $SideIndicator.Parent, 
                                                                        $null, 
                                                                        $Property, 
                                                                        $lut.LogicalInterconnectGroupName,
                                                                        $lu.LogicalInterconnectName,
                                                                        'ADDITIONAL_UPLINKPORT')
                    
                    [void]$CompareObject.Add($_diff)
                    
                    '{0} currently has extra port on bay {1} port {2}' -f $lu.name, $d.bayNumber, $d.portName | Write-Verbose

                }

            }

            $PortSpeedDiff = Compare-Object -ReferenceObject $lutPorts -DifferenceObject $luPorts -Property Speed -PassThru

            'PortSpeedDiff Object: {0}' -f ($PortSpeedDiff | Out-String) | Write-Verbose #-Verbose

            foreach ($d in $PortSpeedDiff) 
            {

                if ($luPorts | Where-Object { $_.bayNumber -eq $d.bayNumber -and $_.portName -eq $d.portName} )
                {

                    $Property = '{0}:Bay{1}:{2}' -f $lut.name,$d.bayNumber, $d.portName

                    'luPort Object: {0}' -f (($luPorts | Where-Object { $_.bayNumber -eq $d.bayNumber -and $_.portName -eq $d.portName}) | Out-String) | Write-Verbose #-Verbose

                    if ($d.SideIndicator -eq '=>')
                    {

                        $ParentValue = $null

                        if ($lutPorts | Where-Object { $_.bayNumber -eq $d.bayNumber -and $_.portName -eq $d.portName})
                        {

                            $ParentValue = '{0}' -f $GetUplinkSetPortSpeeds[($lutPorts | Where-Object { $_.bayNumber -eq $d.bayNumber -and $_.portName -eq $d.portName}).Speed]

                        }
                        
                        $ChildValue = '{0}' -f $GetUplinkSetPortSpeeds[$d.Speed]

                    }
                
                    elseif ($d.SideIndicator -eq '<=')
                    {

                        $ChildValue = $null
                        
                        if ($luPorts | Where-Object { $_.bayNumber -eq $d.bayNumber -and $_.portName -eq $d.portName})
                        {

                            $ChildValue = '{0}' -f $GetUplinkSetPortSpeeds[($luPorts | Where-Object { $_.bayNumber -eq $d.bayNumber -and $_.portName -eq $d.portName}).Speed]

                        }

                        $ParentValue = '{0}' -f $GetUplinkSetPortSpeeds[$d.Speed]                        

                    }

                    $_diff = New-Object HPOneView.Library.CompareObject($Property, 
                                                                        $SideIndicator.NotEqual, 
                                                                        $ParentValue, 
                                                                        $ChildValue, 
                                                                        $lut.LogicalInterconnectGroupName,
                                                                        $lu.LogicalInterconnectName,
                                                                        'LINKSPEED_MISMATCH')
                    
                    [void]$CompareObject.Add($_diff)

                    '{0} Uplink Port {1}:{2} has different link speed {3} than Group {4}' -f $lut.name, $d.bayNumber, $d.portName, $ParentValue, $ChildValue | Write-Verbose

                }

            }

        }

        function CompareUplinksWithGroup ($lu) 
        {

            $lut = $lu.UplinkSetGroup

            if (! $lut) 
            {
                
                '"{0}" Uplink Set has no matching LIG Uplink Set. Skipping.' -f $lu.name | Write-Verbose
                
            }

            if ($lu.name -eq 'missing')
            {

                '"{0}" Uplink Set within Logical Interconnect Group "{1}" is not provisioned or missing from Logical Interconnect "{2}"' -f $lut.name, $lu.LogicalInterconnectGroupName, $lu.LogicalInterconnectName | Write-Verbose

                $_diff = New-Object HPOneView.Library.CompareObject('UplinkSets',
                                                                    $SideIndicator.Child, 
                                                                    $lut.name, 
                                                                    $null, 
                                                                    $lu.LogicalInterconnectGroupName,
                                                                    $lu.LogicalInterconnectName,
                                                                    'MISSING_UPLINKSET')
                
                [void]$CompareObject.Add($_diff)

            }

            else 
            {

                'Comparing {0} Uplink Set with Group' -f $lu.name | Write-Verbose #-Verbose

                'LU: {0}' -f $lu | Write-Verbose #-Verbose
                'LUT: {0}' -f $lut | Write-Verbose #-Verbose

                if ($lu.networkType -ne $lut.networkType) 
                {
                    
                    $_diff = New-Object HPOneView.Library.CompareObject(($lu.name + ':networkType'), 
                                                                        $SideIndicator.Parent, 
                                                                        $lut.networkType, 
                                                                        $lu.networkType,
                                                                        $lut.LogicalInterconnectGroupName,
                                                                        $lu.LogicalInterconnectName,
                                                                        'NETWORKTYPE_MISMATCH')
                    
                    [void]$CompareObject.Add($_diff)
                    
                    '"{0}" current Type "{1}" differs from Group Type "{2}"' -f $lu.name, $lu.networkType, $lut.networkType | Write-Verbose
                
                }

                if ($lu.connectionMode -ne $lut.mode) 
                {

                    $LutPort = $null
                    $LuPort = $null

                    if ($lut.LogicalInterconnectGroupName)
                    {

                        $LutPort = $lut.LogicalInterconnectGroupName + ":" + $lut.name

                    }
                    
                    if ($lu.LogicalInterconnectName)
                    {

                        $LuPort = $lu.LogicalInterconnectName + ":" + $lu.name

                    }
                    
                    $_diff = New-Object HPOneView.Library.CompareObject('connectionMode', 
                                                                        $SideIndicator.Parent, 
                                                                        $lut.mode, 
                                                                        $lu.connectionMode, 
                                                                        $LutPort,
                                                                        $LuPort,
                                                                        'CONNECTIONMODE_MISMATCH')

                    [void]$CompareObject.Add($_diff)

                    '"{0}" current Connection Mode "{1}" differs from Group Connection Mode "{2}"' -f $lu.name, $lu.connectionMode, $lut.mode | Write-Verbose
                    
                }

                if ( $lut.mode -ne 'Auto' -or $lu.connectionMode -ne 'Auto')
                {

                    $LutPrimaryPort = [PSCustomObject]@{ bayNumber = $null; portNumber = $null; portName = $null; Speed = $null }
                    $LutPrimaryPort.bayNumber = ($lut.primaryPort.locationEntries | Where-Object { $_.type -eq 'Bay' } ).relativeValue
                    $LutPrimaryPort.portNumber = ($lut.primaryPort.locationEntries | Where-Object { $_.type -eq 'Port' } ).relativeValue
                    $LutPrimaryPort.portName = GetPortName $LutPrimaryPort.bayNumber $LutPrimaryPort.portNumber

                    $LuPrimaryPort = [PSCustomObject]@{ bayNumber = $null; portNumber = $null; portName = $null; Speed = $null }
                    $LuPrimaryPort.bayNumber = ($lu.primaryPortLocation.locationEntries | Where-Object type -eq 'Bay').value
                    $LuPrimaryPort.portName = ($lu.primaryPortLocation.locationEntries | Where-Object type -eq 'Port').value

                    $PrimaryPortDiff = Compare-Object -ReferenceObject $LutPrimaryPort -DifferenceObject $LuPrimaryPort -Property portName -PassThru

                    'PrimaryPortDiff Object: {0}' -f ($PrimaryPortDiff | Out-String) | Write-Verbose #-Verbose

                    if ($PrimaryPortDiff)
                    {

                        $_SideIndicator = '<=>'

                        $_ParentPrimaryPort = ('BAY{0}:{1}' -f $LutPrimaryPort.bayNumber, $LutPrimaryPort.portName)
                        $_ChildPrimaryPort = ('BAY{0}:{1}' -f $LuPrimaryPort.bayNumber, $LuPrimaryPort.portName)

                        if (! $LuPrimaryPort.portName)
                        {

                            $_SideIndicator = '<='
                            $_ChildPrimaryPort = $null

                        }

                        elseif (! $LutPrimaryPort.portName)
                        {

                            $_SideIndicator = '=>'
                            $_ParentPrimaryPort = $null

                        }

                        $_diff = New-Object HPOneView.Library.CompareObject('PrimaryPort',
                                                                            $_SideIndicator,
                                                                            $_ParentPrimaryPort,
                                                                            $_ChildPrimaryPort, 
                                                                            ($lut.LogicalInterconnectGroupName + ":" + $lut.name),
                                                                            ($lu.LogicalInterconnectName + ":" + $lu.name),
                                                                            'PRIMARYPORT_MISMATCH')

                        [void]$CompareObject.Add($_diff)

                        '"{0}" current Primary Port "{1}" differs from Group "{2}"' -f $lu.name, $_ChildPrimaryPort, $_ParentPrimaryPort | Write-Verbose                

                    }

                }


                if ($lu.nativeNetworkUri -ne $lut.nativeNetworkUri) 
                {

                    'LU NativeNetworkUri: {0}' -f $lu.nativeNetworkUri | Write-Verbose #-Verbose
                    'LUT NativeNetworkUri: {0}' -f $lut.nativeNetworkUri | Write-Verbose #-Verbose

                    $_SideIndicator = $SideIndicator.NotEqual

                    if ($lu.nativeNetworkUri) 
                    { 
                        
                        $luNativeNetwork = (Send-HPOVRequest $lu.nativeNetworkUri).name 
                    
                    }

                    else
                    {
                    
                        $luNativeNetwork = "None"
                        $_SideIndicator = $SideIndicator.Parent
                    
                    }

                    if ($lut.nativeNetworkUri) 
                    {

                        $lutNativeNetwork = (Send-HPOVRequest $lut.nativeNetworkUri).name

                    }

                    else
                    {
                    
                        $lutNativeNetwork = "None"
                        $_SideIndicator = $SideIndicator.Child
                    
                    }

                    $_diff = New-Object HPOneView.Library.CompareObject(($lu.name + ':nativeNetworkUri'), 
                                                                        $_SideIndicator,
                                                                        $lutNativeNetwork, 
                                                                        $luNativeNetwork, 
                                                                        $lut.LogicalInterconnectGroupName,
                                                                        $lu.LogicalInterconnectName,
                                                                        'NATIVENETWORK_MISMATCH')
                    
                    [void]$CompareObject.Add($_diff)
                    
                    '"{0}" current Native Network "{1}" differs from Group Native Network "{2}"' -f $lu.name, $luNativeNetwork, $lutNativeNetwork | Write-Verbose

                }

                CompareNetworks $lu $lut

                ComparePorts $lu $lut

            }

        }
        
        Function MissingUplinkSetFromLIG 
        {

            Return [PSCustomObject] @{

                Name                         = "missing";
                UplinkSetGroup               = $null;
                LogicalInterconnectUri       = $null;
                LogicalInterconnectName      = $null;
                LogicalInterconnectGroupName = $null

            }

        }

        ##################################################################
        # If InputObject is not a PSCustomObject, assume it is an Enclosure Name
        if ($InputObject -IsNot [System.Management.Automation.PSCustomObject])
        {

            Try
            {
            
                $InputObject = Get-HPOVEnclosure -Name $InputObject -ApplianceConnection $ApplianceConnection
            
            }
            
            Catch
            {
            
                PSCmdlet.ThrowTerminatingError($_)
            
            }    

        }

        "InputObject resource: {0} [{1}]" -f $InputObject.name, $InputObject.category | Write-Verbose

        # Loop through all ICM bays of the Enclosure object
        if ($InputObject.category -eq 'enclosures')
        {

            '{0} has {1} interconnect bays which are configured as {2} logical Interconnects' -f $InputObject.name, ($InputObject.interconnectBays | Where-Object interconnectUri).Count, $_LogicalInterconnectUris.Count | Write-Verbose

            $UniqueLIUris = $InputObject.interconnectBays | Select-Object -Property logicalInterconnectUri -Unique | Where-Object { $_.logicalInterconnectUri }  

            ForEach ($_uri in $UniqueLIUris.logicalInterconnectUri)
            {

                'Processing LI URI: {0}' -f $_uri | Write-Verbose

                Try
                {
                
                    $_LIObject = Send-HPOVRequest -Uri $_uri -Hostname $ApplianceConnection
                    $_LigObject = Send-HPOVRequest -Uri $_LIObject.logicalInterconnectGroupUri -Hostname $ApplianceConnection
                    
                    $_LIObject | Add-Member -NotePropertyName LogicalInterconnectGroup -NotePropertyValue $_LigObject -Force
                    [void]$_LogicalInterconnects.Add($_LIObject)
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

            }

        }

        elseif ($InputObject.category -eq 'logical-enclosures')
        {

            # Is this even right? There is a logicalInterconnectUris property. Should that be used, even for C-Class and Synergy?
            ForEach ($_LogicalInterconnectUri in ($InputObject.logicalInterconnectUris | Where-Object { -not $_.StartsWith($SasLogicalInterconnectsUri) }))
            {

                Try
                {
                
                    $_LogicalInterconnect = Send-HPOVRequest -Uri $_LogicalInterconnectUri -Hostname $ApplianceConnection
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }

                '{0} has {1} interconnect bays which are configured within the Logical Interconnect' -f $InputObject.name, $InputObject.interconnects.Count | Write-Verbose

                Try
                {
                
                    $_LigObject = Send-HPOVRequest -Uri $_LogicalInterconnect.logicalInterconnectGroupUri -Hostname $ApplianceConnection
                    
                    $_LogicalInterconnect | Add-Member -NotePropertyName LogicalInterconnectGroup -NotePropertyValue $_LigObject -Force
                    
                    [void]$_LogicalInterconnects.Add($_LogicalInterconnect)
                
                }
                
                Catch
                {
                
                    $PSCmdlet.ThrowTerminatingError($_)
                
                }                

            }

        }

        elseif ($InputObject.category -eq 'logical-interconnects')
        {

            '{0} has {1} interconnect bays which are configured within the Logical Interconnect' -f $InputObject.name, $InputObject.interconnects.Count | Write-Verbose

            Try
            {
            
                $_LIObject = $InputObject.PSObject.Copy()
                $_LigObject = Send-HPOVRequest -Uri $_LIObject.logicalInterconnectGroupUri -Hostname $ApplianceConnection
                
                $_LIObject | Add-Member -NotePropertyName LogicalInterconnectGroup -NotePropertyValue $_LigObject -Force
                [void]$_LogicalInterconnects.Add($_LIObject)
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

        }

        else
        {

            Throw "Unsupported InputObject. Only Enclosure or Logical Interconnect resources are permitted."

        }

        # Start the compare process
        foreach ($_LI in $_LogicalInterconnects) 
        {

            "Logical Interconnect '{0}' has '{1}' Interconnects and is based on Group '{2}'" -f $_LI.name, $_LogicalInterconnect.Interconnects.Count, $_LI.LogicalInterconnectGroup.name | Write-Verbose

            # Compare Expected and Actual interconnect map
            CompareInterconnects $_LI $_LI.LogicalInterconnectGroup

            # Collect Uplink Sets from both LIG and LI
            $lus = GetUplinkSets $_LI $_LI.LogicalInterconnectGroup

            foreach ($lu in $lus) 
            {

                # Compare Uplink Sets between LI and LIG, with LIG Uplink Set within LI Uplink Set (LU)
                CompareUplinksWithGroup $lu

            }

            # Compare Local Networks
            CompareLocalNetworks $_LI $_LI.LogicalInterconnectGroup
            
        }

        # Display final object
        $CompareObject

    }

    End
    {

        'Done.' | Write-Verbose

    }

}

# // TODO: Compare Enclosure with EG
function Compare-Enclosure
{


}

function Show-HPOVLogicalInterconnectMacTable 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "MACAddress")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Pipeline")]
        [ValidateNotNullorEmpty()]
        [Alias ("name","li","LogicalInterconnect")]
        [object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Pipeline")]
        [ValidateNotNullorEmpty()]
        [String]$network,

        [Parameter (Mandatory = $false, ParameterSetName = "MACAddress")]
        [validatescript({if (-not $MacAddressPattern.Match($_).Success) { throw "The input value '$_' does not match 'aa:bb:cc:dd:ee:ff'. Please correct the value and try again."}})]
        [Alias ("mac")]
        [String]$MacAddress,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "MACAddress")]
        [Parameter (Mandatory = $false, ParameterSetName = "Pipeline")]
        [Alias ("x", "ExportFile")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$Export,
        
        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "MACAddress")]
        [Parameter (Mandatory = $false, ParameterSetName = "Pipeline", ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        if ($PSCmdlet.ParameterSetName -ne 'Pipeline')
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $MacTables = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        "[{0}] Logical Interconnect via PipeLine: $PipelineInput" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($InputObject))
        {

            "[{0}] No Logical Interconnects provided via Parameter. Getting all LI resources." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $InputObject = Get-HPOVLogicalInterconnect

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        ForEach ($li in $InputObject) 
        {

            if ($li -is [PSCustomObject] -and $li.category -eq "logical-interconnects") 
            {

                "[{0}] Logical Interconnect object provided: $($li.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Logical Interconnect object URI: $($li.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $uri = $li.uri +"/forwarding-information-base"

            }

            else 
            {

                # Unsupported type
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'LogicalInterconnect' -TargetType $li.GetType().Name -Message "The Parameter -LogicalInterconnect contains an invalid Parameter value type, '$($li.gettype().fullname)' is not supported. Only [PSCustomObject] type is allowed."
                $PSCmdlet.WriteError($ErrorRecord)

            }

            # Filter the request for a specific Network
            if ($Network) 
            {
                
                "[{0}] Filtering for '$Network' Network Resource" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $_Network = Get-HPOVNetwork $network -ApplianceConnection $li.ApplianceConnection.Name

                $_internalVlanId = $_Nework.internalVlanId

                $uri += "?filter=internalVlan=$_internalVlanId"

                "[{0}] Processing $uri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $resp = (Send-HPOVRequest $uri -Hostname $li.ApplianceConnection.Name).members

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                

            }

            elseif ($MacAddress) 
            {

                "[{0}] Filtering for MAC Address '$MacAddress'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $uri += "?filter=macAddress='$MacAddress'"

                "[{0}] Processing $uri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $resp = (Send-HPOVRequest $uri -Hostname $li.ApplianceConnection.Name).members

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

            else 
            {

                "[{0}] Generating '{1}' mactable file." -f $MyInvocation.InvocationName.ToString().ToUpper(), $uri | Write-Verbose

                Try
                {

                    #$MacTableFile = (Send-HPOVRequest -Uri $uri -Metho POST -Hostname $li.ApplianceConnection.Name).members
                    $MacTableFile = Send-HPOVRequest -Uri $uri -Metho POST -Hostname $li.ApplianceConnection.Name

                    # "[{0}] MacTable Contents: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($MacTableFile ) | Write-Verbose

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                

                if ("Success","Completed" -match $MacTableFile.state -and $MacTableFile.fileSize -gt 0 -and -not([System.String]::IsNullOrWhiteSpace($MacTableFile))) 
                {

                    "[{0}] Processing '{1}' mactable file." -f $MyInvocation.InvocationName.ToString().ToUpper(), $MacTableFile.uri | Write-Verbose

                    Try
                    {

                        $resp = Download-MacTable $MacTableFile

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ([System.String]::IsNullOrWhiteSpace($MacTableFile))
                {

                    $Message = 'The results returned are null. This Cmdlet is not supported with the HPE OneView DCS appliance.'
                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidInterconnectFibDataInfo InvalidOperation 'InputObject' -Message $Message
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                else 
                {

                    "[{0}] Results are likely null. Will not generate an error and return null value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }


            }

            if ($resp.fileSize -gt 0)
            {
            $resp | ForEach-Object {

                "[{0}] Adding $($_.address) to collection" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [void]$MacTables.Add($_)
                } 

            } 

        }

    }

    End 
    {

        if ($list) 
        {
            
            "[{0}] Displaying formatted table." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($name -or $MacAddress) 
            {

                $m = @{Expression={($_.interconnectName -split ",")[0]};Label="Enclosure"},
                     @{Expression={($_.interconnectName -split ",")[1]};Label="Interconnect"},                 
                     @{Expression={$_.networkInterface};Label="Interface"},
                     @{Expression={$_.macAddress};Label="Address"},
                     @{Expression={$_.entryType};Label="Type"},
                     @{Expression={$_.networkName};Label="Network"},
                     @{Expression={$_.externalVlan};Label="VLAN"}

            }

            else 
            {

                $m = @{Expression={$_.Enclosure};Label="Enclosure"},
                     @{Expression={$_.Interconnect};Label="Interconnect"},
                     @{Expression={$_.Interface};Label="Interface"},
                     @{Expression={$_.address};Label="Address"},
                     @{Expression={$_.type};Label="Type"},
                     @{Expression={$_.network};Label="Network"},
                     @{Expression={$_.extVlan};Label="VLAN"},
                     @{Expression={$_.LAGPorts};Label="LAG Ports"}

            }

            $MacTables | Sort-Object "Enclosure","Interconnect",macAddress | format-table $m -autosize

        }

        elseif ($PSBoundParameters['Export']) 
        {

            "[{0}] Exporting to CSV file: $Export" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $MacTables | Sort-Object Enclosure,Interconnect,macAddress | Export-CSV $Export -NoTypeInformation

        }
        else 
        {

            "[{0}] Displaying results." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $MacTables | Sort-Object Enclosure,Interconnect,macAddress

        }
        
        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Done. {0} mac table entry(ies) found." -f $MacTables.Count | Write-Verbose

    }

}

function Download-MacTable 
{
    
    <#
        .SYNOPSIS
        Download Logical Interconnect MAC Table CSV.
 
        .DESCRIPTION
        This internal helper function will download the MAC Table CSV from a provided Logical Interconnect, parse it and return an array of MAC Table entries.
 
        .Parameter Uri
        [System.String] URI of Logical Interconnect.
 
        .Parameter Hostname
        [System.String] Hostname of Appliance
 
        .INPUTS
        None.
 
        .OUTPUTS
        System.Array
        Array of MAC Table entries.
 
        .LINK
        Get-HPOVLogicalInterconnect
 
        .EXAMPLE
        PS C:\> $encl1li = Get-HPOVLogicalInterconnect Encl1-LI
        PS C:\> Download-MACTable $encl1li
 
        Get the Logical Interconnect 'Encl1-LI' and
                 
    #>


    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript( { if ($_.type -eq 'interconnect-fib-data-info')
                {
                    $true 
                }
                else
                {
                    throw "-URI must being with a '/rest/logical-interconnects/' in its value. Please correct the value and try again."
                } })]
        [Object]$InputObject

    ) 

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $enc = [System.Text.Encoding]::UTF8

    }
 
    Process
    {    

        "[{0}] Download URI: $($InputObject.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        [System.Net.httpWebRequest]$fileDownload = RestClient GET $InputObject.uri $InputObject.ApplianceConnection.Name

        $fileDownload.accept               = "application/zip,application/octet-stream,*/*"
        $fileDownload.Headers.Item("auth") = ($ConnectedSessions | Where-Object Name -eq $InputObject.ApplianceConnection.Name).SessionID

        $i = 0
        foreach ($h in $fileDownload.Headers) 
        { 
            
            "[{0}] Request Header $($i): $($h) = $($fileDownload.Headers[$i])" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $i++
        
        }
        
        Try
        {

            "[{0}] Request: GET {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $fileDownload.RequestUri.AbsolutePath | Write-Verbose
            
            # Get response
            "[{0}] Getting response" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            [Net.httpWebResponse]$rs = $fileDownload.GetResponse()

            # Display the response status if verbose output is requested
            "[{0}] Response Status: $([Int]$rs.StatusCode) $($rs.StatusDescription)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $i = 0
            foreach ($h in $rs.Headers) 
            { 
                
                "[{0}] Response Header $($i): $($h) = $($rs.Headers[$i])" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $i++ 
            
            }

            # Request is a redirect to download file contained in the response headers
            $fileName = ($rs.headers["Content-Disposition"].SubString(21)) -replace '"', $null

            "[{0}] Filename: $($fileName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                                
            "[{0}] Filesize: $($rs.ContentLength)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $responseStream = $rs.GetResponseStream()

            # Define buffer and buffer size
            [Int] $bufferSize = ($rs.ContentLength*1024)
            [byte[]]$Buffer   = New-Object byte[] ($rs.ContentLength*1024)
            [Int] $bytesRead  = 0

            # This is used to keep track of the file upload progress.
            $totalBytesToRead = $rs.ContentLength
            $numBytesRead     = 0
            $numBytesWrote    = 0

            # Read from stream
            "[{0}] Reading Hand decompressing ttpWebRequest file stream." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            $gzipstream = New-Object IO.Compression.GZipStream($responseStream, [IO.Compression.CompressionMode]::Decompress)

            $memoryStream = new-object -TypeName System.IO.MemoryStream

            $buffer = New-Object byte[](1024)
            
            $count = 0
            
            do
            {

                $count = $gzipstream.Read($buffer, 0, 1024)

                if ($count -gt 0)
                {

                    $memoryStream.Write($buffer, 0, $count)
                    
                }

            } While ($count -gt 0)

            $array = $memoryStream.ToArray()
            $GZipStream.Close()
            $memoryStream.Close()
            $responseStream.Close()
            $sb = [System.Text.Encoding]::UTF8.GetString($array).Split("`n")
            
        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Finally
        {

            # Clean up our work
            if ($responseStream)
            {
                $responseStream.Close() 
            }
            if ($rs)
            {
                $rs.Close() 
            }
            if ($sr)
            {
                $sr.Close(); $sr.Dispose() 
            }

        }

    }

    End 
    {

        "[{0}] Building string array in CSV format" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # $macTableArray = $sb.ToString() -split "`n"
        $header = "enclosure", "interconnect", "interface", "address", "type", "network", "extVLAN", "intVLAN", "serverProfile", "uplinkSet", "LAGPort1", "LAGPort2", "LAGPort3", "LAGPort4", "LAG Port5", "LAG Port6", "LAG Port7", "LAG Port8"
        $sb = $sb[1..($sb.count)]

        $e = @{Expression = {
             
                $lagport = $_
                1..8 | ForEach-Object { if ($lagport."LAGPort$($_)")
                    {
                        $lagport."LAGPort$($_)" 
                    } } 
                           
            }; name       = "LAGPorts"
        }

        $macTable = $sb | ConvertFrom-Csv -Header $header | Select-Object "enclosure", "interconnect", "interface", "address", "type", "network", "extVLAN", "intVLAN", "serverProfile", "uplinkSet", $e

        "[{0}] Returning results." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $macTable

    }

}

function Install-HPOVLogicalInterconnectFirmware 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [Alias ('name','uri', 'li')]
        [ValidateNotNullorEmpty()]
        [object]$LogicalInterconnect,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateSet ('Update','Activate','Stage')]
        [String]$Method = "Update",

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateSet ('OddEven','Parallel','Serial')]
        [Alias ('Order','ActivateOrder')]
        [String]$EthernetActivateOrder = 'OddEven',

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Int]$EthernetActivateDelay = 5,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateSet ('OddEven','Parallel','Serial')]
        [String]$FCActivateOrder = 'Serial',

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Int]$FCActivateDelay = 5,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [Alias ('spp')]
        [object]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($LogicalInterconnect))
        {

            $PipelineInput = $True

        }
        
        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $TaskCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if ($PipelineInput -or $LogicalInterconnect -is [PSCustomObject])
        {

            # Validate Logical Interconnect Object Type
            if (-not($LogicalInterconnect -is [PSCustomObject]) -and $LogicalInterconnect.category -ne 'local-interconnects') 
            {

                "[{0}] invalid LogicalInterconnect passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect | Write-Verbose

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'INSTALL-HPOVLOGICALINTERCONNECTFIRMWARE' -Message "The 'LogicalInterconnect' Parameter value '$($LogicalInterconnect)' is invalid. Please check the Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
            }

        }

        else
        {

            if ($null -eq $ApplianceConnection)
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message 'No Appliance Connection was provided. Please provide a valid ApplianceConnection Object.'
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

            "[{0}] Looking for Logical Interconnect '{1}' from Get-HPOVLogicalInterconnect." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect | Write-Verbose

            Try
            {
                
                $LogicalInterconnect = Get-HPOVLogicalInterconnect -Name $LogicalInterconnect -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        "[{0}] Validating Baseline input value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        switch ($Baseline.GetType().Name)
        {

            'String'
            {

                Try
                {

                    "[{0}] Firmware Baseline name passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

                    $FirmwareBaslineName = $Baseline.Clone()

                    $Baseline = Get-HPOVBaseline -name $Baseline -ApplianceConnection $LogicalInterconnect.ApplianceConnection.Name -ErrorAction SilentlyContinue

                    If (-not $_BaseLinePolicy)
                    {

                        $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            'PSCustomObject'
            {

                "[{0}] Firmware Baseline object passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] object name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.name | Write-Verbose
                "[{0}] object uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.uri | Write-Verbose
                "[{0}] object appliance connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.ApplianceConnection.Name | Write-Verbose
                "[{0}] object category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline.category | Write-Verbose

                if ($Baseline.category -ne 'firmware-drivers')
                {
                    
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException InvalidBaselineObject InvalidArgument 'Baseline' -TargetType 'PSObject' -Message "The Baseline provided in an invalid object. Baseline category value '$($Baseline.caetegory)', expected 'firmware-drivers'. Please check the Parameter value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                }

            }

        }

        $Staging    = $False
        $Activating = $False

        "[{0}] Processing '{1}' Logical Interconnect." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose

        $_Request = NewObject -LogicalInterconnectBaseline

        $_Request.command                 = $Method
        $_Request.ethernetActivationType  = [String]$EthernetActivateOrder
        $_Request.ethernetActivationDelay = [Int]$EthernetActivateDelay
        $_Request.fcActivationType        = [String]$FCActivateOrder
        $_Request.fcActivationDelay       = [Int]$FCActivateDelay
        $_Request.sppUri                  = $Baseline.uri
        $_Request.force                   = [Bool]$PSBoundParameters['Force']

        switch ($Method) 
        {

            {'Update', 'Stage' -match $_}
            { 

                "[{0}] '{1}' Method called." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Method | Write-Verbose
                
                $_Request.command = $Method
                
                
            }

            "Activate" 
            {

                "[{0}] 'Activate' Method called." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                "[{0}] Verifying '{1}' LI is in a Staged state." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose
                
                Try
                {

                    $_FirmwareStatus = Send-HPOVRequest ($LogicalInterconnect.uri + "/firmware") -Hostname $LogicalInterconnect.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Validate interconnect firmware update state
                switch ($_FirmwareStatus.state) 
                {
                     
                    'STAGED' 
                    { 
                        
                        "[{0}] '{1}' LI is in the proper '{2}' state." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name, $_FirmwareStatus.state | Write-Verbose

                        #$baselineObj = [pscustomobject] @{ uri = $_FirmwareStatus.sppUri }

                        $_Request.command = 'ACTIVATE'
                        $_Request.sppUri  = $_FirmwareStatus.sppUri

                    }
                        
                    'STAGING'
                     { 
                        
                        "[{0}] '{1}' is currently being staged with firmware. Please wait until the task completes." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose
                            
                        # Locate and return running task.
                        $_task = Get-HPOVTask -State Running -resource $LogicalInterconnect.name -ApplianceConnection $LogicalInterconnect.ApplianceConnection.Name

                        $_task | Where-Object { $_.taskStatus.StartsWith('Staging') } | ForEach-Object {

                            [void]$TaskCollection.Add($_)

                        }

                        # Flag to skip the command Processing IF block below
                        $Staging = $true
                            
                    }

                    'STAGING_FAILED' 
                    { 
                        
                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectState InvalidResult 'LogicalInterconnect' -Message "The $($LogicalInterconnect.name) Logical Interconnect is in an invalid state ($($_FirmwareStatus.state))in order to issue the Activate command."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                    }

                    'ACTIVATED' 
                    { 
                        
                        "[{0}] '{1}' is already activated." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose
                        
                        Write-Warning ("'{0}' is already activated." -f $LogicalInterconnect.name)
                        
                        Return 
                    
                    }

                    'ACTIVATING' 
                    {
                            
                        # Logical Interconnect is already Processing the Activate command.
                        "[{0}] '{1}' is already activating. Returning task resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose

                        # Flag to skip the command Processing IF block below
                        $activating = $True
                            
                        # Locate and return running task.
                        Try
                        {

                            $_task = Get-HPOVTask -State Running -resource $LogicalInterconnect.name -ApplianceConnection $LogicalInterconnect.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }                        

                        $_task | Where-Object { $_.taskStatus.StartsWith('Activating') } | ForEach-Object {

                            [void]$TaskCollection.Add($_)

                        }

                    }

                    'ACTIVATION_FAILED' 
                    { 
                        
                        "[{0}] '{1}' failed a prior activation request. LI is in a valid state to attempt Activation command." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose

                        #$baselineObj = [pscustomobject] @{ uri = $_FirmwareStatus.sppUri }

                        $_Request.command = 'ACTIVATE'
                        $_Request.sppUri  = $_FirmwareStatus.sppUri
                            
                    }

                    'PARTIALLY_ACTIVATED' 
                    { 
                        
                        "[{0}] '{1}' is Partially Activated. LI is in a valid state to attempt Activation command." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose
                        $baselineObj = [pscustomobject] @{ uri = $_FirmwareStatus.sppUri }
                        
                    }

                    'PARTIALLY_STAGED' 
                    {
                        
                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectState InvalidResult 'LogicalInterconnect' -Message "The $($LogicalInterconnect.name) Logical Interconnect is in an invalid state ($($_FirmwareStatus.state)) in order to issue the Activate command."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                    }

                    'UNINITIALIZED' 
                    { 
                        
                        <# Generate Error that firmware has not been staged #> 
                        $ErrorRecord = New-ErrorRecord InvalidOperationException NoStagedFirmwareFound ObjectNotFound 'LogicalInterconnect' -Message "No staged firmware found for '$($LogicalInterconnect.name)' Logical Interconnect. Use Install-HPOVLogicalInterconnectFirmware -method Stage to first stage the firmware before attempting to Activate."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                    }

                }
                
            }

        }

        $_uri = $LogicalInterconnect.uri + "/firmware"

        # Need to prompt user to update or activate firmware, which could cause an outage.
        if ($Method -eq 'Update' -and -not $Activating -and -not $Staging)
        {

            Write-Warning 'Module activation may cause a network outage if Activation Order is Parallel.'

            if ($PSCmdlet.ShouldProcess($LogicalInterconnect.name, 'update Interconnect modules')) 
            {

                "[{0}] User was prompted warning and accepted. Sending request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_taskResults = Send-HPOVRequest -method PUT -uri $_uri -body $_Request -Hostname $LogicalInterconnect.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                    
            }

            else 
            { 
                
                "[{0}] User was prompted and selected No, will not update {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose
            
            }

        }

        # User is staging firmware, no need to prompt.
        elseif (-not($Activating) -and (-not($Staging)))
        {

            "[{0}] Beginning to stage firmware to '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalInterconnect.name | Write-Verbose

            Try
            {

                $_taskResults = Send-HPOVRequest -method PUT -uri $_uri -body $_Request -Hostname $LogicalInterconnect.ApplianceConnection

            }

            Catch
            {

              $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if (-not($PSBoundParameters['Async']) -and $_taskResults)
        {

            Try
            {

                $_taskResults = Wait-HPOVTaskComplete $_taskResults -ApplianceConnection $_taskResults.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        [void]$TaskCollection.Add($_taskResults)

    }

    End 
    {

        "[{0}] Finished, returning results." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        return $TaskCollection

    }


}

function Show-HPOVPortStatistics 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "InterconnectPort")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Pipeline")]
        [Parameter (Mandatory = $false, ParameterSetName = "InterconnectPort")]
        [object]$Port,

        [Parameter (Mandatory, ParameterSetName = "InterconnectPort")]
        [object]$Interconnect,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Pipeline")]
        [Parameter (Mandatory = $false, ParameterSetName = "InterconnectPort")]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            "[{0}] Port object provided by pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PortStatsCol = [System.Collections.ArrayList]::new()
    
    }

    Process 
    {

        Switch ($PSCmdlet.ParameterSetName) 
        {

            "Pipeline" 
            {

                switch ($Port.GetType().Name)
                {

                    # Do not support String Port values via pipeline, so generate error
                    "String" 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.InterconnectPortResourceException InvalidInterconnectPortParameter InvalidArgument 'Port' -Message "The -Port Parameter only supports Objects via the pipeline. Please refer to the CMDLET help for proper pipeline syntax."

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  
                        
                    }

                    "PSCustomObject" 
                    {

                        "[{0}] Port Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Port.name, $Port.uri | Write-Verbose

                        # Validate the Port Object is type Port
                        if ($Port.category -ne "ports") 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.InterconnectPortResourceException InvalidInterconnectPortObject InvalidArgument 'Port' -TargetType "PSObject" -Message ("The object for the -Port Parameter is the wrong type: {0}. Expected category 'ports'. Please check the object provided and try again." -f $Port.category )
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                        Try
                        {

                            "[{0}] Getting Interconnect resource from Port Object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $_InterconnectUri = $Port.uri.SubString(0,$Port.uri.IndexOf('/ports/' + $Port.portId))

                            $Interconnect = Send-HPOVRequest $_InterconnectUri -ApplianceConnection $Port.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

            }

            "InterconnectPort" 
            { 

                switch ($Interconnect.GetType().Name)
                {

                    "String" 
                    {


                        "[{0}] Getting Interconnect object '$Interconnect'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $Interconnect = Get-HPOVInterconnect $Interconnect -ApplianceConnection $ApplianceConnection

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    "PSCustomObject" 
                    {

                        "[{0}] Interconnect Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Interconnect.name, $Interconnect.uri | Write-Verbose

                        # Validate the Port Object is type Port
                        if ($Interconnect.category -ne 'interconnects') 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.InterconnectPortResourceException InvalidInterconnectPortObject InvalidArgument 'Interconnect' -TargetType "PSObject" -Message ("The object for -Interconnect Parameter is the wrong resource category: {0}. Expected type 'interconnects'. Please check the object provided and try again." -f  $Interconnect.category)

                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                    }

                }

                if ($PSBoundParameters['Port'])
                {

                    if ($Port -is [String])
                    {

                        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Filtering for '{0}' within '{1}' Interconnect." -f $Port, $Interconnect.name | Write-Verbose 

                        $_originalport = $Port

                        $Port = $Interconnect.ports | Where-Object portName -like $Port

                        if (-not($Port)) 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.InterconnectPortResourceException InvalidInterconnectPort InvalidArgument 'Port' -Message ("The the port '{0}' was not found within '{1}'. Available ports within the interconnect are '{2}' Please check the port value and try again." -f $_originalport, $Interconnect.name, ($interconnect.ports.portName -join ",") )

                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                    }

                    elseif ($Port -is [PSCustomObject])
                    {

                        $_originalport = $Port.PSObject.Copy()

                        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Filtering for '{0}' within '{1}' Interconnect." -f $Port.name, $Interconnect.name | Write-Verbose 

                        $Port = $Interconnect.ports | Where-Object portName -like $Port.name

                        if (-not($Port)) 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.InterconnectPortResourceException InvalidInterconnectPort InvalidArgument 'Port' -TargetType 'PSObject' -Message ("The the port '{0}' was not found within '{1}'. Available ports within the interconnect are '{2}' Please check the port value and try again." -f $_originalport.name, $Interconnect.name, ($interconnect.ports.portName -join ",") )

                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                    }

                }

            }

        }

        Try
        {

            $_InterconnectStats = Send-HPOVRequest ($Interconnect.uri + "/statistics") -ApplianceConnection $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        $_InterconnectStats | ForEach-Object { $_.PSObject.TypeNames.Insert(0,"HPOneView.Networking.InterconnectStatistics") }

        if ($Port) 
        { 
            
            $_InterconnectStats.portStatistics = $_InterconnectStats.portStatistics | Where-Object { $port.portName -contains $_.portName } 
        
        }

        # Set the specific TypeNames value for Formats to handle
        foreach ($_PortObj in $Interconnect.ports) 
        {

            switch ($_PortObj.configPortTypes) 
            {

                {@("EnetFcoe","Ethernet") -match $_ } 
                {

                    $TypeName    = "HPOneView.Networking.PortStatistics.Ethernet"
                    $SubTypeName = "Ethernet"
                    Break

                }

                "FibreChannel" 
                {

                    $TypeName    = "HPOneView.Networking.PortStatistics.FibreChannel"
                    $SubTypeName = "FibreChannel"
                    Break

                }

            }

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] inserting '{0}' into '{1}' [{2}]" -f $TypeName, $_PortObj.name, ($_PortObj.configPortTypes -join ",") | Write-Verbose 

            ($_InterconnectStats.portStatistics | Where-Object portName -eq $_PortObj.portName ).PSObject.TypeNames.Insert(0,$TypeName)
            ($_InterconnectStats.portStatistics | Where-Object portName -eq $_PortObj.portName ) | Add-Member -NotePropertyName portConfigType -NotePropertyValue $SubTypeName -force
        }

        # Insert sampleInterval from the Interconnect itself. Otherwise, portStatistics doesn't contain the interval.
        $_InterconnectStats.portStatistics | ForEach-Object { Add-Member -InputObject $_ -NotePropertyName sampleInterval -NotePropertyValue $_InterconnectStats.moduleStatistics.portTelemetryPeriod -force }

        $_InterconnectStats.portStatistics | sort-Object portConfigType,portName | ForEach-Object {

            [void]$_PortStatsCol.Add($_)

        }

    }

    End 
    {

        Return $_PortStatsCol

    }

} 

function Reset-HPOVInterconnectNetOpPassword
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Default')]
        [Alias('Interconnect')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [SecureString]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            $PipelineInput = $True

        }

        Else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
    }

    Process
    {

        # Validate the resource is supported
        if ($SynergyVCEthModulePartNumbers -NotContains $InputObject.partnumber)
        {

            $Message = 'The provided interconnect resource is not a supported resource for this Cmdlet. Only HPE Synergy Ethernet Virtual Connect fabric modules are.'
            $ErrorRecord = New-ErrorRecord HPOneView.Networking.InterconnectResourceException UnsupportedResource InvalidOperation 'InputObject' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        $_PatchOp = NewObject -PatchOperation
        $_PatchOp.op    = 'replace'
        $_PatchOp.path  = '/netOpPasswd'
        $_PatchOp.value = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        Try
        {

            $_Resp = Send-HPOVRequest -Uri $InputObject.uri -Method PATCH -Body $_PatchOp -ApplianceConnection $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_Resp = $_Resp | Wait-HPOVTaskComplete

        }

        $_Resp

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVLogicalInterconnectGroup 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Pipeline')]
        [Alias('Resource')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('SAS','VC')]
        [String]$Type,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Pipeline')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$exportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            $PipelineInput = $True

        }

        Else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $LigCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject])
        {

            # Task Resource Object
            if ($InputObject.category -eq 'tasks')
            {

                "[{0}] Task Resource input object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($InputObject.taskState -eq 'Completed')
                {

                    Try
                    {

                        $_LigObject = Send-HPOVRequest $InputObject.associatedResource.resourceUri -Hostname $InputObject.ApplianceConnection.Name

                        $_LigObject | ForEach-Object { 
                
                            $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnectGroup')    

                            [void]$LigCollection.Add($_) 
                
                        }

                    }

                    Catch
                    {

                        "[{0}] API Error Caught: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_.Exception.Message | Write-Verbose

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Generate error
                else
                {

                    $InputObject

                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException TaskFailure InvalidOperation 'InputObject' -Message "The Task object provided by the pipeline did not complete successfully. Please validate the task object resource and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                }

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException LogicalInterconnectGroupNotFound ObjectNotFound 'InputObject' -Message "The Logical Interconnect Group associated with the pipeline input task object was not found on '$($InputObject.ApplianceConnection.Name)'. Please check the value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

            }

        }

        Else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                $_Query = [System.Collections.ArrayList]::new()

                # Handle default cause of AllResourcesInScope
                if ($Scope -eq 'AllResourcesInScope')
                {
    
                    "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                    $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active
    
                    # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                    if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                    {
    
                        $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                        "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                    }
    
                    # Process ApplianceConnection ActivePermissions collection
                    else
                    {
    
                        Try
                        {
    
                            $_ScopeQuery = Join-Scope $_Scopes
    
                        }
    
                        Catch
                        {
    
                            $PSCmdlet.ThrowTerminatingError($_)
    
                        }
    
                        [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                    }
    
                }
    
                elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
                {
    
                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                elseif ($Scope -eq 'AllResources')
                {
    
                    "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                else
                {
    
                    Try
                    {
    
                        $_ScopeQuery = Join-Scope $Scope
    
                    }
    
                    Catch
                    {
    
                        $PSCmdlet.ThrowTerminatingError($_)
    
                    }
    
                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                }

                if ($Name)
                {

                    if ($Name.Contains('*'))
                    {

                        [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                    }

                    else
                    {

                        [Void]$_Query.Add(("name:'{0}'" -f $Name))

                    }                
                    
                }

                if ($Label)
                {

                    [Void]$_Query.Add(("labels:'{0}'" -f $Label))

                }

                if (-not $PSBoundParameters['Type'] -and $_appliance.ApplianceType -ne 'Composer')
                {

                    $_Category = 'category=logical-interconnect-groups'

                }

                elseif (-not $PSBoundParameters['Type'] -and $_appliance.ApplianceType -eq 'Composer')
                {

                    $_Category = 'category=logical-interconnect-groups&category=sas-logical-interconnect-groups'

                }

                else
                {

                    $_Category = @()

                    switch ($Type)
                    {

                        'VC'
                        {

                            $_Category += 'category=logical-interconnect-groups'

                        }

                        'SAS'
                        {

                            $_Category += 'category=sas-logical-interconnect-groups'

                        }

                    }

                }

                # Build the final URI
                $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

                Try
                {

                    [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Generate non-terminating exception if the name wasn't found
                if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
                { 

                    "[{0}] Logical Interconnect Group '$name' resource not found. Generating error" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ExceptionMessage = "Specified Logical Interconnect Group '{0}' was not found on '{1}' appliance connection. Please check the name and try again." -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectGroupNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)  

                }

                ForEach ($_member in $_ResourcesFromIndexCol) 
                {

                    "[{0}] Processing '{1}' resource (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_member.Name, $_ResourcesFromIndexCol.Count | Write-Verbose

                    switch ($_member.category)
                    {

                        'logical-interconnect-groups'
                        {
                            
                            $_member.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnectGroup')    

                            [void]$LigCollection.Add($_member) 

                        }

                        'sas-logical-interconnect-groups'
                        {

                            $_member.PSObject.TypeNames.Insert(0,'HPOneView.Networking.SASLogicalInterconnectGroup')    

                            [void]$LigCollection.Add($_member) 

                        }

                    }

                }

            }        

        }

    }

    End 
    {

        "[{0}] Done. {1} logical interconnect group(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $LigCollection.count | Write-Verbose

        if ($exportFile)
        {
            
            $LigCollection | convertto-json -Depth 99 | Set-Content -Path $exportFile -force -encoding UTF8 
        
        }
                
        else 
        {
            
            Return $LigCollection | Sort-Object category,name
        
        }

    }

}

function New-HPOVLogicalInterconnectGroup 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "C7000")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "C7000")]
        [Parameter (Mandatory, ParameterSetName = "Synergy")]
        [ValidateNotNullOrEmpty()]
        [Alias ('ligname')]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = "Synergy")]
        [ValidateRange(1,5)]
        [Int]$FrameCount = 1,

        [Parameter (Mandatory, ParameterSetName = "Synergy")]
        [ValidateRange(1,3)]
        [Int]$InterconnectBaySet,

        [Parameter (Mandatory, ParameterSetName = "Synergy")]
        [ValidateSet ('SEVC100F32', 'SEVC40F8', 'SEVCFC', 'SAS')]
        [String]$FabricModuleType,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "C7000")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Synergy")]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Bays,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Synergy")]
        [ValidateSet('Exact', 'None')]
        [String]$InterconnectConsistencyChecking,

        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [ValidateSet ('HighlyAvailable','Redundant','ASide','BSide')]
        [String]$FabricRedundancy = 'Redundant',

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Alias ("IGMPSnoop")]
        [Bool]$EnableIgmpSnooping = $False,
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [ValidateRange(1,3600)]
        [Alias ('IGMPIdle')]
        [Int]$IgmpIdleTimeoutInterval = 260,
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Alias ('FastMAC')]
        [Bool]$EnableFastMacCacheFailover = $True,
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [ValidateRange(1,30)]
        [Alias ('FastMACRefresh')]
        [Int]$MacRefreshInterval = 5,
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Alias ('LoopProtect')]
        [Bool]$EnableNetworkLoopProtection = $True,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Alias ('PauseProtect')]
        [Bool]$EnablePauseFloodProtection = $True,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Bool]$EnableLLDPTagging = $false,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Bool]$EnableEnhancedLLDPTLV,        

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [ValidateSet ('IPv4','IPv6','IPv4AndIPv6')]
        [String]$LldpAddressingMode,        
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Object]$SNMP,
        
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Synergy")]
        [ValidateSet('Exact', 'None')]
        [String]$SNMPConsistencyChecking,
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Bool]$SnmpV1,
        
        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Bool]$SnmpV3,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpV3User,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [ValidateNotNullOrEmpty()]
        [Array]$InternalNetworks,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Synergy")]
        [ValidateSet('Exact', 'None')]
        [String]$InternalNetworkConsistencyChecking,


        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Alias ('qos','QosConfig')]
        [Object]$QosConfiguration,
                
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Synergy")]
        [ValidateSet('Exact', 'None')]
        [String]$QoSConsistencyChecking,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Parameter (Mandatory = $False, ParameterSetName = "Import")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Parameter (Mandatory = $False, ParameterSetName = "Import")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $False, ParameterSetName = "C7000")]
        [Parameter (Mandatory = $False, ParameterSetName = "Synergy")]
        [Switch]$Async,

        [Parameter (Mandatory, ParameterSetName = "Import")]
        [ValidateScript({split-path $_ | Test-Path})]
        [Alias ('i')]
        [object]$Import

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $LigTasks = [System.Collections.ArrayList]::new()

    }
    
    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            If ($Import)
            {
            
                "[{0}] Reading input file" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                try 
                {

                    # Open input file, join so we can validate if the JSON format is correct.
                    $lig = [String]::Join("", (Get-Content $import -ErrorAction Stop)) | convertfrom-json -ErrorAction Stop

                    if ($PSBoundParameters['Scope'])
                    {

                        $lig | Add-Member -NotePropertyName initialScopeUris -NotePropertyValue ([System.Collections.ArrayList]::new())

                        ForEach ($_Scope in $Scope)
                        {

                            "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                            [void]$lig.initialScopeUris.Add($_Scope.Uri)

                        }

                    }

                    "[{0}] LIG Object to Import: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($lig | ConvertTo-Json -depth 99 | Out-String) | Write-Verbose

                    "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    $task = Send-HPOVRequest $logicalInterconnectGroupsUri POST $lig -Appliance $_appliance

                    [void]$LigStatus.Add($task)

                }
            
                # If there was a problem with the input file (format, not syntax) throw error
                catch [System.ArgumentException] 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Import' -TargetType "PSObject" -Message "JSON Input File is invalid. Please check the contents and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            Else 
            {

                switch ($PSCmdlet.ParameterSetName)
                {

                    'C7000'
                    {

                        $uri = $LogicalInterconnectGroupsUri

                        # Create new LIgObject
                        $lig = NewObject -C7KLig 

                        $lig.ethernetSettings.enableIgmpSnooping          = $EnableIgmpSnooping
                        $lig.ethernetSettings.igmpIdleTimeoutInterval     = $IgmpIdleTimeoutInterval
                        $lig.ethernetSettings.enableFastMacCacheFailover  = $EnableFastMacCacheFailover
                        $lig.ethernetSettings.macRefreshInterval          = $MacRefreshInterval
                        $lig.ethernetSettings.enableNetworkLoopProtection = $EnableNetworkLoopProtection
                        $lig.ethernetSettings.enablePauseFloodProtection  = $EnablePauseFloodProtection
                        $lig.ethernetSettings.enableTaggedLldp            = $EnableLLDPTagging
                        $lig.ethernetSettings.enableRichTLV               = $EnableEnhancedLLDPTLV

                        # Fill in missing bay locations from the input value if needed.
                        $Secondary = @{ 1 = $null; 2 = $null; 3 = $null; 4 = $null; 5 = $null; 6 = $null; 7 = $null; 8 = $null }

                        # Check for any duplicate keys
                        $duplicates = $Bays.keys | Where-Object { $Secondary.ContainsKey($_) }

                        if ($duplicates) 
                        {

                            foreach ($item in $duplicates) 
                            {

                                $Secondary.Remove($item)

                            }

                        }

                        #join the two hash tables
                        $NewBays = $Bays + $Secondary 

                        # "[{0}] Bay configuration: $($NewBays | Sort-Object Key -DescEnding | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        # Assign located Interconnect object URI to device bay mapping.
                        foreach ($_bay in ($NewBays.GetEnumerator() | Sort-Object Key))
                        {

                            $_interconnectObject = $null
                
                               switch ($_bay.value) 
                            {

                                "FlexFabric" 
                                {            

                                    # Get VC FlexFabric interconnect-type URI
                                    "[{0}] Found VC FF in bay: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "571956-B21" -Appliance $_appliance

                                }

                                "Flex10" 
                                {

                                    # Get VC Flex-10 interconnect-type URI
                                    "[{0}] Found VC F10 in bay: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "455880-B21" -Appliance $_appliance

                                }

                                "Flex1010D" 
                                {

                                    # Get VC Flex-10/10D interconnect-type URI
                                    "[{0}] Found VC F1010D in bay: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "638526-B21" -Appliance $_appliance

                                }

                                "Flex2040f8" 
                                {

                                    # Get VC Flex-10/10D interconnect-type URI
                                    "[{0}] Found VC Flex2040f8 in bay: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "691367-B21" -Appliance $_appliance

                                }

                                "VCFC20" 
                                {

                                    # Get VC Flex-10/10D interconnect-type URI
                                    "[{0}] Found VC FC 20-port in bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "572018-B21" -Appliance $_appliance

                                }

                                "VCFC24" 
                                {

                                    # Get VC Flex-10/10D interconnect-type URI
                                    "[{0}] Found VC FC 24-port in bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "466482-B21" -Appliance $_appliance

                                }

                                "VCFC16" 
                                {

                                    # Get VC FC 16Gb 24-port interconnect-type URI
                                    "[{0}] Found VC 16Gb FC 24-port in bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose

                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "751465-B21" -Appliance $_appliance

                                }

                                "FEX" 
                                {

                                    # Get Cisco Fabric ExtEnder for HP BladeSystem interconnect-type URI
                                    "[{0}] Found Cisco Fabric ExtEnder for HP BladeSystem in bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_bay.name | Write-Verbose
                            
                                    $_interconnectObject = Get-HPOVInterconnectType -partNumber "641146-B21" -Appliance $_appliance

                                }

                                default 
                                {

                                    $_interconnectObject = $null

                                }
                    
                            }
                
                            $_InterconnectMapEntryTemplate = NewObject -InterconnectMapEntryTemplate

                            $_InterconnectMapEntryTemplate.permittedInterconnectTypeUri = $_interconnectObject.uri;
                            
                            $_LogicalLocationEntry = NewObject -LocationEntry
                            $_LogicalLocationEntry.relativeValue = 1
                            $_LogicalLocationEntry.type          = 'Enclosure'
                            
                            [void]$_InterconnectMapEntryTemplate.logicalLocation.locationEntries.Add($_LogicalLocationEntry)

                            $_LogicalLocationEntry = NewObject -LocationEntry
                            $_LogicalLocationEntry.relativeValue = [String]$_bay.name.ToString().ToLower().Replace('bay',$null)
                            $_LogicalLocationEntry.type          = 'Bay'
                            
                            [void]$_InterconnectMapEntryTemplate.logicalLocation.locationEntries.Add($_LogicalLocationEntry)

                            [void]$lig.interconnectMapTemplate.interconnectMapEntryTemplates.Add($_InterconnectMapEntryTemplate)

                        }

                    }

                    'Synergy'
                    {

                        if ((${Global:ConnectedSessions} | Where-Object Name -EQ $_appliance.Name).ApplianceType -ne 'Composer')
                        {

                            $Message = 'The Appliance {0} is not a Synergy Composer, and this operation is not supported. Only Synergy managed resources are supported with this Cmdlet.' -f $_appliance.Name

                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ComposerNodeException UnsupportedMethod InvalidOperation 'ApplianceConnection' -TargetType 'HPOneView.Appliance.Connection' -Message $Message

                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        switch ($FabricModuleType)
                        {

                            {'SEVC40F8', 'SEVC100F32' -contains $_}
                            {

                                # Used for the POST request below
                                $uri = $LogicalInterconnectGroupsUri

                                # Create new LIgObject
                                $lig = NewObject -SELig 

                                $lig.name                                         = $Name
                                $lig.redundancyType                               = $LogicalInterconnectGroupRedundancyEnum[$FabricRedundancy]
                                $lig.interconnectBaySet                           = $InterconnectBaySet
                                $lig.ethernetSettings.enableIgmpSnooping          = $EnableIgmpSnooping
                                $lig.ethernetSettings.igmpIdleTimeoutInterval     = $IgmpIdleTimeoutInterval
                                $lig.ethernetSettings.enableFastMacCacheFailover  = $EnableFastMacCacheFailover
                                $lig.ethernetSettings.macRefreshInterval          = $MacRefreshInterval
                                $lig.ethernetSettings.enableNetworkLoopProtection = $EnableNetworkLoopProtection
                                $lig.ethernetSettings.enablePauseFloodProtection  = $EnablePauseFloodProtection
                                $lig.ethernetSettings.enableTaggedLldp            = $EnableLLDPTagging
                                $lig.ethernetSettings.enableRichTLV               = $EnableEnhancedLLDPTLV

                                # This is here to make sure Frame# is present, and not just a hashtable of bays.
                                if ($FrameCount -ne $Bays.Count)
                                {

                                    $Message = "The -FrameCount parameter value '{0}' does not match the expected Frame and Fabric Bay configuration in the -Bays parameters, '{1}'." -f $FrameCount, $Bays.Count
                                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidArgumentValue InvalidArgument 'InternalNetworks' -TargetType 'PSObject' -Message $Message
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                1..$FrameCount | ForEach-Object { [void]$lig.enclosureIndexes.Add($_) }

                            }

                            'SEVCFC'
                            {

                                # Used for the POST request below
                                $uri = $LogicalInterconnectGroupsUri

                                # Create new LIgObject
                                $lig = NewObject -SELig 
                                $lig.name               = $Name
                                $lig.redundancyType     = $LogicalInterconnectGroupRedundancyEnum[$FabricRedundancy]
                                $lig.interconnectBaySet = $InterconnectBaySet
                                [void]$lig.enclosureIndexes.Add('-1')
                                $EnclosureIndex = '-1'

                                # Validate BaySet
                                if ($InterconnectBaySet -eq 3)
                                {

                                    $Message = "The -InterconnectBaySet parameter value '{0}' is not supported. Please choose InterconnectBaySet 1 or 2." -f $InterconnectBaySet
                                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidArgumentValue InvalidArgument 'InterconnectBaySet' -TargetType 'Int' -Message $Message
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }
                                
                            }

                            'SAS'
                            {

                                # Used for the POST request below
                                $uri = $SasLogicalInterconnectGroupsUri

                                # Create new LIgObject
                                $lig = NewObject -SESASLIG
                                $lig.name  = $Name

                            }
                            
                        }

                        ForEach ($_Entry in ($Bays.GetEnumerator() | Sort-Object Key))
                        {

                            if ($_Entry.Name -Match 'frame')
                            {
                        
                                if ($EnclosureIndex = '-1' -and $FabricModuleType -eq 'SEVCFC')
                                {

                                    [Int]$_FrameID = -1

                                }

                                else
                                {

                                    [Int]$_FrameID = $_Entry.Name.ToLower().Replace("frame",$null)

                                }
                                

                                "[$($MyInvocation.InvocationName.ToString().ToUpper())] Processing Frame ID: {0}" -f $_FrameID | Write-Verbose

                                ForEach ($_Bay in ($_Entry.Value).GetEnumerator())
                                {

                                    [Int]$_BayID = $_Bay.Name.ToString().ToLower().Replace('bay',$null)

                                    "[$($MyInvocation.InvocationName.ToString().ToUpper())] Getting Fabric Module for Bay {0} to {1}" -f $_BayID, $_Bay.Value | Write-Verbose 
                        
                                    $_InterconnectBayObject = $null

                                    Try
                                    {

                                        $_InterconnectBayObject = Get-InterconnectBayObject $_Bay $_appliance

                                    }

                                    Catch
                                    {

                                        $PSCmdlet.ThrowTerminatingError($_)

                                    }

                                    "[$($MyInvocation.InvocationName.ToString().ToUpper())] Setting Fabric Module Bay {0} to {1}" -f $_BayID, $_InterconnectBayObject.name | Write-Verbose 

                                    $_InterconnectMapEntryTemplate = NewObject -InterconnectMapEntryTemplate

                                    $_InterconnectMapEntryTemplate.permittedInterconnectTypeUri = $_InterconnectBayObject.uri
                                    $_InterconnectMapEntryTemplate.enclosureIndex               = $_FrameID
                                    
                                    $_LogicalLocationEntry = NewObject -LocationEntry
                                    $_LogicalLocationEntry.relativeValue = $_FrameID
                                    $_LogicalLocationEntry.type          = 'Enclosure'
                                
                                    [void]$_InterconnectMapEntryTemplate.logicalLocation.locationEntries.Add($_LogicalLocationEntry)

                                    $_LogicalLocationEntry = NewObject -LocationEntry
                                    $_LogicalLocationEntry.relativeValue = $_BayID
                                    $_LogicalLocationEntry.type          = 'Bay'
                                    
                                    [void]$_InterconnectMapEntryTemplate.logicalLocation.locationEntries.Add($_LogicalLocationEntry)

                                    [void]$lig.interconnectMapTemplate.interconnectMapEntryTemplates.Add($_InterconnectMapEntryTemplate)
                            
                                }

                            }

                            else
                            {

                                [Int]$_BayID = $_Entry.Name.ToString().ToLower().Replace('bay',$null)

                                if ($EnclosureIndex = '-1' -and $FabricModuleType -eq 'SEVCFC')
                                {

                                    [Int]$_FrameID = -1

                                }

                                else
                                {

                                    $_FrameID = 1
                                    
                                }                            
                                            
                                $_InterconnectBayObject = $null

                                Try
                                {

                                    $_InterconnectBayObject = Get-InterconnectBayObject $_Entry $_appliance

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                                if ($_BayID -ne 1 -and $_BayID -ne 4 -and $_InterconnectBayObject.name -match 'SAS')
                                {

                                    $Message = 'The Fabric Module Bay {0} is invalid for the Synergy 12Gb SAS Connection Module. Please specify Fabric Module Bay 1 or 4.' -f $_BayID
                                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidFabricBayIDforSasInterconnect InvalidArgument 'Bays' -TargetType $_Entry.GetType().Name -Message $Message
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                                }

                                "[{0}] Setting Fabric Module Bay {1} to {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_BayID, $_Entry.Value | Write-Verbose 

                                $_InterconnectMapEntryTemplate = NewObject -InterconnectMapEntryTemplate

                                $_InterconnectMapEntryTemplate.permittedInterconnectTypeUri = $_InterconnectBayObject.uri
                                $_InterconnectMapEntryTemplate.enclosureIndex               = $_FrameID
                                
                                $_LogicalLocationEntry = NewObject -LocationEntry
                                $_LogicalLocationEntry.relativeValue = $_FrameID
                                $_LogicalLocationEntry.type          = 'Enclosure'
                            
                                [void]$_InterconnectMapEntryTemplate.logicalLocation.locationEntries.Add($_LogicalLocationEntry)

                                $_LogicalLocationEntry = NewObject -LocationEntry
                                $_LogicalLocationEntry.relativeValue = $_BayID
                                $_LogicalLocationEntry.type          = 'Bay'
                                
                                [void]$_InterconnectMapEntryTemplate.logicalLocation.locationEntries.Add($_LogicalLocationEntry)

                                [void]$lig.interconnectMapTemplate.interconnectMapEntryTemplates.Add($_InterconnectMapEntryTemplate)

                            }

                        }

                    }

                }
                
                if ($lig.type -notmatch 'sas')
                {

                    # Decide what type of QoS Configuration to add to activeQosConfig
                    $lig.qosConfiguration.activeQosConfig = if ($QosConfiguration) 
                    { 

                        if(-not($QosConfiguration -is [PSCustomObject]))
                        {

                            $Message = "The -QosConfiguration Parameter does not contain a valid QOS Configuration Object. Please check the value and try again."
                            $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidArgumentValue InvalidArgument 'QosConfiguration' -TargetType $QosConfiguration.Gettype().Name -Message $Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }
                    
                        if ($QosConfiguration.type -ne 'QosConfiguration')
                        {

                            $Message = "The -QosConfiguration Parameter value does not contain a valid QOS Configuration Object. OBject type expected 'QosConfiguration', Received '$($QosConfiguration.type)'. Please check the value and try again."
                            $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidArgumentValue InvalidArgument 'QosConfiguration' -TargetType 'PSObject' -Message $Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                        }

                        $QosConfiguration 
                
                    } 
                
                    Else 
                    { 
                    
                        NewObject -QosConfiguration 
                
                    }

                    if ($PSBoundParameters['InternalNetworks'])
                    {

                        ForEach ($_network in $InternalNetworks)
                        {

                            "[{0}] Internal Network Type: $($_network.GetType().Name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            switch ($_network.GetType().Name)
                            {

                                'String'
                                {

                                    "[{0}] Processing Internal Network: $_network" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    if ($_network.StartsWith($EthernetNetworksUri))
                                    {

                                        Try
                                        {

                                            # Validating object
                                            $_network = Send-HPOVRequest -Uri $_network -Hostname $_appliance

                                            # Generate terminating error due to incorrect object from URI isn't the correct type
                                            if ($_network.category -ne $ResourceCategoryEnum.EthernetNetwork)
                                            {

                                                $ExceptionMessage = "The Internal Network '{0}' is not an Ethernet network. Please specify an Ethernet Network to assign to the Internal Networks property." -f $_network
                                                $ErrorRecord = New-ErrorRecord HPOneView.LogicalInterconnectGroupResourceException InvalidArgumentValue InvalidArgument 'InternalNetworks' -TargetType 'PSObject' -Message $Message
                                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                            }

                                        }

                                        catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                    }

                                    # Get network resource via Get-HPOVNetwork
                                    else
                                    {

                                        try
                                        {

                                            $_network = Get-HPOVNetwork -Name $_network -ApplianceConnection $_appliance -ErroAction Stop

                                        }

                                        catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                    }

                                }

                                'PSCustomObject'
                                {

                                    "[{0}] Processing Internal PSObject Network: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_network.name, $_network.uri | Write-Verbose

                                    # Throw terminating error if the Internet Network object is not type Ethernet Network
                                    if (-not($_network.category -eq 'ethernet-networks'))
                                    {

                                        $Message = "The Internal Network category for ($_network.name) does not match the allowed value of 'ethernet-networks'."
                                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InternalNetworks' -TargetType 'PSObject' -Message $Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                    }

                                    # Error if Netowrk Object does not match the appliance connection we are currently Processing.
                                    if ($_network.ApplianceConnection.Name -ne $_appliance.Name)
                                    {

                                        $Message = "The Internal Network '($_network.name)' Appliance Connection ($($_network.ApplianceConnection.Name)) does not match the current Appliance Connection ($($_appliance.Name)) being Processed."
                                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InternalNetworks' -TargetType 'PSObject' -Message $Message
                                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                                    }

                                }

                            }

                            # Add to URI's to collection
                            [void]$lig.internalNetworkUris.Add($_network.uri)

                        }

                    }

                }            

                if ($PSBoundParameters['Snmp'])
                {

                    $lig.snmpConfiguration = $Snmp.PSObject.Copy()

                }

                $lig.name = $Name

                # "[{0}] LIG: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (ConvertTo-Json -Depth 99 $lig | Out-String) | Write-Verbose

                "[{0}] Sending request to create '{1}'..." -f $MyInvocation.InvocationName.ToString().ToUpper(), $lig.name | Write-Verbose
            
                Try
                {
                
                    $task = Send-HPOVRequest -Uri $uri -Method POST -Body $lig -Hostname $_appliance
                
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $PSBoundParameters['Async'])
                {

                    $task = Wait-HPOVTaskComplete $task

                }

                $task

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-InterconnectBayObject
{

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.Collections.DictionaryEntry]$InterconnectBay,
        
        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection

    )

    Process
    {

        switch ($InterconnectBay.Value) 
        {

            'SEVC100F32'
            {

                $_PartNumber = '867796-B21'

            }

            'SEVC40f8'
            {            

                $_PartNumber = '794502-B23'
                
            }

            'SEVC16GbFC'
            {

                $_PartNumber = '779227-B21'

            }

            'SEVC32GbFC'
            {

                $_PartNumber = '876259-B21'

            }

            'SE50ILM'
            {

                $_PartNumber = '867793-B21'

            }

            'SE20ILM'
            {

                $_PartNumber = '779218-B21'

            }

            'SE10ILM'
            {

                $_PartNumber = '779215-B21'

            }

            'SE12SAS'
            {

                Try
                {

                    $_interconnectObject = Get-HPOVSasInterconnectType -partNumber "755985-B21" -Appliance $ApplianceConnection

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            default 
            {

                # Should we throw an exception here?
                # $ExceptionMessage = "The specified Interconnect Bay type was not"
                # $ErrorRecord = New-ErrorRecord HPOneView.SnmpTrapDestination InvalidTrapSeverity InvalidArgument 'InterconnectBay' -Message ("The provided SNMP Trap Severity {0} is unsupported. Please check the value, making sure it is one of these values: {1}." -f $_severity, ([System.String]::Join(", ", $SnmpTrapSeverityEnums)))

                # $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                $_interconnectObject = $null

            }
                    
        }

        Try
        {

            '[{0}] Looking for {1} (P/N: {2})' -f $MyInvocation.InvocationName.ToString().ToUpper(), $InterconnectBay.Value, $_Partnumber | Write-Verbose

            if ($Null -ne $_PartNumber)
            {

                $_interconnectObject = Get-HPOVInterconnectType -partNumber $_PartNumber -Appliance $ApplianceConnection

            }
            
        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        Return $_interconnectObject

    }

}

function New-HPOVSnmpConfiguration
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Snmpv3')]
        [ValidateNotNullOrEmpty()]
        [String]$ReadCommunity,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ParameterSetName = 'Snmpv3')]
        [ValidateNotNullOrEmpty()]
        [Bool]$SnmpV1,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Snmpv3')]
        [ValidateNotNullOrEmpty()]
        [Bool]$SnmpV3,

        [Parameter (Mandatory, ParameterSetName = 'Snmpv3')]
        [HPOneView.Networking.SnmpV3User[]]$SnmpV3Users,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Snmpv3")]
        [ValidateNotNullOrEmpty()]
        [String]$Contact,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Snmpv3")]
        [ValidateNotNullOrEmpty()]
        [Array]$AccessList,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Snmpv3")]
        [ValidateNotNullOrEmpty()]
        [Array]$TrapDestinations

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $_SnmpConfigrationCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $_SnmpConfig = NewObject -SnmpConfig

        switch ($PSBoundParameters.keys)
        {

            'ReadCommunity'
            {

                $_SnmpConfig.readCommunity = $ReadCommunity

            }

            'Contact'
            {

                $_SnmpConfig.systemContact = $Contact
            
            }

            'Snmpv1'
            {

                $_SnmpConfig.enabled = $Snmpv1

            }

            'Snmpv3'
            {

                $_SnmpConfig.v3Enabled = $Snmpv3

            }

            'SnmpV3Users'
            {

                ForEach ($_SnmpV3User in $SnmpV3Users)
                {

                    [void]$_SnmpConfig.snmpUsers.add($_SnmpV3User)

                }

            }

            'AccessList'
            {
            
                ForEach ($_entry in $AccessList)
                {

                    [void]$_SnmpConfig.snmpAccess.Add($_entry)

                }
            
            }

            'TrapDestinations'
            {
            

                ForEach ($_entry in $TrapDestinations)
                {

                    [void]$_SnmpConfig.trapDestinations.Add($_entry)

                }

            }

        }


        $_SnmpConfig.PSObject.TypeNames.Insert(0,'HPOneView.Networking.SnmpConfiguration')

        [void]$_SnmpConfigrationCol.Add($_SnmpConfig)

    }

    End
    {

        Return $_SnmpConfigrationCol

    }

}

function New-HPOVSnmpTrapDestination
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'SnmpV3')]
        [ValidateNotNullOrEmpty()]
        [String]$Destination,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Community = 'public',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [Int]$Port = '162',

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('SNMPv1', 'SNMPv2', 'SNMPv3', IgnoreCase = $False)]
        [String]$SnmpFormat = 'SNMPv1',

        [Parameter (Mandatory, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.SnmpV3User]$SnmpV3User,

        [Parameter (Mandatory = $false, ParameterSetName = "SnmpV3")]
        [ValidateSet ('Inform', 'Trap', IgnoreCase = $False)]
        [String]$NotificationType = 'Trap',

        [Parameter (Mandatory = $false, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String]$EngineID,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String[]]$TrapSeverities,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String[]]$VCMTrapCategories,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String[]]$EnetTrapCategories,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "SnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String[]]$FCTrapCategories

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $_TrapDestinationCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ($SnmpFormat -eq 'SnmpV3' -and $NotificationType -eq 'Trap' -and -not $PSboundParameters['EngineID'])
        {

            $ExceptionMessage = 'Setting NotificationType to "Trap" requires an SNMPv3 Engine ID. Please provide a value for the EngineID parameter.'

            Throw $ExceptionMessage

        }

        if ($PSCmdlet.ParameterSetName -eq "SnmpV3" -and $SnmpFormat -ne 'SnmpV3' -and $NotificationType -eq 'Trap' )
        {

            $ExceptionMessage = 'Setting NotificationType is only for SNMPv3 configurations. Please change the SnmpFormat to "SNMPv3" or omit the NotificationType parameter.'

            Throw $ExceptionMessage

        }
        
        if ($PSCmdlet.ParameterSetName -eq "SnmpV3" -and $SnmpFormat -eq 'SnmpV3' -and -not $PSboundParameters['SnmpV3User'])
        {

            $ExceptionMessage = 'Configuring SNMPv3 trap destinations requires an SNMPv3 user account. Please use the New-HPOVSnmpV3User Cmdlet and provide the value to the SnmpV3User parameter.'

            Throw $ExceptionMessage

        }

        $_TrapDestination = NewObject -SnmpTrapDestination

        $_TrapDestination.trapDestination    = $Destination
        $_TrapDestination.communityString    = $Community
        $_TrapDestination.trapFormat         = $SnmpFormat

        switch ($PSBoundParameters.keys)
        {

            'TrapSeverities'
            {

                ForEach ($_severity in $TrapSeverities)
                {
                    
                    # Throw error
                    if ($SnmpTrapSeverityEnums -notcontains $_severity)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.SnmpTrapDestination InvalidTrapSeverity InvalidArgument 'TrapSeverities' -Message ("The provided SNMP Trap Severity {0} is unsupported. Please check the value, making sure it is one of these values: {1}." -f $_severity, ([System.String]::Join(", ", $SnmpTrapSeverityEnums)))

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    $_severity = $_severity.SubString(0,1).ToUpper() + $_severity.SubString(1).tolower()
                    
                    "[{0}] Processing {1} Trap Severity." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_severity | Write-Verbose 
                    
                    [void]$_TrapDestination.trapSeverities.Add($_severity)

                }

            }

            'VCMTrapCategories'
            {
            
                ForEach ($_category in $VCMTrapCategories)
                {
                    
                    # Throw error
                    if ($SnmpVcmTrapCategoryEnums -notcontains $_category)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.SnmpTrapDestination InvalidVcmTrapCategory InvalidArgument 'VCMTrapCategories' -Message ("The provided VCM Trap Category {0} is unsupported. Please check the value, making sure it is one of these values: {1}." -f $_category, ([System.String]::Join(", ", $SnmpVcmTrapCategoryEnums)))

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    $_category = $_category.SubString(0,1).ToUpper() + $_category.SubString(1).tolower()
                    
                    "[{0}] Processing {1} VCM Trap Category." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_category | Write-Verbose 

                    [void]$_TrapDestination.vcmTrapCategories.Add($_category)

                }
            
            }

            'EnetTrapCategories'
            {
            
                ForEach ($_category in $EnetTrapCategories)
                {
                    
                    # Throw error
                    if ($SnmpEneTrapCategoryEnums -notcontains $_category)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.SnmpTrapDestination InvalidEnetTrapCategory InvalidArgument 'EnetTrapCategories' -Message ("The provided Ethernet Trap Category {0} is unsupported. Please check the value, making sure it is one of these values: {1}." -f $_category, ([System.String]::Join(", ", $SnmpEneTrapCategoryEnums)))

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    if ($_category.StartsWith('port'))
                    {

                        $_category = $_category.SubString(0,1).ToUpper() + $_category.SubString(1,3).tolower() + $_category.SubString(4,1).ToUpper() + $_category.SubString(6).tolower()

                    }

                    "[{0}] Processing {1} Enet Trap Category." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_category | Write-Verbose 

                    [void]$_TrapDestination.enetTrapCategories.Add($_category)

                }
            
            }

            'FCTrapCategories'
            {
            
                ForEach ($_category in $FCTrapCategories)
                {

                    # Throw error
                    if ($SnmpFcTrapCategoryEnums -notcontains $_category)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.SnmpTrapDestination InvalidFcTrapCategory InvalidArgument 'FCTrapCategories' -Message ("The provided FC Trap Category {0} is unsupported. Please check the value, making sure it is one of these values: {1}." -f $_category, ([System.String]::Join(", ", $SnmpFcTrapCategoryEnums)))

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    "[{0}] Processing {1} FC Trap Category." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_category | Write-Verbose 
                    
                    [void]$_TrapDestination.fcTrapCategories.Add($_category)

                }
            
            }

        }

        $_TrapDestination.PSObject.TypeNames.Insert(0,'HPOneView.Networking.SnmpTrapDestination')

        [void]$_TrapDestinationCol.Add($_TrapDestination)

        if ($SnmpFormat -eq 'SnmpV3')
        {

            $_TrapDestination.trapFormat = 'SNMPv3'
            $_TrapDestination.userName = $SnmpV3User.userName

            if ($NotificationType -eq 'Trap')
            {

                $_TrapDestination.inform = $false

                if (-not $SnmpV3EngineIdPattern.Match($EngineID).Success)
                {

                    # Generate terminating error EngineID is not in the correct format
                    $ExceptionMessage = "The EngineID parameter value '{0}' is not in the correct format. The EngineID must be prefixed with '10x' followed by an even muber of 10 to 64 hexadecimal digits." -f $EngineID
                    
                    Throw $ExceptionMessage

                }

                $_TrapDestination.engineId = $EngineID                

            }

        }

    }

    End
    {

        Return $_TrapDestinationCol

    }

}

function New-HPOVQosConfig
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Passthrough")]
    Param 
    (

        [Parameter (Mandatory = $False, ParameterSetName = "Passthrough")]
        [Parameter (Mandatory, ParameterSetName = "Custom")]
        [ValidateSet ("Passthrough", "CustomNoFCoE", "CustomWithFCoE", IgnoreCase = $False)]
        [String]$ConfigType = "Passthrough",

        [Parameter (Mandatory = $False, ParameterSetName = "Custom")]
        [ValidateSet ("DSCP", "DOT1P", "DOT1P_AND_DSCP", IgnoreCase = $False)]
        [String]$UplinkClassificationType = "DOT1P",

        [Parameter (Mandatory = $False, ParameterSetName = "Custom")]
        [ValidateSet ("DSCP", "DOT1P", "DOT1P_AND_DSCP", IgnoreCase = $False)]
        [String]$DownlinkClassificationType = "DOT1P_AND_DSCP",

        [Parameter (Mandatory = $False, ParameterSetName = "Custom")]
        [System.Collections.ArrayList]$TrafficClassifiers = @()

    )

    Begin
    {

        # Helper CMDLET. Does not require appliance authentication.

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Validate the caller
        if (($PSBoundParameters['UplinkClassificationType'] -or $PSBoundParameters['DownlinkClassificationType'] -or $PSBoundParameters['TrafficClassifiers']) -and $ConfigType -eq 'Passthrough')
        {

            $ParameterNames = [System.Collections.ArrayList]::new()
        
            switch ($PSBoundParameters.Keys)
            {

                'UplinkClassificationType'   { [void]$ParameterNames.Add('UplinkClassificationType') }
                'DownlinkClassificationType' { [void]$ParameterNames.Add('DownlinkClassificationType') }
                'TrafficClassifiers'         { [void]$ParameterNames.Add('TrafficClassifiers') }

            }

            $Message = "ConfigType Parameter value was set to 'Passthrough' and $($ParameterNames -join ", ") Parameter (s) were provided. When choosing 'Passthrough' QOS Config Type, the other Parameters cannot be used."
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'ConfigType' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    Process
    {

        $_QosConfigurationObject            = NewObject -QosConfiguration
        $_QosConfigurationObject.configType = $ConfigType
        
        switch ($ConfigType)
        {

            'CustomNoFCoE'
            {

                "[{0}] Building 'CustomNoFCoE' QOS Configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($PSBoundParameters['TrafficClassifiers'])
                {

                    "[{0}] Adding Custom Traffic Classifiers." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $TrafficClassifiers | ForEach-Object { [void]$_QosConfigurationObject.qosTrafficClassifiers.Add($_) }

                }
                
                else 
                {

                    "[{0}] Adding Default NoFCoELossless Traffic Classifiers." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_QosConfigurationObject.qosTrafficClassifiers = NewObject -DefaultNoFCoELosslessQosTrafficClassifiers

                }

                $_QosConfigurationObject.uplinkClassificationType   = $UplinkClassificationType
                $_QosConfigurationObject.downlinkClassificationType = $DownlinkClassificationType
            
            }
            
            'CustomWithFCoE'
            {

                "[{0}] Building 'CustomWithFCoE' QOS Configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($PSBoundParameters['TrafficClassifiers'])
                {

                    if ($TrafficClassifiers.Count -gt 6)
                    {

                        $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'TrafficClassifiers' -TargetType 'System.Collections.ArrayList' -Message "The number of provided TrafficClassifiers is exceeded by $($TrafficClassifiers.Count - 2). When defining the QOS Configuration Type to 'CustomWithFCoE', only 6 Custom Traffic Classes are allowed."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($TrafficClassifiers.Count -le 6)
                    {

                        1..($TrafficClassifiers.Count - 6) | ForEach-Object { 
                        
                            $_NewBaseTrafficClass = NewObject -BaseTrafficClass
                            
                            $_NewBaseTrafficClass.qosTrafficClass.className += $_

                            [void]$_QosConfigurationObject.qosTrafficClassifiers.Add($_NewBaseTrafficClass) 
                        
                        }

                    }

                    "[{0}] Adding Custom Traffic Classifiers." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Check to make sure caller has not provided 'Best effort' or 'FCoE lossless' Classes
                    $TrafficClassifiers | ForEach-Object { 
                    
                        # Generate Error
                        if ($_.name -eq 'FCoE lossless')
                        {

                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'TrafficClassifiers' -TargetType 'System.Collections.ArrayList' -Message "The 'FCoE lossless' traffic class is reserved. Please remove it from the TrafficClassifiers Parameter and try again."
                            
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }    
                        
                        # Add to collection
                        [void]$_QosConfigurationObject.qosTrafficClassifiers.Add($_) 
                    
                    }

                    # Add FCoE Class
                    [void]$_QosConfigurationObject.qosTrafficClassifiers.Add((NewObject -FCoELossLessTrafficClass))

                }
                
                else 
                {

                    "[{0}] Adding Default With FCoELossless Traffic Classifiers." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_QosConfigurationObject.qosTrafficClassifiers = NewObject -DefaultFCoELosslessQosTrafficClassifiers

                }
                                
                $_QosConfigurationObject.uplinkClassificationType   = $UplinkClassificationType
                $_QosConfigurationObject.downlinkClassificationType = $DownlinkClassificationType

            }

        }

    }

    End
    {

        $_QosConfigurationObject.qosTrafficClassifiers | ForEach-Object { 
            
            if ($_.PSObject.TypeNames -notcontains 'HPOneView.Networking.Qos.TrafficClassifier')    
            {
            
                $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.Qos.TrafficClassifier') 
            
            }
        
        }

        $_QosConfigurationObject.PSObject.TypeNames.Insert(0,'HPOneView.Networking.Qos.Configuration')

        Return $_QosConfigurationObject

    }

}

function New-HPOVQosTrafficClass
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Alias ('ClassName')]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [ValidateRange(1,100)]
        [Int]$MaxBandwidth,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [String]$BandwidthShare,
        
        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Int]$EgressDot1pValue,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [System.Collections.ArrayList]$IngressDot1pClassMapping,
        
        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [System.Collections.ArrayList]$IngressDscpClassMapping,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Switch]$RealTime,

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Switch]$Enabled

    )

    Begin
    {

        # CMDLET doesn't require auth

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $NoMatch = [System.Collections.ArrayList]::new()
        
        # Validate the IngressDscpClassMapping values caller is providing
        ForEach ($item in $IngressDscpClassMapping)
        {

            if (-not($IngressDscpClassMappingEnum -contains $item))
            {

                [void]$NoMatch.Add($item)

            }

        }

        # Check to make sure caller isn't attempting to create an FCoE lossless Class
        if ($Name -eq "FCoE lossless")
        {

            $Message = "The 'FCoE lossless' Traffic Classifier cannot be modified or created. It is automatically created when using the 'New-HPOVQosConfig' CMDLET."
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Name' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($Name -eq "Best effort" -and $PSBoundParameters['MaxBandwidth'] -and $PSBoundParameters.Count -gt 2 -and (-not($PSBoundParameters['verbose']) -or -not($PSBoundParameters['debug']) -or -not($PSBoundParameters['Enabled'])))
        {

            $Message = "The 'Best effort' Traffic Classifier can only be created with providing the 'Name' and 'MaxBandwidth' Parameters."
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Name' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($NoMatch)
        {

            $Message = "Invalid IngressDscpClassMapping Parameter values found: $($NoMatch -join ', '). Please remove these values and try again."
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'IngressDscpClassMapping' -TargetType 'Array' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    Process
    {

        $_BaseTrafficClass = NewObject -BaseTrafficClass

        switch ($PSBoundParameters.Keys)
        {

            "Name"
            {

                $_BaseTrafficClass.qosTrafficClass.className = $Name

            }

            "MaxBandwidth"
            {
            
                $_BaseTrafficClass.qosTrafficClass.maxBandwidth = $MaxBandwidth
            
            }

            "BandwidthShare"
            {

                $_BaseTrafficClass.qosTrafficClass.bandwidthShare = $BandwidthShare
                        
            }


            "EgressDot1pValue"
            {
            
                $_BaseTrafficClass.qosTrafficClass.egressDot1pValue = $EgressDot1pValue
            
            }

            "RealTime"
            {
            
                $_BaseTrafficClass.qosTrafficClass.realTime = $RealTime
            
            }
            
            "IngressDot1pClassMapping"
            {

                $IngressDot1pClassMapping | ForEach-Object { [void]$_BaseTrafficClass.qosClassificationMapping.dot1pClassMapping.Add($_) }

            }
            
            "IngressDscpClassMapping"
            {

                $IngressDscpClassMapping | ForEach-Object { [void]$_BaseTrafficClass.qosClassificationMapping.dscpClassMapping.Add($_) }

            }

        }

        # "[{0}] BaseTrafficClass Object: $($_BaseTrafficClass ) $($_BaseTrafficClass.qosTrafficClass ) $($_BaseTrafficClass.qosClassificationMapping )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

    End
    {

        $_BaseTrafficClass.PSObject.TypeNames.Insert(0,'HPOneView.Networking.QosTrafficClassifier')

        Return $_BaseTrafficClass

    }

}

function Remove-HPOVLogicalInterconnectGroup 
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("uri","name","Lig",'Resource')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")] 
        [Switch]$force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource'])) 
        {
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_taskcollection = [System.Collections.ArrayList]::new()
        $_ligcollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] LIG Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('sas-logical-interconnect-groups','logical-interconnect-groups' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "LIG:$($InputObject.Name)" -TargetType PSObject -Message "The LIG resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_ligcollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "LIG:$($InputObject.Name)" -TargetType PSObject -Message "The LIG resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'logical-interconnect-groups'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($_lig in $InputObject) 
            {

                # LIG passed is a URI
                if (($_lig -is [String]) -and [System.Uri]::IsWellFormedUriString($_lig,'Relative')) 
                {

                    "[{0}] Received URI: $($_lig)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting Network Name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($ApplianceConnection.count -gt 1)
                    {

                        $ErrorRecord = New-ErrorRecord InvalidOperationException NetworkResourceNameNotUnique InvalidResult 'Resource' -Message "The provided Resource value is an URI, however a specific Appliance Connection was not provided. Please specify an Appliance Connection."
                        $PSCmdlet.WriteError($ErrorRecord)

                    }

                    else
                    {

                        Try
                        {

                            $_resp = Send-HPOVRequest $_lig -Appliance $ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        [void]$_ligcollection.Add($_resp)

                    }
                    
                }

                # LIG passed is the Name
                elseif (($_lig -is [String]) -and (-not($_lig.startsWith("/rest/")))) 
                {

                    "[{0}] Received LIG Name $($_lig)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Getting LIG object from Get-HPOVLogicalInterconnectGroup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    Try
                    {

                        $_lig = Get-HPOVLogicalInterconnectGroup $_lig -ApplianceConnection $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [void]$_ligcollection.Add($_lig)

                }

                # LIG passed is the object
                elseif ($_lig -is [PSCustomObject] -and ('sas-logical-interconnect-groups','logical-interconnect-groups' -contains $_lig.category)) 
                {
                    
                    "[{0}] LIG Object provided: $($_lig )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [void]$_ligcollection.Add($_lig)
                
                }

                elseif ($_lig -is [PSCustomObject] -and ('sas-logical-interconnect-groups','logical-interconnect-groups' -notcontains $_lig.category))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Resource' -TargetType 'PSObject' -Message "Invalid LIG Parameter: $($_lig )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_ligcollection.count) LIG resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process LIG Resources
        ForEach ($_lig in $_ligcollection)
        {
        
            if ($PSCmdlet.ShouldProcess($_lig.name,"Remove Logical Interconnect Group from appliance '$($_lig.ApplianceConnection.Name)'")) 
            {

                "[{0}] Removing LIG '$($_lig.name)' from appliance '$($_lig.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($force.IsPresent)
                    {

                        $_lig.uri += "?force=true"

                    }

                    Send-HPOVRequest -Uri $_lig.Uri -Method DELETE -AddHeader @{'If-Match' = $_lig.eTag } -Hostname $_lig.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVUplinkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Name")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Type")]
        [ValidateNotNullorEmpty()]
        [Alias ('liname')]
        [object]$LogicalInterconnect,

        [Parameter (Mandatory = $false, ParameterSetName = "Type")]
        [ValidateSet ('Ethernet','FibreChannel', IgnoreCase=$False)]
        [String]$Type,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ParameterSetName = "Type")]
        [Switch]$Report,

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ParameterSetName = "Type")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "Name")]
        [Parameter (Mandatory = $false, ParameterSetName = "Type")]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$ExportFile

    )
    
    Begin 
    {

        if ($PSBoundParameters['report'])
        {

            Write-Warning "The Report Parameter has been deprecated. The CMDLET will now display object data in Format-List view."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_UplinkSetCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        if ($LogicalInterconnect -is [PSCustomObject])
        {

            $ApplianceConnection = $ApplianceConnection | Where-Object { $_.Name -eq $LogicalInterconnect.ApplianceConnection.Name }

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '$($_appliance.Name)' Appliance" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Looking for UplinkSet Name without LI Object/Resource
            if ($PSCmdlet.ParameterSetName -eq 'Name' -and (-not($PSBoundParameters['LogicalInterconnect']))) 
            {

                if ($PSboundParameters['Name'])
                {

                    "[{0}] Uplink Set name provided: '$name'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $name = $name -replace ("[*]","%25") -replace ("[&]","%26")

                    # We will crate a URI that uses filter at the resource URI
                    $uri = $uplinkSetsUri + "?filter=name matches '$name'"

                }

                else
                {

                    "[{0}] Looking for all Uplink Sets." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $uri = $uplinkSetsUri

                }

                Try
                {

                    $_uplinksets = Send-HPOVRequest -Uri $uri -Method GET -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

                if ($_uplinksets.count -eq 0 -and $Name)
                {

                    # Generate Error if no name was found
                    $ExceptionMessage = "Specified Uplink Set '{0}' was not found on '{1}'. Please check the name and try again." -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord InvalidOperationException UplinkSetResourceNameNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)  

                }

                elseif ($_uplinksets.count -eq 0)
                {

                    "[{0}] No Uplink Sets found for {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                }

                else
                {

                    $_uplinksets = $_uplinksets.members

                }

            }

            # Looking for LI Object and associated Uplink Sets
            elseif ($PSboundParameters['LogicalInterconnect']) # -and (-not($PSBoundParameters['Name'])))
            {

                # Check the LogicalInterconnect Parameter value type
                switch ($LogicalInterconnect.GetType().Name)
                {
                
                    'PSCustomObject'
                    {

                        "[{0}] Received PSCustomObject for LogicalInterconnect Parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ($LogicalInterconnect.category -eq 'logical-interconnects')
                        {

                            "[{0}] Logical Interconnect Object provided: $($LogicalInterconnect )." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }
                        
                        else
                        {

                            "[{0}] Invalid Logical Interconnect Object provided: $($LogicalInterconnect | Out-String)." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalInterconnectInvalidCategroy InvalidArgument 'LogicalInterconnect' -TargetType 'PSObject' -Message "The provided LogicalInterconnect resource category '$($LogicalInterconnect.category)' does not match the required 'logical-interconnects' value. Please check the Parameter value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                        }

                    }

                    'String'
                    {

                        # User provided Logical Interconnect Name, look for it on the appliance
                        if (-not($LogicalInterconnect.StartsWith('/rest/')) -or (-not($LogicalInterconnect.StartsWith($logicalInterconnectsUri))))
                        {

                            "[{0}] Logical Interconnect name provided: 'LogicalInterconnect'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                "[{0}] Getting Logical Interconnect '$liName'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $LogicalInterconnect = Get-HPOVLogicalInterconnect -Name $LogicalInterconnect -ApplianceConnection $_appliance

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        # User didn't provide a Logical Interconnect Resource Name, generate error as URI's are not supported
                        else
                        {

                            "[{0}] Invalid Logical Interconnect Parameter value provided: $($LogicalInterconnect | Out-String)." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidLogicalInterconnectParameterValue InvalidArgument 'LogicalInterconnect' -TargetType 'PSObject' -Message "The provided LogicalInterconnect resource category '$($LogicalInterconnect.category)' does not match the required 'logical-interconnects' value. Please check the Parameter value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                        }
                        
                    }
                
                }

                # Use Index to find associations
                try 
                { 
                
                    $_uplinksets = [System.Collections.ArrayList]::new()

                    "[{0}] Looking for associated Uplink Sets to Logical Interconnects via Index." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_uri = '{0}?parentUri={1}&name=LOGICAL_INTERCONNECT_TO_UPLINK_SET' -f $AssociationsUri, $LogicalInterconnect.uri
                        $_indexassociatedulinksets = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                    if ($_indexassociatedulinksets.count -gt 0)
                    {

                        ForEach ($child in $_indexassociatedulinksets.members)
                        {

                            $_uplinksetobject = Send-HPOVRequest $child.childUri -Hostname $_appliance

                            if ($Name)
                            {

                                "[{0}] Filtering Uplink Sets for '$Name'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                                if ($Name -match "\*" -or $Name -match "\?")
                                {

                                    if ($_uplinksetobject.name -match $Name)
                                    {

                                        [void]$_uplinksets.Add($_uplinksetobject)

                                    }

                                }

                                else
                                {

                                    if ($_uplinksetobject.name -eq $Name)
                                    {

                                        [void]$_uplinksets.Add($_uplinksetobject)

                                    }

                                }

                            }

                            elseif ($type) 
                            {

                                "[{0}] Filtering Uplink Sets for '$type' type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                                if ($_uplinksetobject.networkType -eq $type)
                                {

                                    [void]$_uplinksets.Add($_uplinksetobject)

                                }

                            }
                            
                        }
                        
                    }
                    
                    
                    if ($Name -and $_uplinksets.count -eq 0)
                    {
                        
                        # Generate Error if no name was found
                        $ErrorRecord = New-ErrorRecord InvalidOperationException UplinkSetResourceNameNotFound ObjectNotFound 'Name' -Message "Specified Uplink Set '$name' was not found associated with '$($LogicalInterconnect.name)' on '$($_appliance.Name)'. Please check the name and try again."
                        $PSCmdlet.WriteError($ErrorRecord)  

                    }

                    elseif ($type -and $_uplinksets.count -eq 0)
                    {

                        $ErrorRecord = New-ErrorRecord InvalidOperationException UplinkSetResourceTypeNotFound ObjectNotFound 'Type' -Message "Specified Uplink Set Type '$type' was not found associated with '$($LogicalInterconnect.name)' on '$($_appliance.Name)'. Please check the name and try again."
                        $PSCmdlet.WriteError($ErrorRecord)  
                    
                    }

                }

                catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            # Update TypeNames
            if ($_uplinksets.count -gt 0)
            {

                foreach ($_object in $_uplinksets)
                {

                    switch ($_object.networkType)
                    {

                        'Ethernet'     
                        { 

                            $_object.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.UplinkSet.Ethernet') 
                            $_object.portConfigInfos | ForEach-Object {
                                
                                Add-Member -InputObject $_ -NotePropertyName ApplianceConnection -NotePropertyValue $_object.ApplianceConnection

                                $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.UplinkSet.Ethernet.UplinkPort') 

                            }
                            
                        }

                        'FibreChannel' 
                        { 
                        
                            $_object.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.UplinkSet.FibreChannel') 
                            $_object.portConfigInfos | ForEach-Object {
                                
                                Add-Member -InputObject $_ -NotePropertyName ApplianceConnection -NotePropertyValue $_object.ApplianceConnection

                                $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalInterconnect.UplinkSet.FibreChannel.UplinkPort') 

                            }
                        
                        }

                    }

                    "[{0}] Adding '$($_object.name)' to final collection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [void]$_UplinkSetCollection.Add($_object)

                }

            }

        }

    }

    End 
    {
                            
        $_UplinkSetCollection | sort-object -Property networkType,name

        "[{0}] Done. $($_UplinkSetCollection.count) uplink set(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVUplinkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "PipelineOrObjectEthernet")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "PipelineOrObjectEthernet")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Alias ('li','lig','ligName','Resource')]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Parameter (Mandatory, ParameterSetName = "PipelineOrObjectEthernet")]
        [Alias ('usName')]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Parameter (Mandatory, ParameterSetName = "PipelineOrObjectEthernet")]
        [Alias ('usType')]
        [ValidateSet ("Ethernet", "FibreChannel", "Untagged", "Tunnel", 'ImageStreamer', IgnoreCase = $false)]
        [String]$Type,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [Alias ('usNetworks')]
        [ValidateNotNullorEmpty()]
        [Array]$Networks,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [Alias ('usNativeEthNetwork','Native','PVID')]
        [ValidateNotNullorEmpty()]
        [Object]$NativeEthNetwork,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [ValidateNotNullorEmpty()]
        [Array]$NetworkSets,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [Switch]$CopyNetworksFromNetworkSet,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [Alias ('usUplinkPorts')]
        [ValidateScript({($_.Split(","))[0].contains(":")})]
        [Array]$UplinkPorts,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [Alias ('usEthMode')]
        [ValidateSet ("Auto", "Failover", IgnoreCase=$false)]
        [String]$EthMode = "Auto",
        
        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [ValidateSet ("Short", "Long", IgnoreCase=$false)]
        [String]$LacpTimer = "Short",

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectEthernet")]
        [ValidateScript({$_.contains(":")})]
        [String]$PrimaryPort,

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [ValidateSet ("Auto", "2", "4", "8", IgnoreCase=$false)]
        [String]$fcUplinkSpeed = "Auto",

        [Parameter (Mandatory = $false, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Bool]$EnableTrunking,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "PipelineOrObjectEthernet")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [ValidateSet ('Exact', 'None')]
        [String]$ConsistencyChecking,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "PipelineOrObjectEthernet")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [Switch]$Async,
        
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "PipelineOrObjectEthernet")]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = "PipelineOrObjectFibreChannel")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }
    
    Process 
    {

        if (-not $PipelineInput -and $ApplianceConnection.ApplianceType -ne 'Composer' -and $Type -eq 'ImageStreamer')
        {
            
            $Exceptionmessage = 'The ApplianceConnection {0} is not a Synergy Composer. The "ImageStreamer" Type is only supported with HPE Synergy.' -f $ApplianceConnection.Name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }

        else
        {

            $_NewUplinkSetCol = [System.Collections.ArrayList]::new()

            # If pipeline object is String and not PSCustomObject, fail the call
            if ($InputObject -is [String] -or (-not($InputObject -is [PSCustomObject])))
            {

                "[{0}] Input Object is an unsupported type: {1}. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.GetType().FullName | Write-Verbose
                
                $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'Resource' -TargetType 'PSObject' -Message "The -Resource Parameter value type($($InputObject.GetType().Fullname)) provided is not a Logical Interconnect Group object. Please check the value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($InputObject -is [PSCustomObject])
            {

                $InputObject = $InputObject.PSObject.Copy()

            }

            # Validate the resource contains the ApplianceConnection NoteProperty
            if (-not($InputObject.ApplianceConnection))
            {

                "[{0}] Input Object does not contain the ApplianceConnection NoteProperty, generating error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.GetType().FullName | Write-Verbose
                
                $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'Type' -Message "The -Type value 'ImageStreamer' is only available for Synergy resources. Please choose another UplinkSet type."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Determine the resource type; LIG or LI
            switch ($InputObject.category)
            {

                # Uplink Sets are created differently for LI Resources
                'logical-interconnects'
                {

                    if ($Type -eq 'Imagestreamer' -and $InputObject.enclosureType -notmatch 'SY')
                    {

                        $ExceptionMessage = "The -Resource Parameter value does not contain the ApplianceConnection object property. Please validate the object was retrieved from Get-HPOVLogicalInterconnectGroup or a resource URI via Send-HPOVRequest."
                        $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'Resource' -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($PSBoundParameters['ConsistencyChecking'])
                    {

                        $ExceptionMessage = "The -ConsistencyChecking parameter is only applicable with logical interconnect group resources."
                        $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'ConsistencyChecking' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    "[{0}] Provided LI Resource Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
                    "[{0}] Provided LI Resource Category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.category | Write-Verbose
                    "[{0}] Provided LI Resource URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose

                    # Init Uplink Set Objects
                    $_liUplinkSetObject  = NewObject -liUplinkSetObject

                    $_liUplinkSetObject.name = $Name
                
                    if ($EthMode)
                    {

                        $_liUplinkSetObject.connectionMode = $EthMode

                        if ($EthMode -eq 'Failover' -and $PSBoundParameters['LacpTimer'])
                        {

                            $ExceptionMessage = "The -LacpTimer Parameter value is not supported when -EthMode is set to Failover."
                            $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'LacpTimer' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    if ($EthMode -eq 'Auto' -and $PSBoundParameters['LacpTimer'])
                    {

                        $_liUplinkSetObject.lacpTimer = $LacpTimer

                    }

                    # Add Logical Interconnect object URI to Uplink Set Object
                    $_liUplinkSetObject.logicalInterconnectUri = $InputObject.uri

                    # Get list of interconnects within LI resource
                    $_liInterconnects = $InputObject.interconnectMap.interconnectMapEntries
                
                    "[{0}] Uplink Ports to Process: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [System.String]::Join(', ', $UplinkPorts) | Write-Verbose

                    # Loop through requested Uplink Ports
                    $port              = [System.Collections.ArrayList]::new()
                    $uslogicalLocation = [System.Collections.ArrayList]::new()

                    foreach ($_p in $UplinkPorts)
                    {

                        # Split string to get bay and port
                        $_p = $_p.Split(':')

                        # Synergy uplink config
                        if ($_p.Count -ge 3)
                        {

                            '[{0}] Port configuration is Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            if ($Type -eq 'FibreChannel' -and $InputObject.enclosureType -match 'SY')
                            {

                                '[{0}] Setting EnclosureID to -1 for Synergy FibreChannel' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                [String]$EnclosureID = '-1'

                            }

                            else
                            {

                                [String]$EnclosureID = $_p[0].TrimStart('enclosureEnclosure')

                            }                            

                            # Remove bay so we just have the ID
                            $bay = $_p[1].ToLower().TrimStart('bayBay') -replace " ",$null
                            
                            # Get faceplate portName (Need to make sure Synergy Uplink Port format which uses : instead of . for subport delimiter is replaced correctly)
                            $uplinkPort = $_p[2]

                            if ($_p.Count -eq 4)
                            {

                                $uplinkPort = '{0}.{1}' -f $uplinkPort, $_p[3]

                            }

                            '[{0}] Processing Frame "{1}", Bay "{2}", Port "{3}"' -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureID, $bay, $uplinkPort | Write-Verbose

                            "[{0}] Looking for Interconnect URI for Bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $bay | Write-Verbose

                            # Loop through Interconnect Map Entry Template items looking for the provided Interconnet Bay number
                            ForEach ($l in ($InputObject.interconnectMap.interconnectMapEntries | Where-Object enclosureIndex -eq $EnclosureID)) 
                            { 
    
                                if ($l.location.locationEntries | Where-Object { $_.type -eq "Bay" -and $_.relativeValue -eq $bay }) 
                                {

                                    $permittedIcUri = $l.permittedInterconnectTypeUri

                                    "[{0}]] Found permitted Interconnect Type URI {1} for Bay {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $permittedIcUri, $bay | Write-Verbose

                                }

                            }

                        }

                        else
                        {

                            '[{0}] Port configuration is not Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            # WHY IS THIS HERE? THIS IS FOR SYNERGY. NEED TO LOOK AT MY UNIT TESTS.
                            # Set the Enclosure ID value. FC type needs to be -1
                            if ($Type -eq 'FibreChannel' -and $InputObject.enclosureType -match 'SY')
                            {

                                '[{0}] Setting EnclosureID to -1 for Synergy FibreChannel' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                [String]$EnclosureID = -1

                            }

                            else
                            {

                                [String]$EnclosureID = $InputObject.enclosureUris

                            }        

                            # Remove bay so we just have the ID
                            $bay = $_p[0].ToLower().TrimStart('bayBay') -replace " ",$null
                            
                            # Get faceplate portName
                            $uplinkPort = $_p[1]

                            '[{0}] Processing Bay "{1}", Port "{2}"' -f $MyInvocation.InvocationName.ToString().ToUpper(), $bay, $uplinkPort | Write-Verbose

                            "[{0}] Looking for Interconnect URI for Bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $bay | Write-Verbose

                            # Loop through Interconnect Map Entry Template items looking for the provided Interconnet Bay number
                            ForEach ($l in $InputObject.interconnectMap.interconnectMapEntries) 
                            { 

                                #$found = $l.logicalLocation.locationEntries | ? { $_.type -eq "Bay" -and $_.relativeValue -eq $bay }
                                                                
                                if ($l.location.locationEntries | Where-Object { $_.type -eq "Bay" -and $_.value -eq $bay }) 
                                {
                                        
                                    $permittedIcUri = $l.permittedInterconnectTypeUri

                                    "[{0}]] Found permitted Interconnect Type URI {1} for Bay {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $permittedIcUri, $bay | Write-Verbose

                                }

                            } 

                        }

                        # Generate error that Interconnect could not be found from the LI
                        if ($null -eq $permittedIcUri)
                        {

                            $ExceptionMessage = 'The Interconnect Bay ID {0} could not be identified within the provided Logical Interconnect resource object.' -f $bay
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedLogicalInterconnectResource InvalidArgument 'InputObject' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        }
                        
                        # Get Interconnect Type object in order to get relative port ID
                        Try
                        {

                            $_interconnecttype = Send-HPOVRequest -Uri $permittedIcUri -Hostname $InputObject.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                    
                        # Validate the Interconnect has capable Uplink Ports
                        if (-not ($_interconnecttype.portInfos | Where-Object uplinkCapable))
                        {

                            $ExceptionMessage = "The Interconnect/Fabric module in 'BAY{0}' has no uplink capable ports. Please check the value and try again." -f $bay, $uplinkPort
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedInterconnectResource InvalidArgument 'UplinkPorts' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        'Looking for {0} port in portInfos Interconnect property.' -f $uplinkPort | Write-Verbose #.Replace('.',':') | Write-Verbose

                        # Translate the port number
                        $_portRelativeValue = $_interconnecttype.portInfos | Where-Object { $_.portName.Replace(':','.') -eq $uplinkPort } 

                        # Didn't find relative port number, so generate terminating error
                        if (-not $_portRelativeValue) 
                        {

                            $ExceptionMessage = "The provided uplink port 'BAY{0}:{1}' is an invalid port ID. Did you mean 'X{2}'? Please check the value and try again." -f $bay, $uplinkPort, $uplinkPort
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException InvalidUplinkPortID InvalidArgument 'port' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Make sure the port found is uplinkCapable
                        if (-not $_portRelativeValue.uplinkCapable) 
                        {

                            $ExceptionMessage = "The provided uplink port 'BAY{0}:{1}' is not uplink capable. Please check the value and try again." -f $bay,$uplinkPort
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedUplinkPort InvalidArgument 'UplinkPorts' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Add uplink port
                        $_location = NewObject -UplinkSetLocation

                        $_EnclosureLocation       = NewObject -UplinkSetLocationEntry
                        $_EnclosureLocation.type  = 'Enclosure'
                        $_EnclosureLocation.value = $EnclosureId
                        [void]$_location.location.locationEntries.Add($_EnclosureLocation)

                        $_BayLocation       = NewObject -UplinkSetLocationEntry
                        $_BayLocation.type  = 'Bay'
                        $_BayLocation.value = [Int]$bay
                        [void]$_location.location.locationEntries.Add($_BayLocation)

                        $_PortLocation       = NewObject -UplinkSetLocationEntry
                        $_PortLocation.type  = 'Port'
                        $_PortLocation.value = [String]$_portRelativeValue.portName
                        [void]$_location.location.locationEntries.Add($_PortLocation)

                        # Create Primary Port logical location object
                        if ($PrimaryPort -match $_p -and $EthMode -eq "Failover") 
                        {

                            "[{0}] Setting Uplink Set mode to 'Failover', and Primary Port to '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PrimaryPort | Write-Verbose

                            $_liUplinkSetObject.primaryPortLocation | Add-Member -NotePropertyName locationEntries -NotePropertyValue ([System.Collections.ArrayList]::new())

                            $_liUplinkSetObject.mode = $EthMode

                            $_EnclosureLogicalLocation       = NewObject -UplinkSetLocationEntry
                            $_EnclosureLogicalLocation.type  = 'Enclosure'
                            $_EnclosureLogicalLocation.value = [Int]$EnclosureID
                            [void]$_liUplinkSetObject.primaryPortLocation.locationEntries.Add($_EnclosureLogicalLocation)

                            $_BayLogicalLocation       = NewObject -UplinkSetLocationEntry
                            $_BayLogicalLocation.type  = 'Bay'
                            $_BayLogicalLocation.value = [Int]$bay
                            [void]$_liUplinkSetObject.primaryPortLocation.locationEntries.Add($_BayLogicalLocation)

                            $_PortLogicalLocation       = NewOBject -UplinkSetLocationEntry
                            $_PortLogicalLocation.type  = 'Port'
                            $_PortLogicalLocation.value = [String]$_portRelativeValue.portName
                            [void]$_liUplinkSetObject.primaryPortLocation.locationEntries.Add($_PortLogicalLocation)

                        }
    
                        # Set FC Uplink Port Speed
                        if ($Type -eq "FibreChannel") 
                        { 

                            $_location.desiredSpeed = $global:SetUplinkSetPortSpeeds[$fcUplinkSpeed]

                        }

                        else 
                        { 
                            
                            $_location.desiredSpeed = "Auto" 
                        
                        }

                        "[{0}] Adding Uplink Set to LIG: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_logicalLocation | out-string) | Write-Verbose
                            
                        [void]$_liUplinkSetObject.portConfigInfos.Add($_location)

                    }

                    if ($PSBoundParameters['Networks'])
                    {

                        # Network Objects
                        "[{0}] Getting Network Uris" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_networkUris = GetNetworkUris -Networks $Networks -ApplianceConnection $ApplianceConnection

                        ForEach ($_uri in $_NetworkUris)
                        {
                        
                            [void]$_liUplinkSetObject.networkUris.Add($_uri)

                        }

                    }                
                    
                    if ($PSBoundParameters['NativeEthNetwork'])
                    {
                        
                        "[{0}] Getting Native Ethernet Network Uri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_liUplinkSetObject | Add-Member -NotePropertyName nativeNetworkUri -NotePropertyValue $null

                        $_liUplinkSetObject.nativeNetworkUri = GetNetworkUris -Networks $NativeEthNetwork -ApplianceConnection $ApplianceConnection

                    }

                    if ($PSBoundParameters['NetworkSets'])
                    {

                        ForEach ($_netset in $NetworkSets)
                        {

                            # Network Objects
                            if (-not $PSBoundParameters['CopyNetworksFromNetworkSet'])
                            {

                                if ($_netset.category -ne $ResourceCategoryEnum.NetworkSet)
                                {

                                    $ExceptionMessage = "The provided network set resource '{0}' is not an expected network set resource." -f $_netset.ToString()
                                    $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException InvalidNetworkSetResource InvalidArgument 'NetworkSets' -Message $ExceptionMessage
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                else
                                {

                                    "[{0}] Adding {1} ({2}) network set." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_netset.name, $_netset.uri | Write-Verbose

                                    [void]$_liUplinkSetObject.networkSetUris.Add($_netset.uri)

                                }
                                
                            }
                            
                            "[{0}] Copying network uris from network set." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_netset.Name | Write-Verbose

                            ForEach ($_uri in $_netset.networkUris)
                            {
                            
                                # Check for duplicate entry
                                if (-not $_liUplinkSetObject.networkUris.Contains($_uri))
                                {

                                    "[{0}] Adding {1} to networkUris." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uri | Write-Verbose

                                    [void]$_liUplinkSetObject.networkUris.Add($_uri)

                                }

                                else
                                {

                                    "[{0}] {1} already exists in networkUris. Skipping." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uri | Write-Verbose

                                }

                            }

                        }

                    }

                    # Validate Uplink Network Type.
                    if ($Type -ne 'FibreChannel')
                    {

                        $_liUplinkSetObject.networkType         = $UplinkSetNetworkTypeEnum[$Type]
                        $_liUplinkSetObject.ethernetNetworkType = $UplinkSetEthNetworkTypeEnum[$Type]

                    }

                    else
                    {

                        $_liUplinkSetObject.networkType = $UplinkSetNetworkTypeEnum[$Type]

                        # Check for the module type first. If VCFC, allow the correct fcMode value, either TRUNK or NONE.
                        if ($FCTrunkCapablePartnumbers.Contains($_interconnecttype.partNumber))
                        {

                            if ($EnableTrunking)
                            {

                                $_ligUplinkSetObject.fcMode = 'TRUNK'

                            }

                            else
                            {

                                $_ligUplinkSetObject.fcMode = 'NONE'

                            }

                        }

                    }
                    
                    "[{0}] {1} Uplink Set object: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, ($_liUplinkSetObject | convertto-json -depth 99) | Write-Verbose

                    "[{0}] Sending request..." | Write-Verbose

                    Try
                    {
                        
                        $resp = Send-HPOVRequest -uri $UplinkSetsUri -method POST -body $_liUplinkSetObject -Hostname $InputObject.ApplianceConnection.Name

                        if (-not $PSBoundParameters['Async'])
                        {

                            $resp | Wait-HPOVTaskComplete

                        }

                        else
                        {

                            $resp

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                'logical-interconnect-groups'
                {

                    # Create new instance of the LIGUplinkSet Object
                    $_ligUplinkSetObject = NewObject -ligUplinkSetObject

                    if ($Type -eq 'Imagestreamer' -and $InputObject.enclosureType -notmatch 'SY')
                    {

                        $ExceptionMessage = "The -Resource Parameter value does not contain the ApplianceConnection object property. Please validate the object was retrieved from Get-HPOVLogicalInterconnectGroup or a resource URI via Send-HPOVRequest."
                        $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_ligUplinkSetObject.name = $Name

                    if ($EthMode)
                    {

                        $_ligUplinkSetObject.mode = $EthMode

                        if ($EthMode -eq 'Failover' -and $PSBoundParameters['LacpTimer'])
                        {

                            $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'LacpTimer' -Message "The -LacpTimer Parameter value is not supported when -EthMode is set to Failover."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    if ($EthMode -eq 'Auto' -and $PSBoundParameters['LacpTimer'])
                    {

                        $_ligUplinkSetObject.lacpTimer = $LacpTimer

                    }

                    "[{0}] Provided LIG Resource Name: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Provided LIG Resource Category: $($InputObject.category)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Provided LIG Resource URI: $($InputObject.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get list of interconnects in LIG definition
                    $ligInterconnects = $InputObject.interconnectMapTemplate.interconnectMapEntryTemplates
                
                    if ($UplinkPorts) 
                    { 
                        
                        "[{0}] Uplink Ports: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [System.String]::Join(', ', $UplinkPorts) | Write-Verbose 
                    
                    }

                    else 
                    { 
                        
                        "[{0}] No uplink ports request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                    
                    }

                    # Loop through requested Uplink Ports
                    $port              = [System.Collections.ArrayList]::new()
                    $uslogicalLocation = [System.Collections.ArrayList]::new()

                    foreach ($_p in $UplinkPorts)
                    {
                        
                        # Split string to get bay and port
                        $_p = $_p.Split(':')

                        # Synergy uplink config
                        if ($_p.Count -ge 3)
                        {

                            [String]$EnclosureID = $EnclosureID = $_p[0].TrimStart('enclosureEnclosure')

                            # Remove bay so we just have the ID
                            $bay = $_p[1].ToLower().TrimStart('bayBay') -replace " ",$null
                            
                            # Get faceplate portName (Need to make sure Synergy Uplink Port format which uses : instead of . for subport delimiter is replaced correctly)
                            #$uplinkPort = $_p[2].Replace('.',':')
                            $uplinkPort = $_p[2]

                            if ($_p.Count -eq 4)
                            {

                                $uplinkPort = '{0}.{1}' -f $uplinkPort, $_p[3]

                            }

                            '[{0}] Processing Frame "{1}", Bay "{2}", Port "{3}"' -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureID, $bay, $uplinkPort | Write-Verbose

                            "[{0}] Looking for Interconnect URI for Bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $bay | Write-Verbose

                            # Loop through Interconnect Map Entry Template items looking for the provided Interconnet Bay number
                            ForEach ($l in ($InputObject.interconnectmaptemplate.interconnectmapentrytemplates | Where-Object enclosureIndex -eq $EnclosureID)) 
                            { 
                                                                
                                if ($l.logicalLocation.locationEntries | Where-Object { $_.type -eq "Bay" -and $_.relativeValue -eq $bay }) 
                                {

                                    $permittedIcUri = $l.permittedInterconnectTypeUri

                                    "[{0}] Found permitted Interconnect Type URI {1} for Bay {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $permittedIcUri, $bay | Write-Verbose

                                }

                            } 

                        }

                        else
                        {

                            '[{0}] Port configuration is not Synergy Ethernet' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            # Set the Enclosure ID value. FC type needs to be -1
                            if ($Type -eq 'FibreChannel' -and $InputObject.enclosureType -match 'SY')
                            {

                                '[{0}] Setting EnclosureID to -1 for Synergy FibreChannel' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                [String]$EnclosureID = -1

                            }

                            else
                            {

                                [String]$EnclosureID = 1

                            }                            

                            # Remove bay so we just have the ID
                            $bay = $_p[0].ToLower().TrimStart('bayBay') -replace " ",$null
                            
                            # Get faceplate portName
                            $uplinkPort = $_p[1]

                            '[{0}] Processing Bay "{1}", Port "{2}"' -f $MyInvocation.InvocationName.ToString().ToUpper(), $bay, $uplinkPort | Write-Verbose

                            "[{0}] Looking for Interconnect URI for Bay {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $bay | Write-Verbose

                            # Loop through Interconnect Map Entry Template items looking for the provided Interconnet Bay number
                            ForEach ($l in $InputObject.interconnectmaptemplate.interconnectmapentrytemplates) 
                            { 

                                if ($l.logicalLocation.locationEntries | Where-Object { $_.type -eq "Bay" -and $_.relativeValue -eq $bay }) 
                                {
                                        
                                    $permittedIcUri = $l.permittedInterconnectTypeUri

                                    "[{0}] Found permitted Interconnect Type URI {1} for Bay {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $permittedIcUri, $bay | Write-Verbose

                                }

                            } 

                        }

                        # Get Interconnect Type object in order to get relative port ID
                        Try
                        {

                            $_interconnecttype = Send-HPOVRequest -Uri $permittedIcUri -Hostname $InputObject.ApplianceConnection.Name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }    

                        # Validate the Interconnect has capable Uplink Ports
                        if (-not ($_interconnecttype.portInfos | Where-Object uplinkCapable))
                        {

                            $ExceptionMessage = "The Interconnect/Fabric module in 'BAY{0}' has no uplink capable ports. Please check the value and try again." -f $bay,$uplinkPort
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedInterconnectResource InvalidArgument 'UplinkPorts' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }                    

                        # Translate the port number
                        $_portRelativeValue = $_interconnecttype.portInfos | Where-Object { $_.portName.Replace(':','.') -eq $uplinkPort } 

                        # Didn't find relative port number, so generate terminating error
                        if (-not $_portRelativeValue) 
                        {

                            $ExceptionMessage = "The provided uplink port 'BAY{0}:{1}' is an invalid port ID. Please check the value and try again." -f $bay,$uplinkPort
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException InvalidUplinkPortID InvalidArgument 'UplinkPorts' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Make sure the port found is uplinkCapable
                        if (-not $_portRelativeValue.uplinkCapable) 
                        {

                            $ExceptionMessage = "The provided uplink port 'BAY{0}:{1}' is not uplink capable. Please check the value and try again." -f $bay,$uplinkPort
                            $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException UnsupportedUplinkPort InvalidArgument 'UplinkPorts' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        # Add uplink port
                        $_logicalLocation = NewObject -UplinkSetLogicalLocation

                        $_EnclosureLogicalLocation = NewObject -UplinkSetLogicalLocationEntry
                        $_EnclosureLogicalLocation.type = 'Enclosure'
                        $_EnclosureLogicalLocation.relativeValue = [Int]$EnclosureID

                        [void]$_logicalLocation.logicalLocation.locationEntries.Add($_EnclosureLogicalLocation)

                        $_BayLogicalLocation = NewObject -UplinkSetLogicalLocationEntry
                        $_BayLogicalLocation.type = 'Bay'
                        $_BayLogicalLocation.relativeValue = [Int]$bay

                        [void]$_logicalLocation.logicalLocation.locationEntries.Add($_BayLogicalLocation)

                        $_PortLogicalLocation = NewObject -UplinkSetLogicalLocationEntry
                        $_PortLogicalLocation.type = 'Port'
                        $_PortLogicalLocation.relativeValue = [Int]$_portRelativeValue.portNumber

                        [void]$_logicalLocation.logicalLocation.locationEntries.Add($_PortLogicalLocation)

                        # Create Primary Port logical location object
                        if ($PrimaryPort -match $_p -and $EthMode -eq "Failover") 
                        {

                            "[{0}] Setting Uplink Set mode to 'Failover', and Primary Port to '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PrimaryPort | Write-Verbose 

                            $_ligUplinkSetObject.primaryPortLocation | Add-Member -NotePropertyName locationEntries -NotePropertyValue ([System.Collections.ArrayList]::new())

                            $_ligUplinkSetObject.mode = $EthMode

                            $_EnclosureLogicalLocation               = NewObject -UplinkSetLogicalLocationEntry
                            $_EnclosureLogicalLocation.type          = 'Enclosure'
                            $_EnclosureLogicalLocation.relativeValue = [Int]$EnclosureID

                            [void]$_ligUplinkSetObject.primaryPortLocation.locationEntries.Add($_EnclosureLogicalLocation)

                            $_BayLogicalLocation               = NewObject -UplinkSetLogicalLocationEntry
                            $_BayLogicalLocation.type          = 'Bay'
                            $_BayLogicalLocation.relativeValue = [Int]$bay

                            [void]$_ligUplinkSetObject.primaryPortLocation.locationEntries.Add($_BayLogicalLocation)

                            $_PortLogicalLocation               = NewOBject -UplinkSetLogicalLocationEntry
                            $_PortLogicalLocation.type          = 'Port'
                            $_PortLogicalLocation.relativeValue = [Int]$_portRelativeValue.portNumber

                            [void]$_ligUplinkSetObject.primaryPortLocation.locationEntries.Add($_PortLogicalLocation)

                        }
    
                        # Set FC Uplink Port Speed
                        if ($Type -eq "FibreChannel") 
                        { 

                            $_logicalLocation.desiredSpeed = $global:SetUplinkSetPortSpeeds[$fcUplinkSpeed] 

                        }

                        else 
                        { 
                            
                            $_logicalLocation.desiredSpeed = "Auto" 
                        
                        }

                        "[{0}] Adding Uplink Set to LIG: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_logicalLocation | out-string) | Write-Verbose
                            
                        [void]$_ligUplinkSetObject.logicalPortConfigInfos.Add($_logicalLocation)

                    }

                    if ($PSBoundParameters['Networks'])
                    {

                        "[{0}] Getting Network Uris" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                        $_NetworkUris = GetNetworkUris -Networks $Networks -ApplianceConnection $ApplianceConnection

                        $_NetworkUris | ForEach-Object {
                        
                            [void]$_ligUplinkSetObject.networkUris.Add($_)

                        }

                    }            

                    if ($PSBoundParameters['NetworkSets'])
                    {

                        ForEach ($_netset in $NetworkSets)
                        {

                            # Network Objects

                            if (-not $PSBoundParameters['CopyNetworksFromNetworkSet'])
                            {

                                if ($_netset.category -ne $ResourceCategoryEnum.NetworkSet)
                                {

                                    $ExceptionMessage = "The provided network set resource '{0}' is not an expected network set resource." -f $_netset.ToString()
                                    $ErrorRecord = New-ErrorRecord HPOneView.UplinkSetResourceException InvalidNetworkSetResource InvalidArgument 'NetworkSets' -Message $ExceptionMessage
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                else
                                {

                                    "[{0}] Adding {1} ({2}) network set." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_netset.name, $_netset.uri | Write-Verbose

                                    [void]$_ligUplinkSetObject.networkSetUris.Add($_netset.uri)

                                }
                                
                            }

                            "[{0}] Copying network uris from network set." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_netset.Name | Write-Verbose

                            ForEach ($_uri in $_netset.networkUris)
                            {
                            
                                # Check for duplicate entry
                                if (-not $_ligUplinkSetObject.networkUris.Contains($_uri))
                                {

                                    "[{0}] Adding {1} to networkUris." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uri | Write-Verbose

                                    [void]$_ligUplinkSetObject.networkUris.Add($_uri)

                                }

                                else
                                {

                                    "[{0}] {1} already exists in networkUris. Skipping." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uri | Write-Verbose

                                }

                            }

                        }

                    }
                    
                    if ($NativeEthNetwork)
                    {
                        
                        "[{0}] Getting Native Ethernet Network Uri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_ligUplinkSetObject | Add-Member -NotePropertyName nativeNetworkUri -NotePropertyValue $null

                        $_ligUplinkSetObject.nativeNetworkUri = GetNetworkUris -Networks $NativeEthNetwork -ApplianceConnection $ApplianceConnection

                    }

                    # Validate Uplink Network Type.
                    if ($Type -ne 'FibreChannel')
                    {

                        $_ligUplinkSetObject.networkType         = $UplinkSetNetworkTypeEnum[$Type]
                        $_ligUplinkSetObject.ethernetNetworkType = $UplinkSetEthNetworkTypeEnum[$Type]

                    }

                    else
                    {

                        $_ligUplinkSetObject.networkType = $UplinkSetNetworkTypeEnum[$Type]

                        if ($FCTrunkCapablePartnumbers.Contains($_interconnecttype.partNumber))
                        {

                            if ($EnableTrunking)
                            {

                                $_ligUplinkSetObject.fcMode = 'TRUNK'

                            }

                            else
                            {

                                $_ligUplinkSetObject.fcMode = 'NONE'

                            }

                        }

                    }
                    
                    if ($PSBoundParameters['ConsistencyChecking'])
                    {

                        "[{0}] Setting uplink set consistentcy checking: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LIGConsistencyCheckingEnum.$ConsistencyChecking | Write-Verbose

                        $_ligUplinkSetObject.consistencyChecking = $LIGConsistencyCheckingEnum.$ConsistencyChecking

                    }

                    "[{0}] {1} Uplink Set object: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, ($_ligUplinkSetObject | convertto-json -depth 99) | Write-Verbose

                    # Rebuld uplinkset collection
                    "[{0}] {1} Rebuilding UplinkSet template collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                    '[{0}] UplinkSets to readd: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uplinkSets.Count | Write-Verbose

                    ForEach ($_uplinkSet in $InputObject.uplinkSets)
                    {

                        "[{0}] Saving Uplink Set object to new collection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uplinkSet.name | Write-Verbose

                        [void]$_NewUplinkSetCol.Add($_uplinkSet)

                    }

                    [void]$_NewUplinkSetCol.Add($_ligUplinkSetObject)
                                        
                    [Array]$InputObject.uplinkSets = $_NewUplinkSetCol

                    '[{0}] UplinkSets after rebuild: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uplinkSets.Count | Write-Verbose

                    '[{0}] Updated Resource: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | ConvertTo-Json -Depth 99 | Out-String) | Write-Verbose

                    '[{0}] Sending request...' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {
                        
                        $resp = Send-HPOVRequest -uri $InputObject.uri -method PUT -body $InputObject -Hostname $InputObject.ApplianceConnection.Name

                        if ($PSBoundParameters['Async'])
                        {

                            $resp

                        }

                        else
                        {

                            $resp | Wait-HPOVTaskComplete

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Unsupported resource category
                default
                {

                    $ExceptionMessage = "The Resource Parameter value provided is not a Logical Interconnect Group or Logical Interconnect object. Please check the value and try again."
                    $ErrorRecord = New-ErrorRecord ArgumentException InvalidParameter InvalidArgument 'Resource' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVUplinkSet 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Ethernet')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Ethernet')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullorEmpty()]
        [Alias ('NetSet', 'NetworkSet')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [Parameter (Mandatory = $false, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [Parameter (Mandatory = $false, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullorEmpty()]
        [Object]$Network,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [ValidateNotNullorEmpty()]
        [Object[]]$AddNetwork,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [ValidateNotNullorEmpty()]
        [Object[]]$RemoveNetwork,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [Parameter (Mandatory = $false, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullorEmpty()]
        [Object[]]$AddPorts,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [Parameter (Mandatory = $false, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullorEmpty()]
        [Object[]]$RemovePorts,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [Alias ('untagged','native','untaggedNetworkUri')]
        [ValidateNotNullorEmpty()]
        [Object]$UntaggedNetwork,

        [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        [Alias ('untagged','native','untaggedNetworkUri')]
        [ValidateSet ('Short', 'Long')]
        [String]$LacpTimer,

        [Parameter (Mandatory = $false, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullorEmpty()]
        [Bool]$EnableTrunking,
        
        # Will need to add this for the Cmdlet to support LIG Uplink Sets
        # [Parameter (Mandatory = $false, ParameterSetName = 'Ethernet')]
        # [Parameter (Mandatory = $false, ParameterSetName = 'FibreChannel')]
        # [ValidateSet ('Exact', 'None')]
        # [String]$ConsistencyChecking,

        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = 'Ethernet')]
        [Parameter (Mandatory = $false, ValueFromPipelinebyPropertyName, ParameterSetName = 'FibreChannel')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose
        
        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                # Check for URI Parameters with multiple appliance connections
                if($ApplianceConnection.Count -gt 1)
                {

                    if ($InputObject -is [String] -and ($InputObject.StartsWith($NetworkSetsUri))) 
                    {
                    
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'InputObject' -Message "The InputObject Parameter as URI is unsupported with multiple appliance connections. Please check the -NetworkSet Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                    }

                    if (($Networks -is [String] -and $Networks.startswith($EthernetNetworksUri)) -or ($Networks -is [Array] -and ($Networks | ForEach-Object { $_.startswith($EthernetNetworksUri) })))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Networks' -TargetType $Networks.GetType().Name -Message "Networks Parameter contains 1 or more URIs that are unsupported with multiple appliance connections. Please check the -networks Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($UntaggedNetwork -is [String] -and $UntaggedNetwork.startswith($EthernetNetworksUri)) 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Untaggednetwork' -Message "Untaggednetwork Parameter as URI is unsupported with multiple appliance connections. Please check the -untaggednetwork Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_TaskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        # Process Network Set input object is the correct resource and data type.
        switch ($InputObject.Gettype().Name) 
        {

            "PSCustomObject" 
            { 
    
                if ($InputObject.category -eq $ResourceCategoryEnum.LogicalInterconnectGroup)
                {

                    "[{0}] Processing '{1}' ({2}) logical interconnect group resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.Uri | Write-Verbose

                }

                elseif ($InputObject.category -eq $ResourceCategoryEnum.UplinkSet)
                {

                    "[{0}] Processing '{1}' ({2}) uplink set resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.Uri | Write-Verbose

                }

                else 
                {

                    $ExceptionMessage = "The provided InputObject resource contains an unsupported category type, '$($NetworkSet.category)'. Only 'network-sets' resources are allowed. Please check the -NetworkSet Parameter value and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkSetResourceException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
                
            }

            default
            {
                    
                $ExceptionMessage = "[$($InputObject.gettype().name)] is an unsupported data type. Only [System.String] or [PSCustomObject] Network Set resources are allowed. Please check the -InputObject Parameter value and try again."
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkSetResourceException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        $_UpdatedNetSet = $InputObject.PSObject.Copy()

        $_UpdatedNetSet.networkUris = [System.Collections.ArrayList]::new()

        # Rebuild the list of URIs
        ForEach ($_OriginalNetUri in $InputObject.networkUris)
        {

            [void]$_UpdatedNetSet.networkUris.Add($_OriginalNetUri)

        }

        # Process Network Set Name change
        if ($PSBoundParameters["Name"]) 
        {
            
            "[{0}] Updating Network Set name to '$name'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_UpdatedNetSet.name = $name
            
        }

        if ($PSBoundParameters["Networks"]) 
        {

            "[{0}] Processing $($Networks.count) network resources" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $i = 1

            "[{0}] Clearing out existing networkUris." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_UpdatedNetSet.networkUris = [System.Collections.ArrayList]::new()

            foreach ($_net in $Networks) 
            {

                switch ($_net.GetType().Name)
                {

                    'String'
                    {

                        if ($_net.startswith($EthernetNetworksUri)) 
                        {

                            "[{0}] Network [$i] is a URI: $_net" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                [void]$_UpdatedNetSet.networkUris.Add($_net)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        elseif ($_net -is [String]) 
                        {

                            "[{0}] Network [$i] is a Name: $_net" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_networkObject = Get-HPOVNetwork $_net -type Ethernet -appliance $ApplianceConnection

                                [void]$_UpdatedNetSet.networkUris.Add($_networkObject.uri)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                                
                        }

                    }

                    'PSCustomObject'
                    {

                        if ($_net.category -eq "ethernet-networks") 
                        {

                            "[{0}] Network [$i] is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$i] Name: $($_net.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$i] uri: $($_net.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Networks' -TargetType $_Net.GetType().Name -Message "Network '$($_net.name)' is not a supported type '$($_net.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        [void]$_UpdatedNetSet.networkUris.Add($_net.uri)

                    }

                    default
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Networks' -TargetType $_Net.GetType().Name -Message "The provided Network is not a supported type '$($_net.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                $i++
                    
            }

        }

        if ($PSBoundParameters['AddNetwork'])
        {

            $a = 1

            ForEach ($_NetToAdd in $AddNetwork)
            {

                switch ($_NetToAdd.GetType().Name)
                {

                    'String'
                    {

                        if ($_NetToAdd.startswith($EthernetNetworksUri)) 
                        {

                            "[{0}] Network [$a] is a URI: $_NetToAdd" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToAdd = Send-HPOVRequest -Uri $_NetToAdd -Appliance $ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        elseif ($_NetToAdd -is [String]) 
                        {

                            "[{0}] Network [$a] is a Name: $_NetToAdd" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToAdd = Get-HPOVNetwork -Name $_NetToAdd -type Ethernet -appliance $ApplianceConnection -ErrorAction Stop

                                # [void]$_UpdatedNetSet.networkUris.Add($_networkObject.uri)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                                
                        }

                    }

                    'PSCustomObject'
                    {

                        if ($_NetToAdd.category -eq "ethernet-networks") 
                        {

                            "[{0}] Network [$a] is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$a] Name: $($_NetToAdd.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$a] uri: $($_NetToAdd.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        {

                            $ExceptionMessage = "Network '{0}' is not a supported type '{1}'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again." -f $_NetToAdd.name, $_NetToAdd.gettype().fullname
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'AddNetwork' -TargetType $_NetToAdd.GetType().Name -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    default
                    {

                        $ExceptionMessage = "The provided Network is not a supported type '$($_NetToAdd.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'AddNetwork' -TargetType $_NetToAdd.GetType().Name -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                "[{0}] Adding network '{1}' to Network Set" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_NetToAdd.name | Write-Verbose

                [void]$_UpdatedNetSet.networkUris.Add($_NetToAdd.uri)

                $a++

            }

        }

        if ($PSBoundParameters['RemoveNetwork'])
        {

            $r = 1

            ForEach ($_NetToREmove in $RemoveNetwork)
            {

                switch ($_NetToRemove.GetType().Name)
                {

                    'String'
                    {

                        if ($_NetToRemove.startswith($EthernetNetworksUri)) 
                        {

                            "[{0}] Network [$r] is a URI: $_NetToRemove" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToRemove = Send-HPOVRequest -Uri $_NetToAdd -Appliance $ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        elseif ($_NetToRemove -is [String]) 
                        {

                            "[{0}] Network [$r] is a Name: $_NetToRemove" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $_NetToRemove = Get-HPOVNetwork -Name $_NetToRemove -type Ethernet -appliance $ApplianceConnection -ErrorAction Stop

                                # [void]$_UpdatedNetSet.networkUris.Add($_networkObject.uri)

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                                
                        }

                    }

                    'PSCustomObject'
                    {

                        if ($_NetToRemove.category -eq "ethernet-networks") 
                        {

                            "[{0}] Network [$r] is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$r] Name: $($_NetToRemove.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            "[{0}] Network [$r] uri: $($_NetToRemove.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        }

                        else 
                        {

                            $ExceptionMessage = "Network '{0}' is not a supported type '{1}'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again." -f $_NetToRemove.name, $_NetToRemove.gettype().fullname
                            $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'RemoveNetwork' -TargetType $_NetToRemove.GetType().Name -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    default
                    {

                        $ExceptionMessage = "The provided Network is not a supported type '$($_NetToRemove.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'RemoveNetwork' -TargetType $_NetToRemove.GetType().Name -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                "[{0}] REmoving network '{1}' from Network Set" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_NetToRemove.name | Write-Verbose

                [void]$_UpdatedNetSet.networkUris.Remove($_NetToRemove.uri)

                $r++
            }

        }

        if ($PSBoundParameters["UntaggedNetwork"])
        {

            switch ($UntaggedNetwork.GetType().Name)
            {

                'String'
                {

                    if ($UntaggedNetwork.startswith($EthernetNetworksUri)) 
                    {

                        "[{0}] Untagged Network is a URI: $UntaggedNetwork" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_UpdatedNetSet.nativeNetworkUri = (Send-HPOVRequest $UntaggedNetwork -Hostname $ApplianceConnection).uri

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    elseif ($UntaggedNetwork -is [String]) 
                    {

                        "[{0}] Untagged Network is a Name: $UntaggedNetwork" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $_networkObject = Get-HPOVNetwork -Name $UntaggedNetwork -type Ethernet -appliance $ApplianceConnection -ErrorAction Stop

                            $_UpdatedNetSet.nativeNetworkUri = $_networkObject.uri

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                                
                    }

                }

                'PSCustomObject'
                {

                    if ($UntaggedNetwork.category -eq "ethernet-networks") 
                    {

                        "[{0}] Native Network is a type [PsCustomObject]" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] Native Network Name: $($UntaggedNetwork.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        "[{0}] Native Network uri: $($UntaggedNetwork.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'UntaggedNetwork' -TargetType $UntaggedNetwork.GetType().Name -Message "The UntaggedNetwork '$($UntaggedNetwork.name)' is not a supported type '$($UntaggedNetwork.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_UpdatedNetSet.nativeNetworkUri = $UntaggedNetwork.uri

                }

                default
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'UntaggedNetwork' -TargetType $UntaggedNetwork.GetType().Name -Message "The provided UntaggedNetwork is not a supported type '$($UntaggedNetwork.gettype().fullname)'. Network resource must be either [System.String] or [PsCustomObject]. Please correct the Parameter value and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        # Process Network Set Bandwidth assignment change
        if ($PSBoundParameters["TypicalBandwidth"] -or $PSBoundParameters["MaximumBandwidth"]) 
        {

            "[{0}] Updating Network bandwidth assignment." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Getting Network Set Connection Template." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
            Try
            {

                $_ct = Send-HPOVRequest -Uri $_UpdatedNetSet.connectionTemplateUri -appliance $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
                
            if ($PSBoundParameters["MaximumBandwidth"]) 
            {
                
                "[{0}] Original Maximum bandwidth assignment: $($_ct.bandwidth.maximumBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] New Maximum bandwidth assignment: $MaximumBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ct.bandwidth.maximumBandwidth = $MaximumBandwidth

            }

            if($PSBoundParameters["TypicalBandwidth"]) 
            {

                "[{0}] Original Typical bandwidth assignment: $($_ct.bandwidth.typicalBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] New Typical bandwidth assignment: $TypicalBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_ct.bandwidth.typicalBandwidth = $TypicalBandwidth
                    
            }

            Try
            {

                $_ct = Send-HPOVRequest -Uri $_UpdatedNetSet.connectionTemplateUri -Method PUT -Body $_ct -appliance $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_UpdatedNetSet = $_UpdatedNetSet | Select-Object * -ExcludeProperty typicalBandwidth, maximumBandwidth, created, modified, state, status
            
        Try
        {

            $_results = Send-HPOVRequest -Uri $_UpdatedNetSet.Uri -Method PUT -Body $_UpdatedNetSet -appliance $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        [void]$_TaskCollection.Add($_results)

    }

    End 
    {

        Return $_TaskCollection

    }

}

function GetNetworkUris
{

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Position = 0, Mandatory, ParameterSetName = "Default")]
        [Array]$Networks,

        [Parameter (Position = 1, Mandatory, ParameterSetName = "Default")]
        [Object]$ApplianceConnection

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        $_NetworkUris = [System.Collections.ArrayList]::new()

    }

    Process
    {

        # Get Network URI's if values are of type String
        ForEach ($_net in $Networks)
        {

            "[{0}] _net Type is {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.GetType().FullName | Write-Verbose

            # Network is String and Name; call Get-HPOVNetwork
            if ($_net -is [String] -and (-not($_net.StartsWith('/rest/'))))
            {

                "[{0}] Network is type String, and Network Name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Get Network Object
                Try
                {

                    $_net = Get-HPOVNetwork -Name $_net -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                "[{0}] Found Network {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.name, $_net.uri | Write-Verbose 
    
                # Insert object into original arraylist
                [void]$_NetworkUris.Add($_net.uri)

            }

            elseif ($_net -is [String] -and $_net.StartsWith('/rest/'))
            {

                "[{0}] Network is type String, and URI of network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                "[{0}] Adding URI to collection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net | Write-Verbose 

                [void]$_NetworkUris.Add($_net)

            }

            # // Need to change this to HPOneView.Networking.Networks.Ethernet
            elseif ($_net -is [PSCustomObject])
            {

                if (-not('HPOneView.Networking.EthernetNetwork','HPOneView.Networking.FCoENetwork','HPOneView.Networking.Networks.FibreChannelNetwork' -contains $_net.PSObject.TypeNames[0]))
                {

                    "[{0}] Input object is not a valid Network type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }
                
                "[{0}] Network '{1}' is [{2}]" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_net.name, $_net.GetType().Fullname | Write-Verbose

                [void]$_NetworkUris.Add($_net.uri)

            }

        }

    }

    End
    {

        "[{0}] Network URIs: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join("," , $_NetworkUris.ToArray()) | Write-Verbose

        Return $_NetworkUris
    
    }

}

# // TODO: Needed for New-HPOVUplinkSet specific to LI's
function BuildPortConfigInfos
{

    [CmdLetBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Object]$UplinkPorts,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [String]$EnclosureID = 1

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {



    }

    End
    {


    }

}

# // TODO: Needed for New-HPOVUplinkSet specific to LIG's
function BuildLogicalPortConfigInfos
{

    [CmdLetBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Object]$UplinkPorts,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [String]$EnclosureID = 1

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {



    }

    End
    {


    }

}

function Get-HPOVSwitchType
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Name')]
    [OutputType([HPOneView.Networking.SwitchType])]
    Param
    (
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'PartNumber')]
        [ValidateNotNullorEmpty()]
        [String]$PartNumber,

        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PartNumber')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $Collection = [System.Collections.ArrayList]::new()
        $NotFound   = [System.Collections.ArrayList]::new()
    
    }
    
    Process 
    {

        $_uri = '{0}?sort=name:asc' -f $SwitchTypesUri

        if ($PSboundParameters['Name']) 
        {

            $_uri += "&filter=name EQ '{0}'" -f $Name
            
        }

        elseif ($PSboundParameters['PartNumber']) 
        {
            
            $_uri += "&filter=partNumber EQ '{0}'" -f $PartNumber
        
        }


        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $resp = Send-HPOVRequest -Uri $_uri -Appliance $_appliance

            }

            Catch
            {

              $PSCmdlet.ThrowTerminatingError($_)

            }        

            if ($resp.count -gt 0)
            {

                ForEach ($_member in ($resp.members | Sort-Object name))
                {

                    New-Object HPOneView.Networking.SwitchType ($_member.name,
                                                                $_member.partNumber,
                                                                $_member.minimumFirmwareVersion,
                                                                $_member.maximumFirmwareVersion,
                                                                $_member.uri,
                                                                $_member.ApplianceConnection)

                }

            }

            elseif (-not $resp.count -and $Name) 
            {

                $ExceptionMessage = "No Switch Types with '{0}' name were found on appliance '{1}'." -f $Name, $_appliance
                $ErrorRecord = New-ErrorRecord HPOneView.SwitchTypeResourceException SwitchTypeNameResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            elseif (-not $resp.count -and $PartNumber) 
            {

                $ExceptionMessage = "No Switch Types with '{0}' partnumber were found on appliance '{1}'." -f $PartNumber, $_appliance
                $ErrorRecord = New-ErrorRecord HPOneView.SwitchTypeResourceException SwitchTypePartnumberResourceNotFound ObjectNotFound 'PartNumber' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVLogicalSwitchGroup
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Pipeline')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Pipeline')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$exportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            $PipelineInput = $True

        }

        Else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_Collection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        if ($PipelineInput)
        {

            # Task Resource Object
            if ($InputObject -is [PSCustomObject] -and $InputObject.category -eq 'tasks')
            {

                "[{0}] Processig task resource to get created object" -f $MyInvocation.InvocationName.ToString().ToUpper()

                if ($InputObject.taskState -eq 'Completed')
                {

                    Try
                    {

                        $_LogicalSwitchGroup = Send-HPOVRequest $InputObject.associatedResource.resourceUri -Hostname $InputObject.ApplianceConnection.Name

                        $_LogicalSwitchGroup | ForEach-Object { 
                
                            $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalSwitchGroup')    

                            [void]$_Collection.Add($_) 
                
                        }

                    }

                    Catch
                    {

                        "[{0}] API Error Caught: $($_.Exception.Message)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Generate error
                else
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchGroupResourceException TaskFailure InvalidOperation 'InputObject' -Message "The Task object provided by the pipeline did not complete successfully. Please validate the task object resource and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                }

            }

            else
            {

                $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchGroupResourceException LogicalSwitchGroupNotFound ObjectNotFound 'InputObject' -Message "The Logical Switch Group associated with the pipeline input task object was not found on '$($InputObject.ApplianceConnection.Name)'. Please check the value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

            }

        }

        Else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                $_Query = [System.Collections.ArrayList]::new()

                # Handle default cause of AllResourcesInScope
                if ($Scope -eq 'AllResourcesInScope')
                {
    
                    "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                    $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active
    
                    # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                    if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                    {
    
                        $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                        "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                    }
    
                    # Process ApplianceConnection ActivePermissions collection
                    else
                    {
    
                        Try
                        {
    
                            $_ScopeQuery = Join-Scope $_Scopes
    
                        }
    
                        Catch
                        {
    
                            $PSCmdlet.ThrowTerminatingError($_)
    
                        }
    
                        [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                    }
    
                }
    
                elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
                {
    
                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                elseif ($Scope -eq 'AllResources')
                {
    
                    "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                else
                {
    
                    Try
                    {
    
                        $_ScopeQuery = Join-Scope $Scope
    
                    }
    
                    Catch
                    {
    
                        $PSCmdlet.ThrowTerminatingError($_)
    
                    }
    
                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                }

                if ($Name)
                {

                    if ($Name.Contains('*'))
                    {

                        [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                    }

                    else
                    {

                        [Void]$_Query.Add(("name:'{0}'" -f $Name))

                    }                
                    
                }

                if ($Label)
                {

                    [Void]$_Query.Add(("labels:'{0}'" -f $Label))

                }

                $_Category = 'category=logical-switch-groups'

                # Build the final URI
                $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

                Try
                {

                    [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
                { 

                    $ExceptionMessage = "Logical Switch Group '{0}' resource not found on {1} appliance. Please check the name and try again." -f $Name, $_appliance.Name

                    "[{0}] {1} Generating error" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ExceptionMessage | Write-Verbose
                
                    $ErrorRecord = New-ErrorRecord InvalidOperationException LogicalSwitchGroupNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)  

                }  
    
                elseif ($_ResourcesFromIndexCol.count -eq 0) 
                { 

                    "[{0}] No Logical Switch Group resources found on {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                }

                else 
                {

                    "[{0}] Found {1} Logical Switch Group resource(s)." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ligs.count | Write-Verbose
        
                    ForEach ($_member in $_ResourcesFromIndexCol)
                    {            

                        $_member.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalSwitchGroup')    

                        [void]$_Collection.Add($_member) 

                    }

                }

            }

        }

    }

    End 
    {

        "[{0}] Done. $($_Collection.count) logical switch group(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose    

        if ($exportFile)
        {
            
            $_Collection | convertto-json -Depth 99 | Set-Content -Path $exportFile -force -encoding UTF8 
        
        }
                
        else 
        {
            
            Return $_Collection | Sort-Object name
        
        }

    }

}

function New-HPOVLogicalSwitchGroup
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateRange(1,2)]
        [Int]$NumberOfSwitches = 1,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Networking.SwitchType]$SwitchType,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Async

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $SwitchType)
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

    }
    
    Process
    {

        # Create new LIgObject
        $_LogicalSwitchGroup = NewObject -LogicalSwitchGroup 
        $_LogicalSwitchGroup.name = $Name

        For ($i = 1; $i -le $NumberOfSwitches; $i++)
        {

            "[{0}] Adding Location Entry {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $i | Write-Verbose

            $_SwitchLogicalLocation = NewObject -SwitchLogicalLocation
            $_SwitchLogicalLocation.permittedSwitchTypeUri = $SwitchType.uri

            $_SwitchLocationEntry = NewObject -LocationEntry
            $_SwitchLocationEntry.relativeValue = $i
            $_SwitchLocationEntry.type = "StackingMemberId"

            [void]$_SwitchLogicalLocation.logicalLocation.locationEntries.Add($_SwitchLocationEntry)
            [void]$_LogicalSwitchGroup.switchMapTemplate.switchMapEntryTemplates.Add($_SwitchLogicalLocation)

        }

        "[{0}] LS: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (ConvertTo-Json -Depth 99 $_LogicalSwitchGroup | out-string) | Write-Verbose 

        "{0}] Sending request to create '{1}'..." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LogicalSwitchGroup.name | Write-Verbose 
    
        Try
        {
        
            $_Task = Send-HPOVRequest -Uri $LogicalSwitchGroupsUri -Method POST -Body $_LogicalSwitchGroup -Hostname $ApplianceConnection
        
        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $Async.IsPresent)
        {

            Try
            {

                $_Task = Wait-HPOVTaskComplete -InputObject $_Task

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_Task

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVLogicalSwitchGroup
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("ls",'LogicalSwitchGroup')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")] 
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        {
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_lsgcollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('logical-switch-groups' -eq $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "LSG:$($InputObject.Name)" -TargetType PSObject -Message "The Logical Switch Group resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_lsgcollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Network:$($InputObject.Name)" -TargetType PSObject -Message "The Logical Switch Group resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'logical-switch-groups'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($_resource in $InputObject) 
            {

                if ($_resource -is [String])
                {

                    "[{0}] Received URI: $($_resource)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ErrorRecord = New-ErrorRecord InvalidOperationException UnsupportedParameterType InvalidArgumetn 'InputObject' -Message "The provided Resource value is a String, only PSCustomObject types are supported."
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                # LIG passed is the object
                elseif ($_resource -is [PSCustomObject] -and 'logical-switch-groups' -eq $_resource.category)
                {
                    
                    "[{0}] Object provided: $($_resource )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [void]$_lsgcollection.Add($_resource)
                
                }

                elseif ($_resource -is [PSCustomObject] -and 'logical-switch-groups' -ne $_resource.category)
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "Invalid Logical Switch Group Parameter: $($_resource )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_lsgcollection.count) resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Resources
        ForEach ($_lsg in $_lsgcollection)
        {
        
            if ($PSCmdlet.ShouldProcess($_lsg.ApplianceConnection.Name,("Remove Logical Switch Group '{0}'" -f $_lsg.name)))
            {

                "[{0}] Removing '$($_lsg.name)' from appliance '$($_lsg.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($force.IsPresent)
                    {

                        $_lsg.uri += "?force=true"

                    }

                    Send-HPOVRequest -Uri $_lsg.Uri -Method DELETE -AddHeader @{'If-Match' = $_lsg.eTag } -Hostname $_lsg.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVLogicalSwitch
{


    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Pipeline')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Pipeline')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ("x", "export")]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$exportFile

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            $PipelineInput = $True

        }

        Else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_Collection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        if ($PipelineInput)
        {

            # Task Resource Object
            if ($InputObject -is [PSCustomObject] -and $InputObject.category -eq 'tasks')
            {

                "[{0}] Processing task resource to get created object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if ($InputObject.taskState -eq 'Completed')
                {

                    Try
                    {

                        $_LogicalSwitchGroup = Send-HPOVRequest $InputObject.associatedResource.resourceUri -Hostname $InputObject.ApplianceConnection.Name

                        $_LogicalSwitchGroup | ForEach-Object { 
                
                            $_.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalSwitch')    

                            [void]$_Collection.Add($_) 
                
                        }

                    }

                    Catch
                    {

                        "[{0}] API Error Caught: $($_.Exception.Message)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Generate error
                else
                {

                    $InputObject

                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchGroupResourceException TaskFailure InvalidOperation 'InputObject' -Message "The Task object provided by the pipeline did not complete successfully. Please validate the task object resource and try again."
                    $PSCmdlet.WriteError($ErrorRecord)  

                }

            }

            else
            {

                $ExceptionMessage = "The Logical Switch associated with the pipeline input task object was not found on '{0}'. Please check the value and try again." -f $InputObject.ApplianceConnection.Name 
                $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchResourceException LogicalSwitchNotFound ObjectNotFound 'InputObject' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)  

            }

        }

        Else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                $_Query = [System.Collections.ArrayList]::new()

                # Handle default cause of AllResourcesInScope
                if ($Scope -eq 'AllResourcesInScope')
                {
    
                    "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                    $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active
    
                    # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                    if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                    {
    
                        $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                        "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                    }
    
                    # Process ApplianceConnection ActivePermissions collection
                    else
                    {
    
                        Try
                        {
    
                            $_ScopeQuery = Join-Scope $_Scopes
    
                        }
    
                        Catch
                        {
    
                            $PSCmdlet.ThrowTerminatingError($_)
    
                        }
    
                        [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                    }
    
                }
    
                elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
                {
    
                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                elseif ($Scope -eq 'AllResources')
                {
    
                    "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                else
                {
    
                    Try
                    {
    
                        $_ScopeQuery = Join-Scope $Scope
    
                    }
    
                    Catch
                    {
    
                        $PSCmdlet.ThrowTerminatingError($_)
    
                    }
    
                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                }

                if ($Name)
                {

                    if ($Name.Contains('*'))
                    {

                        [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                    }

                    else
                    {

                        [Void]$_Query.Add(("name:'{0}'" -f $Name))

                    }                
                    
                }

                if ($Label)
                {

                    [Void]$_Query.Add(("labels:'{0}'" -f $Label))

                }

                $_Category = 'category=logical-switches'

                # Build the final URI
                $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

                Try
                {

                    [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }        
        
                if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
                { 

                    "[{0}] No Logical Switch resources found on {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                    $ExceptionMessage = "The Logical Switch '{0}' was not found on '{1}' appliance connection." -f $Name, $_appliance.Name 
                    $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchResourceException LogicalSwitchNotFound ObjectNotFound 'InputObject' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)  

                }

                elseif ($_ResourcesFromIndexCol.count -eq 0) 
                { 

                    "[{0}] No Logical Switch resources found on {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                }

                else 
                {

                    "[{0}] Found {1} Logical Switch resource(s)." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ResourcesFromIndexCol.count | Write-Verbose
        
                    ForEach ($_member in $_ResourcesFromIndexCol)
                    { 
        
                        $_member.PSObject.TypeNames.Insert(0,'HPOneView.Networking.LogicalSwitch')    

                        [void]$_Collection.Add($_member) 
        
                    }

                }

            }

        }

    }

    End 
    {

        "[{0}] Done. {1} logical switch(es) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Collection.count | Write-Verbose

        if ($exportFile)
        {
            
            $_Collection | convertto-json -Depth 99 | Set-Content -Path $exportFile -force -encoding UTF8 
        
        }
                
        else 
        {
            
            Return $_Collection | Sort-Object name
        
        }

    }

}

function New-HPOVLogicalSwitch
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Managed")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [Object]$LogicalSwitchGroup,

        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "ManagedSnmpV3")]
        [Switch]$Managed,

        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredSnmpV3")]
        [Switch]$Monitored,

        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String]$Switch1Address,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String]$Switch2Address,

        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String]$SshUserName,

        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [Parameter (Mandatory, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [Object]$SshPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [Int]$SnmpPort = 161,

        [Parameter (Mandatory = $false, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $false, ParameterSetName = "Monitored")]
        [Switch]$SnmpV1,

        [Parameter (Mandatory, ParameterSetName = "Managed")]
        [Parameter (Mandatory, ParameterSetName = "Monitored")]
        [ValidateNotNullOrEmpty()]
        [String]$SnmpCommunity,

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [Switch]$SnmpV3,

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [String]$SnmpUserName,

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateSet ("AuthOnly","AuthAndPriv")]
        [ValidateNotNullOrEmpty()]
        [String]$SnmpAuthLevel = "AuthOnly",

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateSet ("SHA","MD5")]    
        [ValidateNotNullOrEmpty()]
        [String]$SnmpAuthProtocol = 'SHA',

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpAuthPassword,

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateSet ("aes128","des56")]    
        [ValidateNotNullOrEmpty()]
        [String]$SnmpPrivProtocol,

        [Parameter (Mandatory = $false, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $false, ParameterSetName = "MonitoredSnmpV3")]
        [ValidateNotNullOrEmpty()]
        [Object]$SnmpPrivPassword,

        [Parameter (Mandatory = $False, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $False, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $False, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $False, ParameterSetName = "MonitoredSnmpV3")]
        [Switch]$Async,
        
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Managed")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Monitored")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "ManagedSnmpV3")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "MonitoredSnmpV3")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $LogicalSwitchGroup)
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        # Validate SNMPv3 Parameters that are required
        if ('ManagedSnmpV3','MonitoredSnmpV3' -contains $PSCmdlet.ParameterSetName)
        {

            if ($SnmpAuthLevel -eq "AuthOnly" -and 
            (-not $SnmpAuthProtocol -or 
            -not $SnmpAuthPassword)) 
            {

                # Generate Terminateing error
                $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchResourceException MissingRequiredParameters InvalidArgument 'SnmpAuthLevel' -Message "The -SnmpAuthLevel Parameter was set to 'AuthOnly', but did not include both -SnmpAuthProtocol and -SnmpAuthPassword Parameters."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            }

            if ($SnmpAuthLevel -eq "AuthAndPriv" -and (
                -not $SnmpAuthProtocol -or 
                -not $SnmpAuthPassword -or 
                -not $SnmpPrivProtocol -or 
                -not $SnmpPrivPassword )) 
            {

                # Generate Terminateing error
                $ErrorRecord = New-ErrorRecord HPOneView.LogicalSwitchResourceException MissingRequiredParameters InvalidArgument 'SnmpAuthLevel' -Message "The -SnmpAuthLevel Parameter was set to 'AuthAndPriv', but did not include -SnmpAuthProtocol, -SnmpAuthPassword, -SnmpPrivProtocol and -SnmpPrivPassword Parameters."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }
    
    Process
    {

        # Create new LIgObject
        $_LogicalSwitch = NewObject -LogicalSwitch 
        $_LogicalSwitch.logicalSwitch.name = $Name
        $_LogicalSwitch.logicalSwitch.managementLevel = $LogicalSwitchManagementLevelEnum[$PSCmdlet.ParameterSetName]

        if ($SshPassword -is [SecureString])
        {

            $SshPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SshPassword))

        }

        if ($PSBoundParameters['SnmpAuthPassword'] -and $SnmpAuthPassword -is [SecureString])
        {

            $SnmpAuthPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SnmpAuthPassword))
            
        }

        if ($PSBoundParameters['SnmpPrivPassword'] -and $SnmpPrivPassword -is [SecureString])
        {

            $SnmpPrivPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SnmpPrivPassword))
            
        }

        # Validate Logic Switch
        if ($LogicalSwitchGroup -isnot [PSCustomObject])
        {

            # Generate Error
            "[{0}] Invalid LogicalSwitchGroup resource. Generating Terminating Error" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_Message = 'The provided Logical Switch Group {0} is not a supported object type. Expected [PSCustomObject], Received "{1}".' -f $LogicalSwitchGroup.name, $SwitchType.GetType().FullName

            $ErrorRecord = New-ErrorRecord HPOneView.SwitchTypeResourceException InvalidSwitchTypeResource InvalidArgument 'LogicalSwitchGroup' -TargetType $LogicalSwitchGroup.GetType().Name -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($LogicalSwitchGroup.category -ne 'logical-switch-groups')
        {

            # Generate error
            "[{0}] Invalid LogicalSwitchGroup resource. Generating Terminating Error" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_Message = 'The provided Logical Switch Group {0} is not a supported object category type. Expected logical-switch-groups", Received "{1}".' -f $LogicalSwitchGroup.name, $LogicalSwitchGroup.category

            $ErrorRecord = New-ErrorRecord HPOneView.SwitchTypeResourceException InvalidSwitchTypeResource InvalidArgument 'LogicalSwitchGroup' -TargetType 'PSObject' -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_LogicalSwitch.logicalSwitch.logicalSwitchGroupUri = $LogicalSwitchGroup.uri
        $NumberOfSwitches = $LogicalSwitchGroup.switchMapTemplate.switchMapEntryTemplates.count

        "[{0}] Processing number of switches from Switch Group: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $NumberOfSwitches | Write-Verbose

        # Add Switch Credentials to connection Object
        For ($i = 1; $i -le $NumberOfSwitches; $i++)
        {

            "[{0}] Processing switch: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $i | Write-Verbose

            # SNMP and Management Address
            $_SwitchCredentialConfig = NewObject -LogicalSwitchCredentials
            $_SwitchCredentialConfig.snmpPort = $SnmpPort

            if ($i -eq 1)
            {

                $_SwitchCredentialConfig.logicalSwitchManagementHost = $Switch1Address

            }
            
            elseif ($i -eq 2)
            {

                $_SwitchCredentialConfig.logicalSwitchManagementHost = $Switch2Address

            }

            if ($PSBoundParameters['SnmpV1'])
            {
                
                $_SwitchCredentialConfig.snmpV1Configuration.communityString = $SnmpCommunity

            }

            else
            {

                $_SwitchCredentialConfig.snmpVersion = 'SNMPv3'

            }

            [void]$_LogicalSwitch.logicalSwitch.switchCredentialConfiguration.Add($_SwitchCredentialConfig)

            # SSH
            $_LogialSwitchConnectionProperties = NewObject -LogialSwitchConnectionProperties

            # SSH User Account
            $_LogicalSwitchConnectionProperty              = NewObject -LogicalSwitchConnectionProperty
            $_LogicalSwitchConnectionProperty.propertyName = 'SshBasicAuthCredentialUser'
            $_LogicalSwitchConnectionProperty.value        = $SshUserName
            $_LogicalSwitchConnectionProperty.valueType    = 'String'

            [void]$_LogialSwitchConnectionProperties.connectionProperties.Add($_LogicalSwitchConnectionProperty)

            # SSH User Password
            $_LogicalSwitchConnectionProperty              = NewObject -LogicalSwitchConnectionProperty
            $_LogicalSwitchConnectionProperty.propertyName = 'SshBasicAuthCredentialPassword'
            $_LogicalSwitchConnectionProperty.value        = $SshPassword
            $_LogicalSwitchConnectionProperty.valueFormat  = 'SecuritySensitive'
            $_LogicalSwitchConnectionProperty.valueType    = 'String'

            [void]$_LogialSwitchConnectionProperties.connectionProperties.Add($_LogicalSwitchConnectionProperty)

            # Add
            [Void]$_LogicalSwitch.logicalSwitchCredentials.Add($_LogialSwitchConnectionProperties)            

        }
    
        # Handle Device SNMP Configuration
        if ('ManagedSnmpV3','MonitoredSnmpV3' -contains $PSCmdlet.ParameterSetName)
        {

            For ($i = 0; $i -lt $NumberOfSwitches; $i++)
            {

                "[{0}] Processing SNMPv3 Auth credentials" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Add SNMPv3 AuthOnly Protocol
                $_LogicalSwitch.logicalSwitch.switchCredentialConfiguration[$i].snmpV3Configuration.authorizationProtocol = $SnmpAuthProtocolEnum[$SnmpAuthProtocol]
                $_LogicalSwitch.logicalSwitch.switchCredentialConfiguration[$i].snmpV3Configuration.securityLevel = 'Auth'

                # Add SNMPv3 Credentials
                $_LogicalSwitchConnectionProperty              = NewObject -LogicalSwitchConnectionProperty
                $_LogicalSwitchConnectionProperty.propertyName = 'SnmpV3User'
                $_LogicalSwitchConnectionProperty.value        = $SnmpUserName
                $_LogicalSwitchConnectionProperty.valueType    = 'String'
                [void]$_LogicalSwitch.logicalSwitchCredentials[$i].connectionProperties.Add($_LogicalSwitchConnectionProperty)

                $_LogicalSwitchConnectionProperty              = NewObject -LogicalSwitchConnectionProperty
                $_LogicalSwitchConnectionProperty.propertyName = 'SnmpV3AuthorizationPassword'
                $_LogicalSwitchConnectionProperty.value        = $SnmpAuthPassword
                $_LogicalSwitchConnectionProperty.valueFormat  = 'SecuritySensitive'
                $_LogicalSwitchConnectionProperty.valueType    = 'String'
                [void]$_LogicalSwitch.logicalSwitchCredentials[$i].connectionProperties.Add($_LogicalSwitchConnectionProperty)

                # Add SNMPv3 Privacy settings if specified
                if ($SnmpAuthLevel -eq "AuthAndPriv") 
                {

                    "[{0}] Processing SNMPv3 AuthAndPrivacy credentials" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_LogicalSwitch.logicalSwitch.switchCredentialConfiguration[$i].snmpV3Configuration.privacyProtocol = $SnmpPrivProtocolEnum[$SnmpPrivProtocol]
                    $_LogicalSwitch.logicalSwitch.switchCredentialConfiguration[$i].snmpV3Configuration.securityLevel   = 'AuthPrivacy'

                    $_LogicalSwitchConnectionProperty              = NewObject -LogicalSwitchConnectionProperty
                    $_LogicalSwitchConnectionProperty.propertyName = 'SnmpV3PrivacyPassword'
                    $_LogicalSwitchConnectionProperty.value        = $SnmpPrivPassword
                    $_LogicalSwitchConnectionProperty.valueFormat  = 'SecuritySensitive'
                    $_LogicalSwitchConnectionProperty.valueType    = 'String'
                    [void]$_LogicalSwitch.logicalSwitchCredentials[$i].connectionProperties.Add($_LogicalSwitchConnectionProperty)

                }

            }

        }

        "[{0}] LS: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (ConvertTo-Json -Depth 99 $_LogicalSwitch | out-string) | Write-Verbose 

        "{0}] Sending request to create '{1}'..." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_LogicalSwitch.name | Write-Verbose 
    
        Try
        {
        
            $_Task = Send-HPOVRequest -Uri $LogicalSwitchesUri -Method POST -Body $_LogicalSwitch -Hostname $ApplianceConnection
        
        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $Async.IsPresent)
        {

            Try
            {

                $_Task = Wait-HPOVTaskComplete -InputObject $_Task

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_Task

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVLogicalSwitch
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("ls",'LogicalSwitch')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")] 
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = "default")] 
        [Switch]$Async

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        {
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_taskcollection          = [System.Collections.ArrayList]::new()
        $_logicalswitchcollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ('logical-switches' -eq $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The Logical Switch resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_logicalswitchcollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The Logical Switch resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'logical-switches'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            foreach ($_resource in $InputObject) 
            {

                if ($_resource -is [String])
                {

                    "[{0}] Received URI: $($_resource)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ErrorRecord = New-ErrorRecord InvalidOperationException UnsupportedParameterType InvalidArgumetn 'InputObject' -Message "The provided Resource value is a String, only PSCustomObject types are supported."
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                # LIG passed is the object
                elseif ($_resource -is [PSCustomObject] -and 'logical-switches' -eq $_resource.category)
                {
                    
                    "[{0}] Object provided: $($_resource )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [void]$_logicalswitchcollection.Add($_resource)
                
                }

                elseif ($_resource -is [PSCustomObject] -and 'logical-switches' -ne $_resource.category)
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Resource' -TargetType 'PSObject' -Message "Invalid Logical Switch Parameter: $($_lig )"
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_logicalswitchcollection.count) resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Resources
        ForEach ($_ls in $_logicalswitchcollection)
        {
        
            if ($PSCmdlet.ShouldProcess($_ls.ApplianceConnection.Name,("Remove Logical Switch '{0}'" -f $_ls.name))) 
            {

                "[{0}] Removing '$($_ls.name)' from appliance '$($_ls.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    if ($force.IsPresent)
                    {

                        $_ls.uri += "?force=true"

                    }

                    $_reply = Send-HPOVRequest -Uri $_ls.uri -Method DELETE -AddHeader @{'If-Match' = $_ls.eTag } -Hostname $_ls.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($PSboundParameters['Async'])
                {

                    $_reply

                }

                else
                {

                    $_reply | Wait-HPOVTaskComplete 

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVLogicalSwitch
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Ethernet")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [Alias ('LogialSwitch')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [String]$Prefix,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [String]$Suffix,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ("General", "Management", "VMMigration", "FaultTolerance")]
        [String]$Purpose,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Bool]$Smartlink, 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Bool]$PrivateNetwork, 

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [validaterange(2,20000)]
        [int32]$TypicalBandwidth, 
        
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [validaterange(100,20000)]
        [int32]$MaximumBandwidth, 

        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateRange(1,1800)]
        [Alias ('lst')]
        [int32]$LinkStabilityTime, 

        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [Alias ('ald')]
        [Bool]$AutoLoginRedistribution,

        [Parameter (Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [Object]$ManagedSan,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "FibreChannel")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        Write-Warning 'IN DEV'
        BREAK

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            "[{0}] Network resource passed via pipeline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_NetworksToUpdate = [System.Collections.ArrayList]::new()
        $NetCollection     = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        #build collection of networks to modify
        foreach ($net in $InputObject) 
        {

            if ($PSBoundParameters['LinkStabilityTime'] -and $net.category -eq 'fcoe-networks')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'LinkStabilityTime' -TargetType 'Int' -Message "The -LinkStabilityTime Parameter is not supported with FCoE Network resources, only FibreChannel network resources. Please check your call and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($PSBoundParameters['AutoLoginRedistribution'] -and $net.category -eq 'fcoe-networks')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'AutoLoginRedistribution' -TargetType 'Boolean'  -Message "The -AutoLoginRedistribution Parameter is not supported with FCoE Network resources, only FibreChannel network resources. Please check your call and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Check the name Parameter value if the caller inadvertantly provided an object for name Parameter
            if ($name -and ($name -match "category=ethernet-networks" -or $name -match "category=fc-networks" -or $name -match "category=fcoe-networks"))
            { 
            
                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Name' -Message "The -name Parameter value appears to have been passed the network resource object, which is converted to type [String] and is an invalid operation. Please verify that you provided the Network Name attribute in the -name Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

            elseif ($name -and $name.length -gt 255) 
            {

                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'Name' -Message "The -name Parameter value is greater than 255 characters. Please check the -name Parameter value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            switch ($net.Gettype().Name) 
            {

                "PSCustomObject" 
                { 
    
                    if ($net -is [PSCustomObject] -and ($net.category -eq "ethernet-networks" -or $net.category -eq "fc-networks" -or $net.category -eq "fcoe-networks")) 
                    {

                        "[{0}] Collecting $($net.type) $($net.name) resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_NetworksToUpdate.Add($net)

                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType 'PSObject' -Message "[$($net.gettype().name)] is an unspported data type. Only [System.String] or [PSCustomObject] or an [Array] of [System.String] or [PSCustomObject] network resources are allowed. Please check the -network Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                    
                }

                "String" 
                { 
                
                    # User provided Network 'name' and 1 or more Appliance Connections
                    if ($net -is [String] -and (-not ($net.StartsWith('/rest/'))))
                    {
                    
                        ForEach ($_appliance in $ApplianceConnection)
                        {

                            "[{0}] Getting '$($net)' resource from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            Try 
                            {

                                $_tempNet = Get-HPOVNetwork $net -type $PSCmdlet.ParameterSetName -ApplianceConnection $_appliance

                            }
                            
                            Catch [HPOneView.NetworkResourceException]
                            {

                                if ($_.CategoryInfo.Category -eq 'ObjectNotFound')
                                {

                                    $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException NetworkResourceNotFound ObjectNotFound 'InputObject' -Message "'$net' Network was not found. Please check the value and try again."
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }
                                
                                else
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                            }
                            
                            if ($_tempNet.count -gt 1)
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException NonUniqueNetworkName InvalidResult 'InputObject' -Message "Multiple '$_tempNet' Network resource found with the same name. Please check the value and try again, or provide the Network Resource Object instead of the name."
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }
                    
                            [void]$_NetworksToUpdate.Add($_tempNet)

                        }
                        
                    }

                    elseif ($net -is [String] -and ($net.StartsWith('/rest/ethernet-networks/') -or $net.StartsWith('/rest/fc-networks/'))) 
                    {
                    
                        "[{0}] Getting '$($net)' resource from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $net = Send-HPOVRequest $net -Appliance $ApplianceConnection

                        }

                        Catch
                        {

                          $PSCmdlet.ThrowTerminatingError($_)

                        }
                                                
                        [void]$NetCollection.Add($net)
                    
                    }
                
                }

            }

        }

    }

    End 
    {

        ForEach ($_net in $_NetworksToUpdate)
        {

            # Set Specific Network Type settings
            switch ($_net.category) 
            {

                "ethernet-networks" 
                {

                    "[{0}] Updating $($_net.name) Ethernet Network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    switch ($PSBoundParameters.keys) 
                    {

                        "purpose" 
                        { 
                        
                            "[{0}] Setting network Purpose to: $purpose" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $_net.purpose = $EthernetNetworkPurposeEnum[$Purpose]
                            
                        }

                        "smartlink" 
                        {

                            "[{0}] Setting smartlink Enabled to: $([Bool]$smartlink)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $_net.smartlink = [Bool]$smartlink

                        }

                        "privateNetwork" 
                        { 

                            "[{0}] Setting privateNetwork Enabled to: $([Bool]$privateNetwork)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $_net.privateNetwork = [Bool]$privateNetwork
                        
                        }

                    }

                }

                "fc-networks" 
                {

                    switch ($PSBoundParameters.keys) 
                    {

                        "LinkStabilityTime" 
                        {

                            "[{0}] Setting LinkStabilityTime to '$LinkStabilityTime' seconds" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if ($_net.fabricType -eq 'DirectAttach')
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidFabricOperation InvalidOperation 'LinkStabilityTime' -TargetType $LinkStabilityTime.Gettype().Name -Message ("Cannot set LinkStabilityTime value to a DirectAttach FibreChannel resource, {0}." -f $_net.name)
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            $_net.linkStabilityTime = [Int]$linkStabilityTime

                        }

                        "AutoLoginRedistribution" 
                        {

                            "[{0}] Setting AutoLoginRedistribution Enabled to: $([Bool]$AutoLoginRedistribution)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if ($_net.fabricType -eq 'DirectAttach')
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidFabricOperation InvalidOperation 'AutoLoginRedistribution' -TargetType $AutoLoginRedistribution.Gettype().Name -Message ("Cannot set AutoLoginRedistribution value to a DirectAttach FibreChannel resource, {0}" -f $_net.name)
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }
                            
                            $_net.autoLoginRedistribution = [Bool]$autoLoginRedistribution

                            if ($_net.linkStabilityTime -eq 0 -and (-not($LinkStabilityTime)) -and [Bool]$AutoLoginRedistribution)
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidLinkStabilityTimeValue InvalidOperation 'AutoLoginRedistribution' -Message ("The '{0}' FC Network resource is a Direct Attach fabric. The Managed SAN resource cannot be modified." -f $_net.name)
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }

                        "managedSan"
                        {

                            if ($_net.fabricType -eq 'DirectAttach')
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.NetworkResourceException InvalidFabricOperation InvalidResult 'Network' -Message ("The '{0}' FC Network resource is a Direct Attach fabric. The Managed SAN resource cannot be modified." -f $_net.name)
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            else
                            {

                                "[{0}] Processing ManagedSAN for FC Network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                Try
                                {

                                    $_net.managedSanUri = (VerifyManagedSan $managedSan $_net.ApplianceConnection.Name)

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                            }
                            
                        }

                    }

                }

                "fcoe-networks"
                {
                    
                    switch ($PSBoundParameters.keys) 
                    {

                        "managedSan"
                        {

                            "[{0}] Processing ManagedSAN for FC Network." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                            $_net.managedSanUri = (VerifyManagedSan $managedSan $_net.ApplianceConnection.Name)
                            
                        }

                    }

                }

            }

            # Shared Parameters for each Network Type
            if ($PSBoundParameters["name"]) 
            {
            
                "[{0}] Updating Network name to '$name'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Validate name Parameter is [String]
                $_net.name = $name
                
            }
    
            if ($PSBoundParameters["prefix"]) 
            {
                
                "[{0}] Updating Network name to include '$prefix' prefix to Network Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Updated Network Name: $($prefix + $_net.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Validate name Parameter is [String]
                $_net.name = $prefix + $_net.name
                
            }
    
            if ($PSBoundParameters["suffix"]) 
            {
                
                "[{0}] Updating Network name to include '$suffix' suffix to Network Name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Updated Network Name: $($_net.name + $suffix)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Validate name Parameter is [String]
                $_net.name += $suffix
                
            }
    
            if ($PSBoundParameters["typicalBandwidth"] -or $PSBoundParameters["maximumBandwidth"]) 
            {
    
                "[{0}] Updating Network bandwidth assignment." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Getting Connection Template resource." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $ct = Send-HPOVRequest $_net.connectionTemplateUri -Appliance $_net.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                } 
                
                if ($PSBoundParameters["maximumBandwidth"]) 
                {
                
                    "[{0}] Original Maximum bandwidth assignment: $($ct.bandwidth.maximumBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] New Maximum bandwidth assignment: $maximumBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ct.bandwidth.maximumBandwidth = $maximumBandwidth
    
                }

                if($PSBoundParameters["typicalBandwidth"]) 
                {
    
                    "[{0}] Original Typical bandwidth assignment: $($ct.bandwidth.typicalBandwidth)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] New Typical bandwidth assignment: $typicalBandwidth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ct.bandwidth.typicalBandwidth = $typicalBandwidth
                    
                }
    
                # "[{0}] Updating Connection Template: $($ct | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $ct = Send-HPOVRequest $ct.uri PUT $ct -Appliance $ct.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
    
            }

            $_net = $_net | Select-Object * -ExcludeProperty defaultTypicalBandwidth, defaultMaximumBandwidth, created, modified

            # "[{0}] Updating Network Resource object: $($_net )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            Try
            {

                $resp = Send-HPOVRequest $_net.uri PUT $_net -Appliance $_net.ApplianceConnection.Name
            
            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [void]$NetCollection.Add($resp)
        
        }
        
        Return $NetCollection

    }

} 

function Update-HPOVLogicalSwitch
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [Alias ('LogicalSwitch')]
        [Alias ('LS')]
        [ValidateNotNullorEmpty()]
        [object]$InputObject,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$Async

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PiplineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
            
        }        

        $_lsobjects   = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        "[{0}] Processing $($InputObject.count) LI objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_logicalswitch in $InputObject) 
        {
            
            if (($_logicalswitch -is [PSCustomObject]) -and ($_logicalswitch.category -ieq 'logical-switches')) 
            {

                "[{0}] Logical Switch Object was provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_logicalswitch.name, $_logicalswitch.uri | Write-Verbose

                [void]$_lsobjects.Add($_logicalswitch)

            }

            else 
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $_li.GetType().Name -Message "An invalid Resource object was provided. $($_li.GetType()) $($_li.category) was provided. Only type String or PSCustomObject, and 'logical-interconnects' object category are permitted."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }

    End 
    {

        # Loop through liobject collection to perform action
        ForEach ($_ls in $_lsobjects)
        {

            "[{0}] Processing Logical Switch: $($_ls.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_ls.name,"Refresh Logical Switch"))
            { 

                Try
                {

                    "[{0}] Sending request to refresh Logical Switch." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                    $uri = $_ls.uri + "/refresh"

                    $_reply = Send-HPOVRequest $uri PUT -Hostname $_ls.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($PSBoundParameters['Async'])
                {

                    $_reply

                }

                else
                {

                    $_reply | Wait-HPOVTaskComplete

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {
                
                "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
        

        }

    }

}

function Get-HPOVSwitch
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Label')]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Label')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_Collection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category=switches'

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            if ($_ResourcesFromIndexCol.count -eq 0 -and $Name) 
            { 

                "[{0}] Switch '{1}' resource not found on appliance {2}. Generating error" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "Specified Switch '{0}' was not found on {1} appliance connection. Please check the name and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord InvalidOperationException SwitchNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)  

            }
            
            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.Networking.Switch')    

                    [void]$_Collection.Add($_member) 

                }

            }

        }

    }

    End 
    {

        "[{0}] Done. {1} switch(es) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Collection.count | Write-Verbose

        if ($exportFile)
        {
            
            $_Collection | convertto-json -Depth 99 | Set-Content -Path $exportFile -force -encoding UTF8 
        
        }
                
        else 
        {
            
            Return $_Collection | Sort-Object name
        
        }

    }

}

#######################################################
# Image Streamer
#

function Get-HPOVImageStreamerAppliance
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ImageStreamerCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $_uri = $AvailableDeploymentServersUri

        if ($Name)
        {

            $_uri = "{0}?filter=name matches '{1}'" -f $_uri, $Name.Replace('*','%25').Replace('?','%26')

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            If ($_appliance.ApplianceType -ne 'Composer')
            {

                $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $_appliance.Name, $_appliance.ApplianceType
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                Try
                {

                    $_CollectionResults = Send-HPOVRequest -uri $_uri -Hostname $_appliance.Name            

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($Name -and -not $_CollectionResults.members)
                {

                    $ExceptionMessage = 'Image Streamer Appliance "{0}" was not found on "{1}" appliance connection.' -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerResourceException ResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                else
                {

                    $_CollectionResults.members | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.ImageStreamerAppliance')
                    
                        $_

                    }

                }

            }
            
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVOSDeploymentServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        $_uri = $DeploymentServersUri

        if ($Name)
        {

            if ($Name.Contains('*'))
            {

                $Name = $Name.Replace("*","%25").Replace("&","%26")

            }

            $_uri = '{0}?filter=name matches "{1}"' -f $_uri, $Name

        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            If ($_appliance.ApplianceType -ne 'Composer')
            {

                $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $_appliance.Name, $_appliance.ApplianceType
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                if ($PSBoundParameters['Label'])
                {

                    $_uri = '{0}?category:deployment-servers&query=labels:{1}' -f $IndexUri, $Label

                    Try
                    {

                        "[{0}] Getting OS Deployment Servers from Index for Label lookup" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_IndexMembers = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                        # Loop through all found members and get full SVT object
                        ForEach ($_member in $_IndexMembers.members)
                        {

                            Try
                            {

                                $_member = Send-HPOVRequest -Uri $_member.uri -Hostname $_appliance

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }                        

                            $_member.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.OSDeploymentServer')

                            $_member

                        }

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                else
                {

                    "[{0}] Getting OS Deployment servers from primary URI" -f $MyInvocation.InvocationName.ToString().ToUpper()| Write-Verbose

                    Try
                    {

                        $_CollectionResults = Send-HPOVRequest -uri $_uri -Hostname $_appliance.Name            

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    if ($Name -and -not $_CollectionResults.members)
                    {

                        $ExceptionMessage = 'OS Deployment Server "{0}" was not found on "{1}" appliance connection.' -f $Name, $_appliance.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerResourceException ResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                        $PSCmdlet.WriteError($ErrorRecord)

                    }

                    else
                    {

                        ForEach ($_DeploymentServer in $_CollectionResults.members)
                        {
                            
                            $_DeploymentServer.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.OSDeploymentServer')

                            $_DeploymentServer

                        }

                    }

                }

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVOSDeploymentServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Alias ('ImageStreamer','I3S')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$ManagementNetwork,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($PipelineInput)
        {

            $ApplianceConnection = $ConnectedSessions | Where-Object Name -eq $ApplianceConnection.Name

        }

        If ($ApplianceConnection.ApplianceType -ne 'Composer')
        {

            $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $ApplianceConnection.Name, $ApplianceConnection.ApplianceType
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Validate the Management Network resource
        if ($ManagementNetwork -is [String])
        {

            "[{0}] ManagementNetwork Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ManagementNetwork | Write-Verbose

            Try
            {

                $ManagementNetwork = Get-HPOVNetwork -Name $ManagementNetwork -Type Ethernet -ApplianceConnection $ApplianceConnection -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Validation rules
        if ($ManagementNetwork.category -ne 'ethernet-networks')
        {

            "[{0}] Unsupported Network: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ManagementNetwork.name | Write-Verbose

            $ExceptionMessage = 'The ManagementNetwork {0} is not a valid "ethernet-network".' -f $ManagementNetwork.name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerManagementNetworkException UnsupportedNetwork InvalidArgument 'ManagementNetwork' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }

        if ([System.String]::IsNullOrWhiteSpace($ManagementNetwork.subnetUri))
        {

            $ExceptionMessage = 'The ManagementNetwork {0} resource is not assigned to a valid IPv4 Address Pool.' -f $ManagementNetwork.name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerManagementNetworkException UnsupportedEthernetNetwork InvalidArgument 'ManagementNetwork' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Get Subnet resource
        Try
        {

            $_ManagementNetworkSubnet = Send-HPOVRequest -Uri $ManagementNetwork.subnetUri -Hostname $ApplianceConnection
            $_ApplianceNetwork        = Send-HPOVRequest -uri $ApplianceNetworkConfigUri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($_ManagementNetworkSubnet.subnetMask -ne $_ApplianceNetwork.applianceNetworks.ipv4Subnet)
        {

            $ExceptionMessage = 'The ManagementNetwork "{0}" resource Subnet Mask "{1}" does not match the appliance Subnet Mask "{2}".' -f $ManagementNetwork.name, $_ManagementNetworkSubnet.subnetMask, $_ApplianceNetwork.applianceNetworks.ipv4Subnet
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerManagementNetworkException UnsupportedEthernetNetwork InvalidArgument 'ManagementNetwork' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not [HPOneView.Appliance.AddressPool]::IsInSameSubnet($_ManagementNetworkSubnet.networkId + '/' + $_ApplianceNetwork.applianceNetworks.ipv4Subnet, $_ApplianceNetwork.applianceNetworks.virtIpv4Addr))
        {

            $ExceptionMessage = "The ManagementNetwork's associated IPv4 Subnet {0} is not local to the appliance. ImageStreamer requires the IPv4 Subnet be on the same NetworkID as the appliance." -f $_ManagementNetworkSubnet.name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerManagementNetworkException UnsupportedEthernetNetwork InvalidArgument 'ManagementNetwork' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Validate InputObject
        if (-not $InputObject.uri.StartsWith($AvailableDeploymentServersUri))
        {

            $ExceptionMessage = 'The InputObject is not a valid ImageStreamer resource.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerManagementNetworkException InvalidInputObject InvalidArgument 'InputObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_AddI3S = NewObject -I3SAdd

        $_AddI3S.description    = $Description
        $_AddI3S.name           = $Name
        $_AddI3S.mgmtNetworkUri = $ManagementNetwork.uri
        $_AddI3S.applianceUri   = $InputObject.uri

        Try
        {

            $_Results = Send-HPOVRequest -Uri $DeploymentServersUri -Method POST -Body $_AddI3S -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_Results | Wait-HPOVTaskComplete

        }

        else
        {

            $_Results

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVOSDeploymentServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($PipelineInput)
        {

            $ApplianceConnection = $ConnectedSessions | Where-Object Name -eq $ApplianceConnection.Name

        }

        If ($ApplianceConnection.ApplianceType -ne 'Composer')
        {

            $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $ApplianceConnection.Name, $ApplianceConnection.ApplianceType
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Validate InputObject
        if ($InputObject.category -ne 'deployment-managers')
        {

            $ExceptionMessage = 'The InputObject is not a valid OS Deployment Server resource.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerManagementNetworkException InvalidInputObject InvalidArgument 'InputObject' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        elseif ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection.Name, ("Remove OS Deployment Server from appliance '{0}'" -f $InputObject.name))) 
        {

            "[{0}] Remove OS Deployment Server '{1}' from appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.ApplianceConnection.Name | Write-Verbose

            $Uri = $InputObject.Uri

            if ($Force)
            {

                $Uri += '?force=true'

            }

            Try
            {

                $_resp = Send-HPOVRequest -Uri $Uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Async'])
            {

                $_resp | Wait-HPOVTaskComplete

            }

            else
            {

                $_resp

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVOSDeploymentPlan
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_OSDeploymentPlanCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            If ($_appliance.ApplianceType -ne 'Composer')
            {

                $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $_appliance.Name, $_appliance.ApplianceType
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                $_Query = [System.Collections.ArrayList]::new()

                # Handle default cause of AllResourcesInScope
                if ($Scope -eq 'AllResourcesInScope')
                {
    
                    "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                    $_Scopes = $ApplianceConnection.ActivePermissions | Where-Object Active
    
                    # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                    if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                    {
    
                        $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                        "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                    }
    
                    # Process ApplianceConnection ActivePermissions collection
                    else
                    {
    
                        Try
                        {
    
                            $_ScopeQuery = Join-Scope $_Scopes
    
                        }
    
                        Catch
                        {
    
                            $PSCmdlet.ThrowTerminatingError($_)
    
                        }
    
                        [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                    }
    
                }
    
                elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
                {
    
                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)
    
                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                elseif ($Scope -eq 'AllResources')
                {
    
                    "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose
    
                }
    
                else
                {
    
                    Try
                    {
    
                        $_ScopeQuery = Join-Scope $Scope
    
                    }
    
                    Catch
                    {
    
                        $PSCmdlet.ThrowTerminatingError($_)
    
                    }
    
                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))
    
                }

                if ($Name)
                {

                    if ($Name.Contains('*'))
                    {

                        [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                    }

                    else
                    {

                        [Void]$_Query.Add(("name:'{0}'" -f $Name))

                    }                
                    
                }

                # if ($Label)
                # {

                # [Void]$_Query.Add(("labels:'{0}'" -f $Label))

                # }

                $_Category = 'category=os-deployment-plans'

                # Build the final URI
                $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

                Try
                {

                    [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($Name -and -not $_ResourcesFromIndexCol)
                {

                    $ExceptionMessage = 'OS Deployment Plan "{0}" was not found on "{1}" appliance connection.' -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ImageStreamerResourceException ResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                else
                {

                    ForEach ($_member in $_ResourcesFromIndexCol)
                    {
                    
                        $_member.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.OSDeploymentPlan')

                        [void]$_OSDeploymentPlanCollection.Add($_member)

                    }

                }                

            }            

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Return $_OSDeploymentPlanCollection

    }

}

function Get-HPOVOSDeploymentPlanAttribute
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_PlanAttributesCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        if ($PipelineInput)
        {

            $ApplianceConnection = $ConnectedSessions | Where-Object Name -eq $ApplianceConnection.Name

        }

        If ($ApplianceConnection.ApplianceType -ne 'Composer')
        {

            $ExceptionMessage = 'The ApplianceConnection {0} ({1}) is not a Synergy Composer. This Cmdlet only support Synergy Composer management appliances.' -f $ApplianceConnection.Name, $ApplianceConnection.ApplianceType
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_OSDeploymentSettingsCollection = New-Object 'HPOneView.ServerProfile.OSDeployment.OsDeploymentPlanParametersCollection[HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter]'

        if ($InputObject.category -eq $ResourceCategoryEnum.ServerProfileTemplate)
        {

            # Process the osDeploymentSettings.osCustomAttributes for plan attributs to return

            ForEach ($_SptDeploymentPlanAttribute in $InputObject.osDeploymentSettings.osCustomAttributes)
            {

                '[{0}] Add {1} = {2} into OsCustomAttributesCollection' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_SptDeploymentPlanAttribute.name, $_SptDeploymentPlanAttribute.value | Write-Verbose

                $_PlanAttribute = New-Object HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter ($_SptDeploymentPlanAttribute.name, $_SptDeploymentPlanAttribute.value)

                [void]$_OSDeploymentSettingsCollection.Add($_PlanAttribute)

            }

        }

        elseif ($InputObject.category -eq 'os-deployment-plans')
        {

            $ExpectedParamForNic = @{
                connectionid = $null;
                dhcp         = $False;
                ipv4disable  = $False;
                networkuri   = $null;
                constraint   = "auto"
            }

            #Build initial collection of Build Plan Parameters
            ForEach ($_PlanAttribute in $InputObject.additionalParameters)
            {

                '[{0}] Attribute name: {1}, type: {2}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PlanAttribute.name, $_PlanAttribute.caType | Write-Verbose

                if ($_PlanAttribute.caType -eq 'nic')
                {

                    ForEach ($AdditionalNicParam in ($ExpectedParamForNic.GetEnumerator() | Sort-Object keys ))
                    {

                        $_ParameterName = '{0}.{1}' -f $_PlanAttribute.name, $AdditionalNicParam.key

                        '[{0}] Add "{1}" NIC "{2}" = "{3}" into OsCustomAttributesCollection' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PlanAttribute.name, $_ParameterName, $AdditionalNicParam.value | Write-Verbose                    

                        $_Attribute = New-Object HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter($_ParameterName, $AdditionalNicParam.value)

                        [void]$_OSDeploymentSettingsCollection.Add($_Attribute)

                    }

                }

                if ([System.Convert]::ToBoolean($_PlanAttribute.caEditable) -and $_PlanAttribute.caType -ne 'nic')
                {

                    '[{0}] Add {1} = {2} into OsCustomAttributesCollection' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PlanAttribute.name, $_PlanAttribute.value | Write-Verbose

                    $_PlanAttribute = New-Object HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter ($_PlanAttribute.name, $_PlanAttribute.value)

                    [void]$_OSDeploymentSettingsCollection.Add($_PlanAttribute)

                }

            }
        }

        $_OSDeploymentSettingsCollection

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Server Profiles:
#

function Get-HPOVServerProfile 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Detailed")]
        [Parameter (Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Export")]
        [Alias ('profile')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ValueFromPipeline = $false, ParameterSetName = "Detailed")]
        [Switch]$Detailed,

        [Parameter (Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Switch]$NonCompliant,

        [Parameter (Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Export")]
        [Switch]$Unassigned,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Export")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Detailed")]
        [Parameter (Mandatory = $false, ParameterSetName = "Export")]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Detailed")]
        [Parameter (Mandatory = $false, ParameterSetName = "Export")]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "Default", ValueFromPipelinebyPropertyName)]
        [Parameter (Mandatory = $false, ParameterSetName = "Detailed", ValueFromPipelinebyPropertyName)]
        [Parameter (Mandatory = $false, ParameterSetName = "Export", ValueFromPipelinebyPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),
        
        [Parameter (Mandatory, ValueFromPipeline = $false, ParameterSetName = "Export")]
        [Alias ("x")]
        [Switch]$export,

        [Parameter (Mandatory, ValueFromPipeline = $false, ParameterSetName = "Export")]
        [ValidateNotNullOrEmpty()]
        [Alias ("save")]
        [String]$location

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Validate the path exists. If not, create it.
        if (($Export) -and (-not(Test-Path $Location)))
        { 
        
            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            New-Item -path $Location -ItemType Directory
        
        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $ProfileCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                "[{0}] Filtering for Label: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Label | Write-Verbose

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            if ($PSBoundParameters['NonCompliant'])
            {

                "[{0}] Filtering for non-compliant profiles." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Void]$_Query.Add("templateCompliance:'NonCompliant'")

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.ServerProfile

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Unassigned']) 
            {

                $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object $null -eq serverHardwareUri

            }

            if ($PSBoundParameters['InputObject'])
            {

                "[{0}] Processing InputObject property." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                switch ($InputObject.category)
                {

                    $ResourceCategoryEnum.ServerHardware
                    {

                        "[{0}] Filtering for Server Hardware resource '{1}' assigned to a server profile." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                        if ($InputObject.serverProfileUri)
                        {
                        
                            "[{0}] Resource is assigned to a server profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object serverHardwareUri -eq $InputObject.uri

                        }

                        else
                        {

                            "[{0}] Resource is not assigned to a server profile. Filtering based on ServerHardwareType" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object serverHardwareTypeUri -eq $InputObject.serverHardwareTypeUri

                        }

                    }

                    $ResourceCategoryEnum.ServerHardwareType
                    {

                        "[{0}] Filtering for Server Hardware Type: {1} [{2}]"  -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.model | Write-Verbose

                        $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object serverHardwareTypeUri -eq $InputObject.uri

                    }

                    $ResourceCategoryEnum.ServerProfileTemplate
                    {

                        "[{0}] Filtering for Server Profile Template: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                        $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object serverProfileTemplateUri -eq $InputObject.uri

                    }

                }

            }

            if ($_ResourcesFromIndexCol.count -eq 0 -and $Name)
            {

                "[{0}] Profile Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $Exceptionmessage = "The specified Server Profile '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerProfileResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            foreach ($_member in $_ResourcesFromIndexCol)
            {
            
                $_member.PSObject.TypeNames.Insert(0,'HPOneView.ServerProfile')
                    
                [void]$ProfileCollection.Add($_member)
                
            }

        }

    }

    End 
    {

        $ProfileCollection = $ProfileCollection | Sort-Object name

        "Done. {0} server profile resource(s) found." -f $ProfileCollection.count | Write-Verbose 

        if ($PSBoundParameters['Detailed']) 
        {

            # Display Pertinant Server Profile data in Table format
            $a1 = @{Expression={$_.name};Label="Name"},
                  @{Expression={$profileCache[$serverHardwareTypeUri]};Label="Server Hardware Type"},
                  @{Expression={ if ($profileCache[$enclosureGroupUri]) {$profileCache[$enclosureGroupUri]}
                                 else { 'N/A' }
                                };Label="Enclosure Group"},
                  @{Expression={    if ($_.serverHardwareUri){ (Send-HPOVRequest -Uri $_.serverHardwareUri ).name }
                                 else { "Unassigned" }
                                 };Label="Assigned"},
                  @{Expression={
                  
                         switch ($_.affinity) {
                  
                             "Bay" { "Device bay" }
                             "BayAndServer" { "Device bay + Server Hardware" }
                  
                  
                         }
                  
                  };Label="Server Affinity"},
                  @{Expression={$_.state};Label="State"},
                  @{Expression={$_.status};Label="Status"}

            $a2 = @{Expression={$_.bios.manageBios};Label="Manage BIOS";align="Left"},
                  @{Expression={$_.boot.manageBoot};Label="Manage Boot Order";align="Left"},
                  @{Expression={$_.firmware.manageFirmware};Label="Manage Firmware";align="Left"},
                  @{Expression={if ($_.serialNumberType -eq "Virtual") { $_.serialNumber + " (v)" } else { $_.serialNumber + " (p)" }};Label="Serial Number"},
                  @{Expression={if ($_.serialNumberType -eq "Virtual") { $_.uuid + " (v)" } else { $_.uuid + " (p)" }};Label="UUID"}


            # Firmware Details
            $f = @{Expression={
                if ($_.firmware.manageFirmware) {

                    $baseline = Send-HPOVRequest $_.firmwareBaselineUri
                    "$($baseline.name) version $($baseline.version)"

                }
                else { "none" }
            
            };Label="Firmware Baseline"}

            $c = @{Expression={$_.id};Label="ID";width=2},
                 @{Expression={$_.functionType};Label="Type";width=12},
                 @{Expression={
                   
                   $address = @()
                 
                   # Mac Address
                   if ($_.macType -eq "Virtual" -and $_.mac) { $address += "MAC $($_.mac) (V)" }
                   elseif ($_.macType -eq "Physical" -and $_.mac) { $address += "MAC $($_.mac) (p)" }
                   
                   # WWNN
                   if ($_.wwpnType -eq "Virtual" -and $_.wwnn) { $address += "WWNN $($_.wwnn) (v)"} 
                   elseif ($_.wwpnType -eq "Physical" -and $_.wwnn) { $address += "WWNN $($_.wwnn) (p)" }
                   
                   # WWPN
                   if ($_.wwpnType -eq "Virtual" -and $_.wwpn) { $address += "WWPN $($_.wwpn) (v)"} 
                   elseif ($_.wwpnType -eq "Physical" -and $_.wwpn) { $address += "WWPN $($_.wwpn) (p)" }

                   $addressCol = $address | Out-String | ForEach-Object { $_ -replace '^\s+|\s+$' }
                   $addressCol
                   
                 };Label="Address";width=32},
                 @{Expression={$profileCache[$_.networkUri]};Label="Network"},
                 @{Expression={$_.portId};Label="Port Id";width=10},
                 @{Expression={[String]$_.requestedMbps};Label="Requested BW";width=12},
                 @{Expression={[String]$_.maximumMbps};Label="Maximum BW";width=10},
                 @{Expression={
                 
                      $bootSetting = @()
                      $bootSetting += $_.boot.priority
                      if ($_.boot.targets) {
                 
                           for ($i=0; $i -eq $boot.targets.count; $i++) { $bootSetting += "WWN $($_.boot.targets[$i].arrayWwpn)`nLUN $($_.boot.targets[$i].lun)" }
                 
                      }
                      $bootSettingString = $bootSetting | Out-String | ForEach-Object { $_ -replace '^\s+|\s+$' }
                      $bootSettingString
                 
                   
                  };Label="Boot";width=20},
                 @{Expression={
                 
                    if ($_.functionType -eq "FibreChannel" -and -not ($_.boot.targets)) { "Yes" } 
                    elseif ($_.functionType -eq "FibreChannel" -and $_.boot.targets) { "No" }
                    else { $Null }
                 
                  };Label="Use Boot BIOS";width=13}
                               
            # Display extEnded BIOS settings
            $b = @{Expression={$_.category};Label="BIOS Category"},
                 @{Expression={$_.settingName};Label="Setting Name"},
                 @{Expression={$_.valueName};Label="Configured Value"}

            $ls = @{Expression={$_.manageLocalStorage};Label="Manage Local Storage";align="Left"},
                  @{Expression={$_.initialize};Label="Initialize Disk";align="Left"},
                  @{Expression={
                  
                        $logicalDriveCol = @()
                        $d=0

                        while ($d -lt $sp.logicalDrives.count) 
                        {

                            if ($_.logicalDrives[$d].bootable) { $logicalDriveCol += "Drive {$d} $($sp.logicalDrives[$d].raidLevel) (Bootable)" }
                            else { $logicalDriveCol += "Drive {$d} $($sp.logicalDrives[$d].raidLevel)" }
                            $d++
                        }

                        $logicalDriveString = $logicalDriveCol | Out-String | ForEach-Object { $_ -replace '^\s+|\s+$' }
                        $logicalDriveString
                    
                   };Label="Logical Disk"}

            $ss = @{Expression={$_.manageSanStorage};Label="Manage SAN Storage";align="Left"},
                  @{Expression={$_.hostOSType};Label="Host OS Type";align="Left"}

            $p = @{Expression={[Int]$_.connectionId};Label="Connection ID";align="Left"},
                 @{Expression={[String]$_.network};Label="Fabric";align="Left"},
                 @{Expression={[String]$_.initiator};Label="Initiator";align="Left"},
                 @{Expression={[String]$_.target};Label="Target";align="Left"},
                 @{Expression={[Bool]$_.isEnabled};Label="Enabled";align="Left"}

            # Server Profile cache
            $profileCache = @{}
            
            # Loop through all Server Profile objects and display details
            ForEach ($profile in ($ProfileCollection | sort-object -property name)) 
            {

                $serverHardwareTypeUri = $profile.serverHardwareTypeUri
                $enclosureGroupUri = $profile.enclosureGroupUri

                # Cache resources during runtime to reduce API calls to appliance.
                if (-not ($profileCache[$serverHardwareTypeUri])) 
                { 

                    Try
                    {

                        $_Sht = Send-HPOVRequest -Uri $serverHardwareTypeUri -appliance $profile.ApplianceConnection.name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                    $profileCache.Add($serverHardwareTypeUri, $_Sht.name) 

                }

                if (-not ($profileCache[$enclosureGroupUri]) -and $profile.enclosureGroupUri) 
                {

                    Try
                    {

                        $_EG = Send-HPOVRequest -Uri $enclosureGroupUri -appliance $profile.ApplianceConnection.name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $profileCache.Add($enclosureGroupUri, $_EG.name) 

                }

                foreach ($connection in $profile.connectionSettings.connections) 
                {
                
                    $connection | ForEach-Object { $_.psobject.typenames.Insert(0,"HPOneView.Profile.Connection") }

                    if (-not ($profileCache[$connection.networkUri])) 
                    { 

                        Try
                        {

                            $_Net = Send-HPOVRequest -Uri $connection.networkUri -appliance $profile.ApplianceConnection.name

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                        
                        $profileCache.Add($connection.networkUri, $_Net.name) 
                    
                    } 
                
                }

                foreach ($volume in $profile.sanStorage.volumeAttachments)
                 {

                    # Insert HPOneView.Profile.SanVolume TypeName
                    $volume | ForEach-Object { $_.psobject.typenames.Insert(0,"HPOneView.Profile.SanVolume") }
    
                    # Cache Storage System, Storage Pool and Storage Volume Resources
                    if (-not ($profileCache[$volume.volumeStorageSystemUri])) { $profileCache.Add($volume.volumeStorageSystemUri,(Send-HPOVRequest $volume.volumeStorageSystemUri $profile.ApplianceConnection.name)) }
                    if (-not ($profileCache[$volume.volumeStoragePoolUri])) { $profileCache.Add($volume.volumeStoragePoolUri,(Send-HPOVRequest $volume.volumeStoragePoolUri $profile.ApplianceConnection.name)) }
                    if (-not ($profileCache[$volume.volumeUri])) { $profileCache.Add($volume.volumeUri,(Send-HPOVRequest $volume.volumeUri $profile.ApplianceConnection.name)) }

                }

                #$profileCache

                # Initial Server Profile information
                $profile | format-table $a1 -AutoSize -wrap
                $profile | format-table $a2 -AutoSize -wrap

                # Firmware Baseline
                $profile.firmware | format-table $f

                # Server Profile Connection details
                $profile.connectionSettings.connections | format-table -wrap
                
                # Local Storage
                $profile.localStorage | format-table $ls -wrap -auto

                # SAN Storage
                $profile.sanStorage | Format-Table $ss -auto
                #$profile.sanStorage.volumeAttachments | format-table -auto

                $profile.sanStorage.volumeAttachments | ForEach-Object {

                    $_ | format-table -auto

                    $pathConnectionCol = @()

                    foreach ($path in $_.storagePaths) 
                    {

                        $pathObject = [PSCustomObject]@{
                            connectionId = $Null; 
                            network      = $Null; 
                            initiator    = $Null; 
                            target       = $Null; 
                            isEnabled    = $Null
                        }

                        $pathConnection = $profile.connectionSettings.connections | Where-Object { $path.connectionId -eq $_.id }

                        $pathObject.connectionId = $pathConnection.id
                        $pathObject.network      = $profileCache[$pathConnection.networkUri]
                        $pathObject.initiator    = $pathConnection.wwpn
                        $pathObject.target       = if ($path.storageTargets) { $path.storageTargets }
                                                   else { "PEnding" }
                        $pathObject.isEnabled    = [Bool]$path.isEnabled
                        $pathConnectionCol += $pathObject

                    }

                    #
                    # Display path details with a left padded view. Format-Table doesn't have the ability to pad the display
                    $capture = ($pathConnectionCol | Sort-Object connectionId | format-table $p -AutoSize -wrap | out-string) -split "`n"
                    $capture | ForEach-Object { ($_).PadLeft($_.length + 5) }

                }

                #Boot Order
                $bootOrder = @()
                if ($profile.boot.manageBoot) 
                {

                    $i = 0
                    while ($i -lt $profile.boot.order.count) 
                    {
                        $bootOrder += "$($i+1) $($profile.boot.order[$i])"
                        $i++
                    }
                    "Boot Order"
                    "----------"
                    $bootOrder

                }
                else 
                { 

                    "No Boot Management" 
                
                }

                # Display configured BIOS Settings from profile
                $configedBiosSettings = @()

                foreach ($setting in $profile.bios.overriddenSettings) 
                {

                    $shtBiosSettingDetails = $profileCache[$serverHardwareTypeUri].biosSettings | Where-Object { $setting.id -eq $_.id }

                    $biosSetting = [PSCustomObject]@{

                        Category = $shtBiosSettingDetails.category;
                        settingName = $shtBiosSettingDetails.name;
                        valueName = ($shtBiosSettingDetails.options | Where-Object { $_.id -eq $setting.value } ).name;

                    }

                    $configedBiosSettings += $biosSetting
                
                }            
            
                $configedBiosSettings | Sort-Object category,settingName | format-table $b

                "----------------------------------------------------------------------"
            
            }

        }

        # If user wants to export the profile configuration
        elseif ($export) 
        {

            # Get the unique applianceConnection.name properties from the profile collection for grouping the output files
            $ProfileGroupings = $ProfileCollection.ApplianceConnection.name | Select-Object -Unique

            ForEach ($pg in $ProfileGroupings)
            {
                
                $outputProfiles = [System.Collections.ArrayList]::new()

                $profiles = $ProfileCollection | Where-Object {$_.ApplianceConnection.Name -eq $pg}

                # Loop through all profiles
                foreach ($profile in $profiles) 
                {

                    # Trim out appliance unique properties

                    $_profile = $profile | select-object -Property * -excludeproperty uri,etag,created,modified,status,state,inprogress,enclosureUri,enclosureBay,serverHardwareUri,taskUri,ApplianceConnection
                    $_profile.serialNumberType = "UserDefined"

                    # Loop through the connections to save the assigned address
                    $i = 0
                    foreach ($connection in $profile.connectionSettings) 
                    {

                        if ($profile.connectionSettings.connections[$i].mac) 
                        { 
                            
                            $_profile.connectionSettings.connections[$i].macType = "UserDefined" 
                        
                        }

                        if ($profile.connectionSettings.connections[$i].wwpn) 
                        { 
                            
                            $_profile.connectionSettings.connections[$i].wwpnType = "UserDefined" 
                        
                        }
                        
                        $i++

                    }

                    [void]$outputProfiles.Add($_profile)
                    
                }

                # Save profile to JSON file
                "[{0}] Saving $($_profile.name) to $($location)\$($_profile.name).json" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                convertto-json -InputObject $outputProfiles -depth 99 | new-item "$location\$pg`_$($_profile.name).json" -itemtype file

            }

        }

        else 
        {

            Return $ProfileCollection

        }

    }

}

function New-HPOVServerProfile 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [ValidateSet ("Bay", "Server", "Unassigned")]
        [Alias ('assign')]
        [String]$AssignmentType = 'Server',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [object]$Enclosure,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateRange(1,16)]
        [Alias ('bay')]
        [int32]$EnclosureBay,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "SPT")]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Import")]
        [ValidateNotNullOrEmpty()]
        [object]$Server,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")] 
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [String]$Description,

        [Parameter (Mandatory, ParameterSetName = "SPT")]
        [Object]$ServerProfileTemplate,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [array]$Connections,

        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$FCConnectionAddresses,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Alias ('eg')]
        [object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Alias ('sht')]
        [object]$ServerHardwareType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Firmware,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [object]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Alias ('FirmwareMode')]
        [ValidateSet ('FirmwareOnly', 'FirmwareAndSoftware', 'FirmwareOffline', 'FirmwareAndOSDrivers', 'FirmwareOnlyOfflineMode')]
        [String]$FirmwareInstallMode = 'FirmwareAndSoftware',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateSet ('Immediate', 'Scheduled', 'NotScheduled')]
        [String]$FirmwareActivationMode = 'Immediate',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$FirmwareActivateDateTime,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Switch]$ForceInstallFirmware,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Bios = $false,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [array]$BiosSettings = @(),
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]        
        [ValidateSet ("UEFI","UEFIOptimized","BIOS",'Unmanaged', IgnoreCase = $False)]
        [String]$BootMode = "BIOS",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]        
        [ValidateSet ("Auto","IPv4","IPv6","IPv4ThenIPv6","IPv6ThenIPv4", IgnoreCase = $False)]
        [String]$PxeBootPolicy = "Auto",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Alias ('boot')]
        [Switch]$ManageBoot,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [array]$BootOrder,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Unmanaged", "Enabled", "Disabled", IgnoreCase = $False)]
        [String]$SecureBoot = 'Unmanaged',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Switch]$LocalStorage,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Alias ('LogicalDisk')]
        [ValidateNotNullorEmpty()]
        [Object]$StorageController,

        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [Switch]$SANStorage,

        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('CitrixXen','CitrixXen7','AIX','IBMVIO','RHEL4','RHEL3','RHEL','RHEV','RHEV7','VMware','Win2k3','Win2k8','Win2k12','Win2k16','OpenVMS','Egenera','Exanet','Solaris9','Solaris10','Solaris11','ONTAP','OEL','HPUX11iv1','HPUX11iv2','HPUX11iv3','SUSE','SUSE9','Inform', IgnoreCase = $true)]
        [Alias ('OS')]
        [String]$HostOStype,

        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullorEmpty()]
        [object]$StorageVolume,

        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias ('Even')]
        [Switch]$EvenPathDisabled,

        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias ('Odd')]
        [Switch]$OddPathDisabled,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Bay","BayAndServer", IgnoreCase = $false)]
        [String]$Affinity = "Bay",
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateSet ("Virtual", "Physical", "UserDefined", IgnoreCase)]
        [String]$MacAssignment = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateSet ("Virtual", "Physical", "'UserDefined", IgnoreCase)]
        [String]$WwnAssignment = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateSet ("Virtual", "Physical", "UserDefined", IgnoreCase)]
        [String]$SnAssignment = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [String]$Uuid,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [Bool]$HideUnusedFlexNics = $True,

        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [Array]$IscsiIPv4Address,

        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateScript ({[RegEx]::Match($_,$iQNPattern).Success})]
        [String]$ISCSIInitatorName,

        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$ChapSecret,

        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$MutualChapSecret,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Object]$OSDeploymentPlan,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Array]$OSDeploymentAttributes,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "SPT")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "SPT")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Import")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory, ParameterSetName = "Import")]
        [Switch]$Import,
        
        [Parameter (Mandatory, ParameterSetName = "Import", ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [Alias ("location","file")]
        [Object]$ProfileObj,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Parameter (Mandatory = $false, ParameterSetName = "SPT")]
        [Switch]$Passthru

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSBoundParameters['Bootable'])
        {

            Write-Warning 'The -Bootable Parameter has been deprecated. In order to configure local storage, please read Help New-HPOVServerProfile and the LocalDisk Parameter.'

        }

        if ($PSBoundParameters['RaidLevel'])
        {

            Write-Warning 'The -RaidLevel Parameter has been deprecated. In order to configure local storage, please read Help New-HPOVServerProfile and the LocalDisk Parameter.'

        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if (-not($PSBoundParameters['ServerProfileTemplate']))
        {

            if ($snAssignment -eq "UserDefined" -and (-not($serialnumber)) -and (-not($uuid))) 
            {
        
                $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'snAssignment' -Message "The -snAssignment paramter was set to 'UserDefined', however both -serialnumber and -uuid are Null. You must specify a value for both Parameters."
        
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
            }
        
            elseif ($snAssignment -eq "UserDefined" -and $serialnumber -and (-not($uuid))) 
            {
        
                $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'uuid' -Message "The -snAssignment paramter was set to 'UserDefined', however -uuid is Null. You must specify a value for both Parameters."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($snAssignment -eq "UserDefined" -and (-not($serialnumber)) -and $uuid) 
            {
            
                $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'serialnumber' -Message "The -snAssignment paramter was set to 'UserDefined', however -serialnumber is Null. You must specify a value for both Parameters."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
        
            }

            # Update the error information
            switch ($AssignmentType) 
            { 

                "server" 
                {

                    if (-not($server))
                    {
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'Server' -Message "The -AssignmentType Parameter is set to 'server', but no server Parameter was supplied."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                "bay" 
                {

                    if (-not($enclosureBay))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'AssignmentType' -Message "The -AssignmentType Parameter is set to 'bay', but no bay Parameter was supplied."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if (-not($enclosure))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'AssignmentType' -Message "The -AssignmentType Parameter is set to 'bay', but no Enclosure Parameter was supplied."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if (-not($ServerHardwareType))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'AssignmentType' -Message "The -AssignmentType Parameter is set to 'bay', but no ServerHardwareType Parameter was supplied."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($ApplianceConnection.Count -gt 1)
                    {

                        if($enclosure -is [String] -and $enclosure.StartsWith("/rest"))
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'Enclosure' -Message "Enclosure as URI is not supported for multiple appliance connections."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                }

                "unassigned" 
                {
                
                    # If the profile is not based on a template, the SHT is required
                    if ((-not($PSBoundParameters['Template'])) -and (-not($PSBoundParameters['ServerHardwareType'])))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'ServerHardwareType' -Message "The -AssignmentType Parameter is set to 'unassigned', but no server hardware type was supplied."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($PSBoundParameters['Server'])
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfileResourceException InvalidArgument InvalidArgument 'ServerHardwareType' -Message "The -AssignmentType Parameter is set to 'unassigned', and a Server object/name was provided. You cannot both assign and unassign a Server Profile."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            # Check for URI values in Parameters and validate that only one appliance connection is provided in the call
            if($ApplianceConnection.Count -gt 1)
            {
            
                # SHT
                if($serverHardwareType -is [String] -and $serverHardwareType.StartsWith($ServerHardwareTypesUri))
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Server Hardware Type as URI is not supported for multiple appliance connections"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                }
            
                if($serverHardwareType -is [String] -and $serverHardwareType.StartsWith("/rest"))
                {
            
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Server Hardware Type as URI is not supported for multiple appliance connections."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                }

                # EG
                if(($enclosureGroup -is [String] -and $enclosureGroup.StartsWith("/rest")))
                {
            
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Enclosure Group as URI is not supported for multiple appliance connections."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                }

                # Server
                if ($server -is [String] -and $server.StartsWith("/rest")) 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Server as URI is not supported for multiple appliance connections."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                }

                #Baseline
                if (($baseline -is [String]) -and ($baseline.StartsWith('/rest'))) 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Baseline as URI is not supported for multiple appliance connections."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                }

                # Import
                if($Import) 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Import functionality is not supported for multiple appliance connections."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        if ($PSBoundParameters['IscsiIPv4Address'])
        {

            $_TmpCollection = [System.Collections.ArrayList]::new()

            $IscsiIPv4Address | ForEach-Object { [void]$_TmpCollection.Add($_) }

            $IscsiIPv4Address = $_TmpCollection.Clone()

        }    

        $uri = $ServerProfilesUri

        $colStatus = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        if ($AssignmentType -eq 'Server' -and -not $Server)
        {

            $ExceptionMessage = 'A Server resource object or name must be provided when using the "Server" AssignmentType parameter.'
            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException NullServerNotAllowed InvalidArgument 'Server' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Import Server Profile JSON to appliance
        if ($PSBoundParameters['Import']) 
        {

            "[{0}] Import server profile" -f $($MyInvocation.InvocationName.ToString().ToUpper()) | Write-Verbose

            if (($ProfileObj -is [System.String]) -and (Test-Path $ProfileObj)) 
            {

                # Received file location
                "[{0}] Received JSON file as input: {1}" -f $($MyInvocation.InvocationName.ToString().ToUpper()), $ProfileObj | Write-Verbose
            
                $ServerProfile = (get-content $ProfileObj) -join "`n" | convertfrom-json
                
                # Remove unique values with Select-Object
                $ServerProfile = $ServerProfile | Select-Object * -Exclude uri,created,modified,eTag,ApplianceConnection

            }

            # Input object could be the JSON object, which is type [System.String]
            elseif ($ProfileObj -is [System.String]) 
            {

                "[{0}] Received JSON resource object as input {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($ProfileObj | out-string) | Write-Verbose
                
                $ServerProfile = $ProfileObj -join "`n" | convertfrom-json

            }

            # Input object is PsCustomObject of a Server Profile
            elseif ($ProfileObj -is [PsCustomObject]) 
            {

                "[{0}] Received JSON PsCustomObject as input {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($ProfileObj | out-string) | Write-Verbose

                $ServerProfile = $ProfileObj.PSObject.Copy()

            }

            # Inavlid input type for $ProfileObj and Generate Terminating Error
            else 
            { 

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidImportObject InvalidArgument 'ProfileObj' -Message "Invalid `$Import input object. Please check the object you provided for ProfileObj Parameter and try again"
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }

        else
        {

            if ($PSBoundParameters['ServerProfileTemplate'])
            {

                # Validate ServerProfileTemplate Parameter value
                switch ($ServerProfileTemplate.GetType().Name)
                {

                    'PSCustomObject'
                    {

                        "[{0}] Received PSCustomObject for ServerProfileTemplate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] Resource Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfileTemplate.name | Write-Verbose

                        "[{0}] Resource Category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfileTemplate.category | Write-Verbose

                        if ($ServerProfileTemplate.category -ne $ResourceCategoryEnum.ServerProfileTemplate)
                        {

                            $ExceptionMessage = "Invalid ServerProfileTemplate input object. The input object category '{0}' is not the expected value '{1}'. Please check the value and try again." -f $ServerProfileTemplate.category, $ResourceCategoryEnum.ServerProfileTemplate
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileTemplateResourceException InvalidServerProfileTemplateObject InvalidArgument 'ServerProfileTemplate' -TargetType 'PSObject' -Message $ExceptionMessage

                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    # Validate the String data value
                    'String'
                    {

                        if ($ServerProfileTemplate.StartsWith($ServerProfileTemplatesUri))
                        {

                            "[{0}] Resource URI Received. Getting resource object from API." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $ServerProfileTemplate = Send-HPOVRequest -Uri $ServerProfileTemplate -Hostname $ApplianceConnection.Name

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                        else
                        {

                            "[{0}] Resource Name Received." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            Try
                            {

                                $ServerProfileTemplate = Get-HPOVServerProfileTemplate -Name $ServerProfileTemplate -ApplianceConnection $ApplianceConnection.Name -ErrorAction Stop

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                        }

                    }
                    
                }

                "[{0}] Requesting new Server Profile from API." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $ServerProfile = Send-HPOVRequest -Uri ($ServerProfileTemplate.uri + "/new-profile") -Hostname $ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $ServerProfile = $ServerProfile | Select-Object * -ExcludeProperty templateCompliance,uri,taskUri,inProgress,state,status,modified,created,associatedServer,eTag,category

                # If there are existing connections, handle the iSCSI ones for IPAddress and CHAP password
                if ($ServerProfile.connectionSettings.connections)
                {

                    # Rebuild Connections into an ArrayList
                    $_TmpConnections = $ServerProfile.connectionSettings.connections.Clone()

                    $ServerProfile.connectionSettings.connections = [System.Collections.ArrayList]::new()

                    ForEach ($_con in $_TmpConnections)
                    {

                        [void]$ServerProfile.connectionSettings.connections.Add($_con)

                    }

                    # ForEach ($_conn in $ServerProfile.connections)
                    For ([Int]$c = 0; $c -lt $ServerProfile.connectionSettings.connections.Count; $c++) 
                    {

                        # Perform Param validation
                        if ($ServerProfile.connectionSettings.connections[$c].functionType -eq 'iSCSI')
                        {

                            # ISCSI Connection is Bootable
                            if ($ServerProfile.connectionSettings.connections[$c].boot.priority -ne 'NotBootable')
                            {

                                # An IPv4 Address was not provided, generate error
                                if (-not($PSBoundParameters['IscsiIPv4Address']) -and $ApplianceConnection.Type -ne 'Composer')
                                {

                                    $Message     = 'Connection ID {0} is configured for {1}, but the -IscsiIPv4Address Parameter was not provided. Please specify an IPv4Address in your command.' -f $ServerProfile.connections[$c].id , $ServerProfile.connections[$c].boot.priority
                                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException IscsiIPv4AddressParamRequired InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Message
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                                }

                                # This is NOT an error, do don't generate one. Set initiatorNameSource -> UserDefined, and also need to set Profile to
                                if ($PSBoundParameters['ISCSIInitatorName'])
                                {

                                    $ServerProfileTemplate.iscsiInitiatorNameType                              = 'UserDefined'
                                    $ServerProfile.connectionSettings.connections[$c].boot.initiatorName       = $ISCSIInitatorName
                                    $ServerProfile.connectionSettings.connections[$c].boot.initiatorNameSource = 'UserDefined'

                                }

                                switch ($ServerProfile.connectionSettings.connections[$c].boot.chapLevel)
                                {

                                    'Chap'
                                    {

                                        if (-not($PSBoundParameters['ChapSecret']))
                                        {

                                            $Message     = 'Connection ID {0} is configured for "CHAP" Authentication, but the -ChapSecret Parameter was not provided.' -f $ServerProfile.connections[$c].id 
                                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException ChapSecretParamRequired InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Message
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                                        }

                                        $ServerProfile.connectionSettings.connections[$c].boot.chapPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ChapSecret))

                                    }

                                    'MutualChap'
                                    {

                                        if (-not($PSBoundParameters['ChapSecret']))
                                        {

                                            $Message     = 'Connection ID {0} is configured for "CHAP" Authentication, but the -ChapSecret Parameter was not provided.'
                                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException ChapSecretParamRequired InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Message
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                                        }

                                        if (-not($PSBoundParameters['MutualChapSecret']))
                                        {

                                            $Message     = 'Connection ID {0} is configured for "MutualChap" Authentication, but the -MutualChapSecret Parameter was not provided.'
                                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException MutualChapSecretParamRequired InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Messag
                                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                                        }

                                        $ServerProfile.connectionSettings.connections[$c].boot.chapSecret       = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ChapSecret))
                                        $ServerProfile.connectionSettings.connections[$c].boot.mutualChapSecret = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($MutualChapSecret))

                                    }

                                }

                                if ($IscsiIPv4Address.count -gt 0)
                                {

                                    "[{0}] Assigning {1} IPv4Address to Connection ID {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $IscsiIPv4Address[0], $ServerProfile.connections[$c].id | Write-Verbose

                                    $_IPv4Address = $IscsiIPv4Address[0]

                                    [void]$IscsiIPv4Address.Remove($_IPv4Address)

                                    $ServerProfile.connectionSettings.connections[$c].boot.initiatorIp = $_IPv4Address

                                }

                                else
                                {

                                    $Message = 'Connection ID {0} is configured as a Bootable iSCSI Connection, however no additional IPv4Address is available to allocate.' -f $ServerProfile.connections[$c].id
                                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException MutualChapSecretParamRequired InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Messag
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                                }

                            }

                        }

                        elseif ($ServerProfile.connectionSettings.connections[$c].functionType -eq 'FibreChannel')
                        {

                            if (-not $PSBoundParameters['FCConnectionAddresses'])
                            {

                                # Generate warning message that unmanaged connections were found and no addresses were provided
                                
                            }

                            else
                            {

                                "[{0}] Setting connection id '{1}' to '{2}' WWPN address." -f $MyInvocation.InvocationName.ToString().ToUpper(), $FCConnectionAddresses.$c.Name, $FCConnectionAddresses.$c.Value | Write-Verbose

                                $ServerProfile.connectionSettings.connections[$c].wwpn = $FCConnectionAddresses.$c.Value

                            }

                        }

                    }

                }

                else
                {

                    $ServerProfile.connectionSettings.connections = [System.Collections.ArrayList]::new()

                }

                # Handle firmware differently
                if ($ServerProfile.firmware.manageFirmware -and $ServerProfile.firmware.firmwareActivationType -eq 'Scheduled')
                {

                    $ServerProfile.firmware.forceInstallFirmware = [Bool]$ForceInstallFirmware

                    if ($PSBoundParameters['FirmwareInstallMode'])
                    {

                        "[{0}] Overriding SPT Firmware Install Type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfileFirmwareControlModeEnum[$FirmwareInstallMode] | Write-Verbose
                        $ServerProfile.firmware.firmwareInstallType = $ServerProfileFirmwareControlModeEnum[$FirmwareInstallMode]
                
                    }

                    if ($PSBoundParameters['FirmwareActivationMode'])
                    {

                        $ServerProfile.firmware.firmwareActivationType = $ServerProfileFirmareActivationModeEnum[$FirmwareActivationMode]

                    }

                    if ('FirmwareOffline', 'FirmwareOnlyOfflineMode' -contains $ServerProfile.firmware.firmwareActivationType -and $PSBoundParameters['FirmwareActivateDateTime'])
                    {

                        $ExceptionMessage = "The Server Profile Template is not configured to schedule firmware activation, and the use of -FirmwareActivationDateTime parameter is not supported. Please choose a different Server Profile Template with Online updates, or overrride using the -FirmwareInstallMode parameter."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidFirmwareInstallMode InvalidArgument 'FirmwareActivateDateTime' -TargetType 'Switch' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                    elseif ($ServerProfile.firmware.firmwareActivationType -eq 'Scheduled' -and -not $PSBoundParameters['FirmwareActivateDateTime'])
                    {

                        $ExceptionMessage = "The Server Profile Template provided is set to schedule firmware activation, which requires the -FirmwareActivateDateTime parameter."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidFirmwareInstallMode InvalidArgument 'FirmwareActivateDateTime' -TargetType 'Switch' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                    elseif ($ServerProfile.firmware.firmwareActivationType -eq 'Scheduled' -and $PSBoundParameters['FirmwareActivateDateTime'])
                    {

                        # Convert DateTime to UTC time for the appliance
                        "[{0}] Setting firmware activation schedule: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $FirmwareActivateDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") | Write-Verbose
                        $ServerProfile.firmware.firmwareScheduleDateTime = $FirmwareActivateDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")

                    }    

                }

                # Get SHT from Template
                # Get the SHT of the SH that we are going to assign.
                Try
                {

                    $ServerHardwareType = Send-HPOVRequest -Uri $ServerProfile.serverHardwareTypeUri -appliance $ApplianceConnection

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($ServerProfile.enclosureGroupUri)
                {

                    Try
                    {

                        $EnclosureGroup = Send-HPOVRequest -Uri $ServerProfile.enclosureGroupUri -appliance $ApplianceConnection

                    }
                    
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                # Process OSDeploymentAttributes for SP from SPT
                # Do we need to first look at the osDeploymentSettings at all for Constraints?
                if ($PSBoundParameters['OSDeploymentAttributes'])
                {

                    If ($ApplianceConnection.ApplianceType -ne 'Composer')
                    {

                        $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. The OSDeploymentAttributes parameter is only supported with HPE Synergy and HPE ImageStreamer.' -f $ApplianceConnection.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    ForEach ($_PlanAttribute in $ServerProfile.osDeploymentSettings.osCustomAttributes)
                    {

                                    if (($ServerProfile.osDeploymentSettings.osCustomAttributes | Where-Object { $_.Name -match ('{0}.constraint' -f $_PlanAttribute.name)}) -and 'Auto', 'DHCP' -notcontains $_PlanAttribute.value -and -not ($OSDeploymentAttributes | Where-Object name -eq $_PlanAttribute.name))
                        {

                            $ExceptionMessage = 'The attribute {0} requires a value and is not provided in the OSDeploymentAttributes.' -f $_PlanAttribute.name
                            $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.OSDeploymentAttributeResourceException InvalidOperation InvalidArgument 'OSDeploymentAttributes' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                        }

                        '[{0}] Setting {1} attribute to {2}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PlanAttribute.name, ($OSDeploymentAttributes | Where-Object name -eq $_PlanAttribute.name).value | Write-Verbose

                        ($ServerProfile.osDeploymentSettings.osCustomAttributes | Where-Object name -eq $_PlanAttribute.name).value = ($OSDeploymentAttributes | Where-Object name -eq $_PlanAttribute.name).value

                    }

                }

            }

            else
            {

                "[{0}] Get generic Server Profile object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                # New Server Resource Object
                $ServerProfile = NewObject -ServerProfile
                
                $ServerProfile.affinity           = $Affinity
                $ServerProfile.hideUnusedFlexNics = [Bool]$HideUnusedFlexNics
                $ServerProfile.bios.manageBios    = [Bool]$Bios
                $ServerProfile.boot.manageBoot    = $ManageBoot.IsPresent
                $ServerProfile.boot.order         = $BootOrder
                

                # Process OSDeploymentPlan
                if ($PSBoundParameters['OSDeploymentPlan'])
                {

                    If ($ApplianceConnection.ApplianceType -ne 'Composer')
                    {

                        $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. The OSDeploymentPlan parameter is only supported with HPE Synergy and HPE ImageStreamer.' -f $ApplianceConnection.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($OSDeploymentPlan.type -ne 'Osdp')
                    {

                        $ExceptionMessage = 'The provided OSDeploymentPlan parameter value is not a valid OS Deployment Plan resource.' -f $ApplianceConnection.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.OSDeploymentPlanResourceException InvalidOperation InvalidArgument 'OSDeploymentPlan' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                    }

                    $_OSDeploymentSettings = NewObject -OSDeploymentSettings
                    $_OSDeploymentSettings.osDeploymentPlanUri = $OSDeploymentPlan.uri

                    ForEach ($_PlanAttribute in $OSDeploymentAttributes)
                    {

                        if ($_PlanAttribute -isnot [HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter])
                        {

                            $ExceptionMessage = 'The provided OSDeploymentAttribute parameter value is not a valid resource.' -f $ApplianceConnection.Name
                            $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.OSDeploymentAttributeResourceException InvalidOperation InvalidArgument 'OSDeploymentAttributes' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }                        

                        $_PlanAttributeSetting = NewObject -OSDeploymentPlanSetting
                        $_PlanAttributeSetting.name  = $_PlanAttribute.name
                        $_PlanAttributeSetting.value = $_PlanAttribute.value

                        '[{0}] Setting {1} attribute to {2}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PlanAttribute.name, $_PlanAttribute.value | Write-Verbose

                        [void]$_OSDeploymentSettings.osCustomAttributes.Add($_PlanAttributeSetting)

                    }

                    $ServerProfile | Add-Member -NotePropertyName osDeploymentSettings -NotePropertyValue $null -Force

                    $ServerProfile.osDeploymentSettings = $_OSDeploymentSettings

                }

            }

            if ('Unassigned', 'Bay' -Contains $AssignmentType) 
            {
            
                "[{0}] Profile assignmentType: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $AssignmentType | Write-Verbose 
            
                # Check to see if the serverHardwareType is null, and generate error(s) then break.
                if (-not $ServerHardwareType)
                {

                    $ExceptionMessage = "Server Hardware Type is missing. Please provide a Server Hardware Type using the -sht Parameter and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'ServerHardwareType' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
            
                # If the URI is passed as the Server Hardware Type, then set the serverHardwareTypeUri variable
                If ($ServerHardwareType -is [String])
                {

                    if ($ServerHardwareType.StartsWith($ServerHardwareTypesUri))
                    { 
                        
                        "[{0}] SHT URI Provided: {1}"  -f $($MyInvocation.InvocationName.ToString().ToUpper()), $ServerHardwareType | Write-Verbose 

                        Try
                        {
                        
                            $ServerHardwareType = Send-HPOVRequest -Uri $ServerHardwareType -appliance $ApplianceConnection
                        
                        }
                        
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }
                
                    # Otherwise, perform a lookup ofthe SHT based on the name
                    else 
                    {

                        "[{0}] SHT Name Provided: {1}"  -f $($MyInvocation.InvocationName.ToString().ToUpper()), $ServerHardwareType | Write-Verbose 

                        Try
                        {

                            $ServerHardwareType = Get-HPOVServerHardwareType -name $ServerHardwareType -ErrorAction Stop -ApplianceConnection $ApplianceConnection

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                }

                # Else the SHT object is passed
                elseif ($ServerHardwareType)
                { 

                    $ServerHardwareType = $ServerHardwareType | Where-Object { $_.ApplianceConnection.name -eq $ApplianceConnection.name }

                    "[{0}] ServerHardwareType object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                    "[{0}] ServerHardwareType Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.name | Write-Verbose 
                    "[{0}] ServerHardwareType Uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.uri | Write-Verbose 
                    
                }

                if (-not($PSBoundParameters['EnclosureGroup']) -and (-not($ServerHardwareType.model -match "DL")) -and $AssignmentType -eq 'unassigned' -and $null -eq $ServerProfileTemplate)
                {
                        
                    $ExceptionMessage = "Enclosure Group is missing. Please provide an Enclosure Group using the -EnclosureGroup Parameter and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureGroupObject InvalidArgument 'EnclosureGroup' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif ($PSBoundParameters['EnclosureGroup'] -is [String] -and $AssignmentType -eq 'unassigned')
                {

                    # If the URI is passed as the Enclosure Group, then set the enclosureGroupUri variable
                    if ($EnclosureGroup.StartsWith('/rest'))
                    { 
                        
                        Try
                        {

                            $EnclosureGroup = Send-HPOVRequest -Uri $EnclosureGroup -appliance $ApplianceConnection

                        }
                        
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                    
                    }

                    # Otherwise, perform a lookup ofthe Enclosure Group
                    else
                    {

                        Try
                        {

                            $EnclosureGroup = Get-HPOVEnclosureGroup -name $EnclosureGroup -ErrorAction Stop -appliance $ApplianceConnection

                        }
                        
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }
                        
                    }

                    "[{0}] EG URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup.uri | Write-Verbose

                }
                        
                # Else the EG object is passed
                elseif (($EnclosureGroup -is [Object]) -and ($EnclosureGroup.category -eq "enclosure-groups") -and $AssignmentType -eq 'unassigned') 
                { 

                    $EnclosureGroup = $EnclosureGroup | Where-Object { $ApplianceConnection.name -eq $_.applianceConnection.name }

                    "[{0}] Enclosure Group object provided" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup.name | Write-Verbose
                    "[{0}] Enclosure Group Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup.name | Write-Verbose
                    "[{0}] Enclosure Group Uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnclosureGroup.uri | Write-Verbose

                }

                elseif (-not $EnclosureGroup -and ($ServerHardwareType.platform -eq "RackServer")) 
                {

                    "[{0}] Server is a ProLiant DL model. Enclosure Group not required." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                # EG Param not required if assignment is to a bay
                elseif (-not $PSBoundParameters['EnclosureGroup'] -and $AssignmentType -eq 'bay')
                {

                    # First check for $enclosure Param
                    if (-not $PSBoundParameters['Enclosure'])
                    {

                        $ExceptionMessage = "Enclosure parameter is missing. Please provide an Enclosure using the -enclosure Parameter and try again."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureObject InvalidArgument 'Enclosure' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                    
                    # Retrieve the enclosure group uri from passed in enclosure uri Param
                    elseif($Enclosure -is [String]) 
                    {
                        
                        if($Enclosure.StartsWith('/rest'))
                        { 
                                    
                            try 
                            {

                                $Enclosure = Send-HPOVRequest -Uri $Enclosure -appliance $ApplianceConnection

                            }

                            catch 
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureGroupObject InvalidArgument 'Enclosure' -Message "Enclosure is missing. Please provide an Enclosure using the -enclosure Parameter and try again."
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                            }

                        }

                        # Enclosure is a name
                        else
                        {

                            try 
                            {

                                $Enclosure = Get-HPOVEnclosure -Name $Enclosure -ErrorAction Stop -appliance $ApplianceConnection
                                
                            }

                            catch 
                            {

                                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureGroupObject InvalidArgument 'Enclosure' -Message "Enclosure is missing. Please provide an Enclosure using the -enclosure Parameter and try again."
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }

                    }

                    elseif ($Enclosure -is [object] -and $Enclosure.category -match 'enclosures')
                    {

                        $Enclosure = $Enclosure | Where-Object { $_.ApplianceConnection.Name -eq $ApplianceConnection.name }

                        "[{0}] Enclosure object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    "[{0}] Enclosure Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Enclosure.uri | Write-Verbose
                    "[{0}] Enclosure's Enclosure Group Uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Enclosure.enclosureGroupUri | Write-Verbose

                    $serverProfile.enclosureUri      = $Enclosure.uri
                    $serverProfile.enclosureGroupUri = $Enclosure.enclosureGroupUri
                    $serverProfile.enclosureBay      = $EnclosureBay
                            
                } 
        
                else 
                { 

                    $ExceptionMessage = "Enclosure Group is invalid. Please specify a correct Enclosure Group name, URI or object and try again."
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureGroupObject InvalidArgument 'EnclosureGroup' -TargetType $EnclosureGroup.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                }

            }

            # Creating an assigned profile
            else 
            {
            
                # Looking for the $server DTO to be string
                if ($Server -is [String]) 
                {
                
                    # If the server URI is passed, look up the server object
                    if ($Server.StartsWith($ServerHardwareUri)) 
                    {

                        "[{0}] Server URI passed: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Server | Write-Verbose 
                        
                        Try
                        {
                        
                            $Server = Send-HPOVRequest -Uri $Server -appliance $ApplianceConnection
                        
                        }
                        
                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }
                
                    # Else the name is passed and need to look it up.
                    else
                    {

                        Try
                        {

                            $Server = Get-HPOVServer -name $Server -appliance $ApplianceConnection

                        }
                    
                        Catch
                        {
                            
                            $PSCmdlet.ThrowTerminatingError($_)    
                            
                        }            
                    
                    }

                }
            
                "[{0}] Server object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Server | Out-String) | Write-Verbose 

                # Check to make sure the server NoProfileApplied is true
                if ($Server.serverProfileUri)
                {

                    Try
                    {

                        $ServerProfileConflict = Send-HPOVRequest -Uri $Server.serverProfileUri -Hostname $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $ExceptionMessage = "{0} already has a profile assigned, '{1}'. Please specify a different Server Hardware object." -f $Server.name, $ServerProfileConflict.name
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerProfileAlreadyAssigned ResourceExists 'Server' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Get the SHT of the SH that we are going to assign.
                Try
                {

                    $ServerHardwareType = Send-HPOVRequest -Uri $Server.serverHardwareTypeUri -appliance $ApplianceConnection

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Set the server hardware URI value in the profile
                $ServerProfile.serverHardwareUri = $Server.uri

                if($AssignmentType -eq 'bay' -and $EnclosureBay)
                {

                    $ServerProfile | Add-Member -NotePropertyName enclosureBay -NotePropertyValue $EnclosureBay

                }

                if ($Server.serverGroupUri)
                {

                    "[{0}] Getting Enclosure Group object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {
    
                        $EnclosureGroup = Send-HPOVRequest -Uri $Server.serverGroupUri -Hostname $ApplianceConnection
    
                    }
                    
                    Catch
                    {
    
                        $PSCmdlet.ThrowTerminatingError($_)
    
                    }

                }
            
            }

            # User provided UEFI or UEFIOptimized for a non-Gen9 platform.
            if ($BootMode -ne "BIOS" -and ("Gen9", "Gen10" -notcontains $ServerHardwareType.Generation))
            {

                $ExceptionMessage = "The -BootMode Parameter was provided and the Server Hardware model '{0}' does not support this Parameter. Please verify the Server Hardware Type is at least an HPE ProLiant Gen9." -f $ServerHardwareType.model
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException BootModeNotSupported InvalidArgument 'BootMode' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)    

            }

            # Handle Boot Order and BootManagement
            # Perform Device Model specific functions?

            # Handle DL Server Profiles by setting BL-specific properties to NULL
            if ($ServerHardwareType.platform -eq "RackServer")
            {

                "[{0}] Server Hardware Type is a DL, setting 'macType', 'wwnType', 'serialNumberType', 'affinity' and 'hideUnusedFlexNics' to supported values." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if (-not $PSboundParameters['ServerProfileTemplate'])
                {

                    $ServerProfile.macType            = 'Physical'
                    $ServerProfile.wwnType            = 'Physical'
                    $ServerProfile.serialNumberType   = 'Physical'
                    $ServerProfile.hideUnusedFlexNics = $true
                    $ServerProfile.affinity           = $Null

                }
                
            }
            
            else
            {

                if ($PSBoundParameters['MacAssignment'])
                {

                    "[{0}] MacAssignment override specified. Setting to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $MacAssignment | Write-Verbose 

                    $ServerProfile.macType = $MacAssignment

                }

                if ($PSBoundParameters['WwnAssignment'])
                {

                    "[{0}] MacAsWwnAssignmentsignment override specified. Setting to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $MacAssignment | Write-Verbose 

                    $ServerProfile.wwnType = $WwnAssignment

                }

                if ($PSBoundParameters['SnAssignment'])
                {

                    "[{0}] User is overriding SnAssignment type to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $SnAssignment | Write-Verbose 

                    $ServerProfile.serialNumberType = $SnAssignment

                    if ($SnAssignment -eq 'UserDefined')
                    {

                        if (-not $PSBoundParameters['SerialNumber'])
                        {

                            $ExceptionMessage = "The -SerialNumber Parameter is required when -SnAssignment is set to UserDefined. Provide a valid serial number value."
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException MissingRequiredSerialNumberParameter InvalidOperation 'UserDefined' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                        }

                        if (-not $PSBoundParameters['Uuid'])
                        {

                            $ExceptionMessage = "The -Uuid Parameter is required when -SnAssignment is set to UserDefined. Provide a valid UUID value."
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException MissingRequiredUuidParameter InvalidOperation 'UserDefined' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)   

                        }

                        "[{0}] User is overriding serialNumber to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Serialnumber | Write-Verbose 
                        "[{0}] User is overriding uuid to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Uuid | Write-Verbose 

                        $ServerProfile.serialNumber = $Serialnumber
                        $ServerProfile.uuid         = $Uuid

                    }

                }

            }
            
            if ('Gen7', 'Gen8' -contains $ServerHardwareType.generation)
            {

                if (-not($PSboundParameters['BootOrder']) -and $ManageBoot)
                {

                    "[{0}] No boot order provided for Gen8 Server resource type. Defaulting to 'CD','Floppy','USB','HardDisk','PXE'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                    [System.Collections.ArrayList]$serverProfile.boot.order = ('CD','Floppy','USB','HardDisk','PXE')

                }

            }

            else
            {

                if (-not $ServerProfileTemplate)
                {

                    "[{0}] Gen 9/10 Server, setting BootMode to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $BootMode | Write-Verbose 

                    $serverProfile.bootMode = NewObject -ServerProfileBootMode

                    switch ($BootMode) 
                    {

                        'Unmanaged'
                        {

                            $serverProfile.bootMode.manageMode = $false                        

                        }

                        "BIOS" 
                        {

                            $serverProfile.bootMode = NewObject -ServerProfileBootModeLegacyBios

                            $serverProfile.bootMode.manageMode = $true;
                            $serverProfile.bootMode.mode       = $BootMode;                        
                            
                        }

                        { "UEFI","UEFIOptimized" -match $_ } 
                        {
                            
                            $serverProfile.bootMode.manageMode    = $true;
                            $serverProfile.bootMode.mode          = $BootMode;
                            $serverProfile.bootMode.pxeBootPolicy = $PxeBootPolicy
                            
                            if ($ServerHardwareType.model -match 'DL|XL|ML')
                            {

                                $serverProfile.boot.manageBoot = $false

                            }
                            
                        }

                    }

                }

                if ($BootOrder -or (-not $BootOrder -and -not $ServerProfileTemplate))
                {

                    "[{0}] Processing Gen9/10 Server BootOrder settings." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                    if ($ManageBoot -and ($BootOrder -contains "Floppy") -and ($BootMode -match "UEFI"))
                    # If ($BootOrder -contains "Floppy" -and $BootMode -match "UEFI")
                    {
                        
                        $ExceptionMessage = "The -BootOrder Parameter contains 'Floppy' which is an invalid boot option for a UEFI-based system."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidUEFIBootOrderParameterValue InvalidArgument 'BootOrder' -TargetType 'Array' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ((-not ($PSBoundParameters["BootOrder"])) -and $ManageBoot -and ('Unmanaged','UEFI' -notcontains $BootMode)) 
                    # Elseif ((-not ($PSBoundParameters["BootOrder"])) -and ('Unmanaged','UEFI' -notcontains $BootMode))
                    {

                        "[{0}] No boot order provided for Gen9 Server resource type. Defaulting to 'CD','USB','HardDisk','PXE'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                        [System.Collections.ArrayList]$serverProfile.boot.order = @('CD','USB','HardDisk','PXE')
            
                    }

                    elseif ((-not ($PSBoundParameters["BootOrder"])) -and $ManageBoot -and $BootMode -match 'UEFI' -and $ServerHardwareType.model -notmatch 'DL|XL|ML')
                    # Elseif ((-not ($PSBoundParameters["BootOrder"])) -and $BootMode -match 'UEFI' -and $ServerHardwareType.model -notmatch 'DL')
                    {

                        "[{0}] No boot order provided for BL Gen9 Server resource type. Defaulting to 'HardDisk'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                        [System.Collections.ArrayList]$serverProfile.boot.order = @('HardDisk')
            
                    }

                    elseif (($BootOrder.count -gt 1) -and $ManageBoot -and $BootMode -match 'UEFI')
                    # Elseif (($BootOrder.count -gt 1) -and $BootMode -match 'UEFI')
                    {

                        $ExceptionMessage = "The -BootOrder Parameter contains more than 1 entry, and the system BootMode is set to {0}, which is invalud for a UEFI-based system. Please check the -BootOrder Parameter and make sure either 'HardDisk' or 'PXE' are the only option." -f $BootMode
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidUEFIBootOrderParameterValue InvalidArgument 'BootOrder' -TargetType 'Array' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
                    }

                    elseif ($BootOrder -and $serverProfile.boot.manageBoot -and $BootMode -match 'UEFI' -and $ServerHardwareType.model -notmatch 'DL|XL|ML')
                    # Elseif ($BootOrder -and $serverProfile.boot.manageBoot -and $BootMode -match 'UEFI' -and $ServerHardwareType.model -notmatch 'DL')
                    {

                        "[{0}] Adding provided BootOrder {1} to Server Profile object." -f $MyInvocation.InvocationName.ToString().ToUpper(), ($BootOrder -join ', ') | Write-Verbose 

                        [System.Collections.ArrayList]$serverProfile.boot.order = $BootOrder

                    }

                }                    

            }

            $ServerProfile.name                  = $Name
            $ServerProfile.description           = $Description
            $ServerProfile.serverHardwareTypeUri = $ServerHardwareType.uri

            if ($EnclosureGroup -and $null -eq $ServerProfile.enclsosureGroupUri)
            {

                $ServerProfile.enclosureGroupUri = $EnclosureGroup.uri 

            }

            if ($EnclosureBay -and $null -eq $ServerProfile.enclosureBay)
            {

                $ServerProfile.enclosureBay = $EnclosureBay

            }
            
            # Check to make sure Server Hardware Type supports Firmware Management (OneView supported G7 blade would not support this feature)
            if ($PSBoundParameters['Firmware']) 
            {
                
                "[{0}] Firmware Baseline: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

                if ($ServerHardwareType.capabilities -match "firmwareUpdate" ) 
                {

                    $ServerProfile.firmware.manageFirmware         = [Bool]$firmware
                    $ServerProfile.firmware.forceInstallFirmware   = [Bool]$forceInstallFirmware
                    $ServerProfile.firmware.firmwareInstallType    = $ServerProfileFirmwareControlModeEnum[$FirmwareInstallMode]
                    $ServerProfile.firmware.firmwareActivationType = $ServerProfileFirmareActivationModeEnum[$FirmwareActivationMode]

                    if ('FirmwareOffline', 'FirmwareOnlyOfflineMode' -contains $FirmwareInstallMode -and $PSBoundParameters['FirmwareActivateDateTime'])
                    {

                        $ExceptionMessage = "The specifying a scheduled firmware installation and performing offline method is not supported. Please choose an online method."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidFirmwareInstallMode InvalidArgument 'FirmwareActivateDateTime' -TargetType 'Switch' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                    elseif ($FirmwareActivationMode -eq 'Scheduled' -and -not $PSBoundParameters['FirmwareActivateDateTime'])
                    {

                        $ExceptionMessage = "The specifying a scheduled firmware installation requires the -FirmwareActivateDateTime parameter."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidFirmwareInstallMode InvalidArgument 'FirmwareActivateDateTime' -TargetType 'Switch' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                    }

                    elseif ($FirmwareActivationMode -eq 'Scheduled' -and $PSBoundParameters['FirmwareActivateDateTime'])
                    {

                        # Convert DateTime to UTC time for the appliance
                        "[{0}] Setting firmware activation schedule: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $FirmwareActivateDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") | Write-Verbose
                        $ServerProfile.firmware.firmwareScheduleDateTime = $FirmwareActivateDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")

                    }                    

                    # Validating that the baseline value is a string type and that it is an SPP name.
                    if (($baseline -is [String]) -and (-not ($baseline.StartsWith('/rest'))) -and ($baseline -match ".iso")) 
                    {
                        
                        try 
                        {

                            $FirmwareBaslineName = $Baseline.Clone()

                            $Baseline = Get-HPOVBaseline -isoFileName $Baseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                            If (-not $_BaseLinePolicy)
                            {

                                $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }
                            
                            $serverProfile.firmware.firmwareBaselineUri = $baseline.uri
                        
                        }

                        catch 
                        {
                            
                            "[{0}] Error caught when looking for Firmware Baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $PSCmdlet.ThrowTerminatingError($_)
                        
                        }
                    
                    }

                    # Validating that the baseline value is a string type and that it is an SPP name.
                    elseif (($baseline -is [String]) -and (-not ($baseline.StartsWith('/rest')))) 
                    {

                        try 
                        {

                            $FirmwareBaslineName = $Baseline.Clone()

                            $Baseline = Get-HPOVBaseline -SppName $Baseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                            If (-not $_BaseLinePolicy)
                            {

                                $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            $serverProfile.firmware.firmwareBaselineUri = $Baseline.uri

                        }

                        catch 
                        {

                            "[{0}] Error caught when looking for Firmware Baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }
            
                    # Validating that the baseline value is a string type and that it is the Baseline URI
                    elseif (($baseline -is [String]) -and ($baseline.StartsWith('/rest'))) 
                    {
                
                        Try
                        {

                            $baselineObj = Send-HPOVRequest -Uri $baseline -appliance $ApplianceConnection

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }                            

                        if ($baselineObj.category -eq "firmware-drivers") 
                        {
                        
                            "[{0}] Valid Firmware Baseline provided: $($baselineObj.baselineShortName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $serverProfile.firmware.firmwareBaselineUri = $baselineObj.uri 
                        
                        }

                        else 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidBaselineResource ObjectNotFound 'Baseline' -Message "The provided SPP Baseline URI '$($baseline)' is not valid or the correct resource category (expected 'firmware-drivers', received '$($baselineObj.category)'. Please check the -baseline Parameter value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                    # Else we are expecting the SPP object that contains the URI.
                    elseif (($baseline) -and ($baseline -is [object])) 
                    {

                        $serverProfile.firmware.firmwareBaselineUri = $baseline.uri
                    
                    }

                    elseif (!$baseline) 
                    {
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareMgmtFeatureNotSupported NotImplemented 'Firmware' -TargetType 'SwitchParameter' -Message "Baseline is required when manage firmware is set to true."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    }

                }

                else 
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareMgmtFeatureNotSupported NotImplemented 'Firmware' -TargetType 'SwitchParameter' -Message "`"$($serverHardwareType.name)`" Server Hardware Type does not support Firmware Management."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                    
                }

            }

            # Exmamine the profile connections Parameter and pull only those connections for this appliance connection
            If ($PSBoundParameters['Connections'])
            {

                $BootableConnections = [System.Collections.ArrayList]::new()

                # Check if non BL or SY, and set the search value to only get the list of Fibre Channel networks that are not Direct Attach?
                if ($ServerHardwareType.capabilities -notcontains 'VCConnections')
                {

                    ForEach ($c in $Connections)
                    {

                        # Validate the connection specified is FibreChannel; throw error if not
                        if ($c.functionType -ne 'FibreChannel')
                        {

                            $ExceptionMessage = 'The provided connection {0} is an Ethernet connection, which is not allowed. Only unmanaged Fibre Channel connections can be provisioned with non-Virtual Connect configurations.' -f $c.id
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException UnsupportedConnectionType InvalidArgument 'Connections' -TargetType 'PSObject' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                        # Check for duplicate WWPN
                        if ($_duplicateConnectionAddress = $ServerProfile.connectionSettings.connections | ? wwpn -eq $c.wwpn)
                        {

                            $ExceptionMessage = 'Connection {0} with the same WWPN is found. WWPNs must be unique within the server profile.' -f $_duplicateConnectionAddress.id
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException DuplicateWwpnAddressFound InvalidArgument 'Connections' -TargetType 'PSObject' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                        "[{0}] Adding unmanaged connection {1} to profile." -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.id | Write-Verbose

                        [void]$ServerProfile.connectionSettings.connections.Add([ServerProfileUnmanagedFCConnection]::new($c))

                    }

                }

                else
                {

                    "[{0}] Getting available Network resources based on SHT and EG." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Need to have a statement to check for connections that this URI will not return a value for
                    # Get avaialble Networks based on the EG and SHT
                    $_uri = '{0}?serverHardwareTypeUri={1}&enclosureGroupUri={2}' -f $ServerProfilesAvailableNetworksUri, $ServerHardwareType.uri, $EnclosureGroup.uri

                    Try
                    {

                        $_AvailableNetworkResources = Send-HPOVRequest -Uri $_uri -Hostname $ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    ForEach($c in $connections)
                    {

                        $Message = $null

                        # Remove connection Parameters no permitted in Template
                        $c = $c | Select-Object -property * -ExcludeProperty ApplianceConnection

                        switch (($c.networkUri.Split('\/'))[2])
                        {

                            'ethernet-networks'
                            {
                        
                                if (-not($_AvailableNetworkResources.ethernetNetworks | Where-Object uri -eq $c.networkUri))
                                {

                                    $Message = "The Ethernet network {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection.Name).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                                }

                                else
                                {

                                    "[{0}] {1} is available for Connection {2} in this Server Profile request." -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.networkUri, $c.id | Write-Verbose 

                                    # Add check for iSCsi Initiator Name, to make sure the initiatorName property is set correctly.

                                }
                        
                            }

                            'network-sets'
                            {
                        
                                if (-not($_AvailableNetworkResources.networkSets | Where-Object uri -eq $c.networkUri))
                                {

                                    $Message = "The network set {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection.Name).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                                }
                        
                                else
                                {

                                    "[$($MyInvocation.InvocationName.ToString().ToUpper())] {0} is available for Connection {1} in this Server Profile request." -f $c.networkUri, $c.id | Write-Verbose 

                                }

                            }

                            'fc-networks'
                            {
                        
                                if (-not($_AvailableNetworkResources.fcNetworks | Where-Object uri -eq $c.networkUri))
                                {

                                    $Message = "The FC network {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection.Name).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                                }
                        
                                else
                                {

                                    "[$($MyInvocation.InvocationName.ToString().ToUpper())] {0} is available for Connection {1} in this Server Profile request." -f $c.networkUri, $c.id | Write-Verbose 

                                }

                            }

                            'fcoe-networks'
                            {
                        
                                if (-not($_AvailableNetworkResources.fcNetworks | Where-Object uri -eq $c.networkUri))
                                {

                                    $Message = "The FCoE network {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection.Name).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                                }
                        
                                else
                                {

                                    "[$($MyInvocation.InvocationName.ToString().ToUpper())] {0} is available for Connection {1} in this Server Profile request." -f $c.networkUri, $c.id | Write-Verbose 

                                }
                        
                            }

                        }

                        if ($Message)
                        {

                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException NetworkResourceNotProvisioned InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Message
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }
                    
                        [void]$ServerProfile.connectionSettings.connections.Add($c)

                        if ($null -ne $c.boot -and $c.boot.priority -ne "NotBootable") 
                        {

                            "[{0}] Found bootable connection ID: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.id | Write-Verbose

                            [void]$BootableConnections.Add($c.id)

                        }
                
                    }

                    if (-not $PSBoundParameters['ManageBoot'] -and $BootableConnections.count -gt 0) 
                    {

                        $ExceptionMessage = "Bootable Connections {0} were found, however the -ManageBoot switch Parameter was not provided. Please correct your command syntax and try again." -f [String]::Join(', ', $BootableConnections.ToArray())
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException BootableConnectionsFound InvalidArgument 'manageBoot' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    } 

                }

            }

            # Check to make sure Server Hardware Type supports Bios Management (OneView supported G7 blade do not support this feature)
            if ($PSBoundParameters['BIOS']) 
            {

                if ($serverHardwareType.capabilities -match "ManageBIOS" ) 
                {

                    if ($BiosSettings.GetEnumerator().Cout -gt 0)
                    {
                            
                        # check for any duplicate keys
                        $biosFlag = $false
                        $hash = @{}
                        $BiosSettings.id | ForEach-Object { $hash[$_] = $hash[$_] + 1 }

                        foreach ($biosItem in ($hash.GetEnumerator() | Where-Object {$_.value -gt 1} | ForEach-Object {$_.key} )) 
                        {
                                
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException BiosSettingsNotUnique InvalidOperation 'BiosSettings' -TargetType 'Array' -Message "'$(($ServerHardwareType.biosSettings | where { $_.id -eq $biosItem }).name)' is being set more than once. Please check your BIOS Settings are unique. This setting might be a depEndency of another BIOS setting/option. Please check your BIOS Settings are unique. This setting might be a depEndency of another BIOS setting/option."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }
                    
                    }

                    $serverProfile.bios.overriddenSettings = $BiosSettings

                }

                else 
                { 

                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareMgmtFeatureNotSupported NotImplemented 'New-HPOVServerProfile' -Message "`"$($ServerHardwareType.name)`" Server Hardware Type does not support BIOS Management."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)                
                
                }
                    
            }

            # Manage Secure Boot settings
            if ($PSBoundParameters['SecureBoot'])
            {

                # Check to make sure Server Hardware supports SecureBoot
                if ($ServerHardwareType.capabilities.Contains('SecureBoot') -and $BootMode -eq 'UEFIOptimized')
                {

                    $serverProfile.bootMode.secureBoot = $SecureBoot

                }

                # Generate exception if not
                elseif ($ServerHardwareType.capabilities.Contains('SecureBoot') -and $BootMode -ne 'UEFIOptimized')
                {

                    $ExceptionMessage = 'The Server Hardware Type "{0}" supports managing SecureBoot, but BootMode was not set to "UEFIOptimized".' -f $ServerHardwareType.name
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidBootModeManageValue InvalidArgument 'BootMode' -TargetType 'Bool' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif (-not $ServerHardwareType.capabilities.Contains('SecureBoot') -and $BootMode -eq 'UEFIOptimized')
                {

                    $ExceptionMessage = 'The Server Hardware Type "{0}" does not support managing SecureBoot.' -f $ServerHardwareType.name
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidSecureBootManageValue InvalidArgument 'SecureBoot' -TargetType 'Bool' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            # Set Local Storage Management and Check to make sure Server Hardware Type supports it (OneView supported G7 blade would not support this feature)
            if (($PSBoundParameters['StorageController']) -and ($ServerHardwareType.capabilities -Contains "ManageLocalStorage" )) 
            {

                # Loop through Controllers provided by user, which should have LogicalDisks attached.
                ForEach ($_Controller in $StorageController)
                {

                    # Loop through Controllers provided by user, which should have LogicalDisks attached.
                    $__controller = $_Controller.PSObject.Copy()

                    $_NewLogicalDisksCollection = [System.Collections.ArrayList]::new()

                    "[{0}] Processing {1} Controller" -f $MyInvocation.InvocationName.ToString().ToUpper(), $__controller.deviceSlot | Write-Verbose
                    
                    # Validate the SHT.storageCapabilities controllerModes -> mode, raidLevels -> logicalDrives.raidLevel and maximumDrives -> numPhysicalDrives
                    if ($__controller.mode -eq 'RAID' -and ($ServerHardwareType.storageCapabilities.controllerModes -notcontains 'Mixed' -and $ServerHardwareType.storageCapabilities.controllerModes -notcontains 'RAID'))
                    {

                        $_ExceptionMessage = "Unsupported LogicalDisk policy with Virtual Machine Appliance. The requested Controller Mode '{0}' is not supported with the expected Server Hardware Type, which only supports '{1}'" -f $__controller.mode, ([System.String]::Join("', '", $ServerHardwareType.storageCapabilities.controllerModes)) 
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedImportConfigurationSetting InvalidOperation "StorageController" -TargetType 'PSObject' -Message $_ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    # Need to set Gen10+ controller mode to Mixed, especially if ImportConfiguration is requested
                    elseif ($__controller.mode -eq 'RAID' -and 'Mixed' -eq $ServerHardwareType.storageCapabilities.controllerModes)
                    {

                        $__controller.mode = "Mixed"

                    }

                    $_l = 1

                    "[{0}] Storage Controller has {1} LogicalDrives to Process" -f $MyInvocation.InvocationName.ToString().ToUpper(), $__controller.logicalDrives.count | Write-Verbose

                    # Validate the SHT.storageCapabilities .raidLevels -> logicalDrives.raidLevel and .maximumDrives -> numPhysicalDrives
                    ForEach ($_ld in $__controller.logicalDrives)
                    {

                        "[{0}] Processing {1} of {2} LogicalDisk: {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_l, $__controller.logicalDrives.count, $_ld.name | Write-Verbose

                        "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ld | Out-String) | Write-Verbose

                        if ($_ld.PSObject.Properties.Match('SasLogicalJBOD').Count)
                        {

                            "[{0}] Processing SasLogicalJbod {1} (ID:{2}) in Controller {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ld.SasLogicalJBOD.name, $_ld.SasLogicalJbodId, $__controller.deviceSlot | Write-Verbose

                            If ($ApplianceConnection.ApplianceType -ne 'Composer')
                            {

                                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. The LogicalDisk within the StorageController contains a SasLogicalJbod configuration with is only supported with HPE Synergy.' -f $ApplianceConnection)
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                            [void]$serverProfile.localStorage.sasLogicalJBODs.Add($_ld.SasLogicalJBOD)

                            # Needed for D3940 RAID drive attachment
                            if (-not [String]::IsNullOrEmpty($_ld.raidLevel))
                            {

                                $_ld = $_ld | Select-Object * -ExcludeProperty SasLogicalJBOD

                                [Void]$_NewLogicalDisksCollection.Add($_ld)

                            }

                        }
                        else
                        {

                        if ($ServerHardwareType.storageCapabilities.raidLevels -notcontains $_ld.raidLevel)
                        {

                            $_ExceptionMessage = "Unsupported LogicalDisk RAID Level {0} policy with {1} logical disk. The Server Hardware Type only supports '{2}' RAID level(s). " -f $_ld.raidLevel, $_ld.name, [System.String]::Join("', '", $ServerHardwareType.storageCapabilities.raidLevels) 
                            $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedLogicalDriveRaidLevel InvalidOperation "StorageController" -TargetType 'PSObject' -Message $_ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        if ($_ld.numPhysicalDrives -gt $ServerHardwareType.storageCapabilities.maximumDrives)
                        {

                            $_ExceptionMessage = "Invalid number of drives requested {0}. The Server Hardware Type only supports a maximum of '{1}'." -f $_ld.numPhysicalDrives, $ServerHardwareType.storageCapabilities.maximumDrives 
                            $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedNumberofDrives InvalidOperation "StorageController" -TargetType 'PSObject' -Message $_ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_ld = $_ld | Select-Object * -ExcludeProperty SasLogicalJBOD

                        [Void]$_NewLogicalDisksCollection.Add($_ld)

                        }

                        $_l++

                    }

                    $__controller.logicalDrives = $_NewLogicalDisksCollection

                    [void]$serverProfile.localStorage.controllers.Add($__controller)        

                }

            }
            
            # StRM Support
            if ($PSBoundParameters['SANStorage'] -and $ServerHardwareType.capabilities -Contains 'VCConnections')
            { 

                "[{0}] SAN Storage being requested" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ServerProfile.sanStorage = NewObject -ServerProfileSanStorage
                $ServerProfile.sanStorage.hostOSType        = $ServerProfileSanManageOSType[$HostOsType];
                $ServerProfile.sanStorage.manageSanStorage  = [Bool]$SANStorage;

                $_AllNetworkUrisCollection  = [System.Collections.ArrayList]::new()

                # Build list of network URI's from connections
                ForEach ($_Connection in ($ServerProfile.connectionSettings.connections | Where-Object { -not $_.networkUri.StartsWith($NetworkSetsUri) })) 
                {

                    [void]$_AllNetworkUrisCollection.Add($_Connection.networkUri)

                }

                # Copy the Parameter array into a new object
                $_VolumesToAttach = [System.Collections.ArrayList]::new()

                $StorageVolume | ForEach-Object { 

                    if ($_)
                    {
                    
                        [void]$_VolumesToAttach.Add($_)

                    }
                    
                }
                
                "[{0}] Number of Volumes to Attach: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumesToAttach.Count | Write-Verbose

                $_v = 0
                
                foreach ($_Volume in $_VolumesToAttach) 
                {  

                    $_v++

                    "[{0}] Processing Volume {1} of {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_v, $_VolumesToAttach.Count | Write-Verbose

                    # Ephemeral Volume Support
                    if ($null -eq $_Volume.volumeUri -and $_Volume.volume.properties.storagePool)
                    {

                        $_uri = "{0}?networks='{1}'&filter=uri='{2}'" -f $ReachableStoragePoolsUri, ([String]::Join(',', $_AllNetworkUrisCollection.ToArray())), $_Volume.volume.properties.storagePool
                        $_VolumeName = $_Volume.volume.properties.name
                        $_VolumeUri  = 'StoragePoolUri:{0}' -f $_Volume.volumeStoragePoolUri

                    }

                    # Provisioned Volume Support
                    else
                    {

                        Try
                        {

                            $_VolumeObject = Send-HPOVRequest -uri $_Volume.volumeUri -Hostname $_Volume.ApplianceConnection

                        }

                        catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }    

                        $_uri = "{0}?networks='{1}'&filter=name='{2}'" -f $AttachableStorageVolumesUri, ([String]::Join(',', $_AllNetworkUrisCollection.ToArray())), $_VolumeObject.name
                        $_VolumeUri = $_Volume.uri
                                            

                    }

                    "[{0}] Processing Volume ID: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Volume.id | Write-Verbose 
                    "[{0}] Looking to see if volume '{1} ({2})' is attachable" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumeObject.name, $_VolumeUri |Write-Verbose 

                    try
                    {

                        $_resp = Send-HPOVRequest -Uri $_uri -appliance $ApplianceConnection

                    }

                    catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Members found
                    if ($_resp.count -gt 0)
                    {

                        "[{0}] '{1} ({2})' volume is attachable" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumeName, $_VolumeUri | Write-Verbose

                        if (($_Volume.id -eq 0) -or (-not($_Volume.id)))
                        {

                            "[{0}] No VolumeID value provided. Getting next volume id value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $id = 1

                            $Found = $false

                            While (-not $Found -and $id -lt 256)
                            {

                                if (-not($_VolumesToAttach | Where-Object id -eq $id))
                                {

                                    "[{0}] Setting Volume ID to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $id | Write-Verbose

                                    $_Volume.id = $id

                                    $Found = $true

                                }

                                $id++

                            }

                        }

                        # If the storage paths array is null, Process connections to add mapping
                        if ($_Volume.storagePaths.Count -eq 0)
                        {

                            "[{0}] Storage Paths value is Null. Building connection mapping." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            # This should only be 1 within members array
                            foreach ($_member in $_resp.members) 
                            {

                                if ($_Member.deviceSpecificAttributes.iqn -or $_Member.family -eq 'StoreVirtual')
                                {

                                    "[{0}] Looking for Ethernet connections." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $_StorageTypeUri = $EthernetNetworksUri
                                    
                                }

                                else
                                {

                                    "[{0}] Looking for FC/FCoE connections." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $_StorageTypeUri = $FcNetworksUri

                                }

                                # Figure out which connections "should" map based on identified storage connectivity type
                                [Array]$_ProfileConnections = $ServerProfile.connectionSettings.connections | Where-Object { $_.networkUri.StartsWith($_StorageTypeUri) }

                                "[{0}] Number of connections that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ProfileConnections.Count | Write-Verbose

                                if ($_ProfileConnections.Count -gt 0)
                                {

                                    "[{0}] Connections that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', [Array]$_ProfileConnections.id) | Write-Verbose

                                }

                                [Array]$_ReachableNetworkUris = $_Member.reachableNetworks | Where-Object { $_.StartsWith($_StorageTypeUri) }

                                "[{0}] Number of reachable networks that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ReachableNetworkUris.Count | Write-Verbose

                                if ($_ReachableNetworkUris.Count -gt 0)
                                {

                                    "[{0}] Reachable networks that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', [Array]$_ReachableNetworkUris) | Write-Verbose

                                }

                                ForEach ($_ReachableNetworkUri in $_ReachableNetworkUris)
                                {

                                    "[{0}] Processing reachable network URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ReachableNetworkUri | Write-Verbose

                                    ForEach ($_ProfileConnection in ($_ProfileConnections | Where-Object { $_.networkUri -eq $_ReachableNetworkUri }))
                                    {

                                        "[{0}] Mapping connectionId '{1}' -> volumeId '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ProfileConnection.id, $_Volume.id | Write-Verbose

                                        $_StoragePath = NewObject -StoragePath

                                        $_StoragePath.connectionId = $_ProfileConnection.id
                                        $_StoragePath.isEnabled    = $True

                                        [void]$_Volume.storagePaths.Add($_StoragePath)

                                    }

                                }

                                if ($_Volume.storagePaths.Count -eq 0)
                                {

                                    Write-Warning ('No available connections were found that could attach to {0} Storage Volume. Storage Volumes may not be attached.' -f $_VolumeName)

                                }

                                [void]$ServerProfile.sanStorage.volumeAttachments.Add($_Volume)

                            }

                        }

                        else
                        {
                        
                            [void]$ServerProfile.sanStorage.volumeAttachments.Add($_Volume)
                        
                        }

                    }

                    # No members found, generate exception
                    else
                    {

                        $ExceptionMessage = "'{0}' Volume is not available to be attached to the profile. Please check the volume or available storage pools and try again."  -f $VolumeName
                        $ErrorRecord = New-ErrorRecord InvalidOperationException StorageVolumeUnavailableForAttach ResourceUnavailable 'StorageVolume' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                # Check to see if user passed -EvenPathDisable and/or -OddPathDisable Parameter switches
                if ($EvenPathDisabled.IsPresent -or $OddPathDisabled.IsPresent) 
                {
                                        
                    "[{0}] Disable Even Path: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EvenPathDisable.IsPresent | Write-Verbose
                    "[{0}] Disable Odd Path: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), $OddPathDisable.IsPresent | Write-Verbose

                    # Keep track of Volume Array index
                    $v = 0

                    foreach ($_vol in $ServerProfile.sanStorage.volumeAttachments) 
                    {
                        
                        # Keep track of Volume Path Array index
                        $p = 0

                        foreach ($_Path in $_vol.storagePaths) 
                        {

                            $_IsEnabled = $true

                            if ([Bool]$OddPathDisabled.IsPresent -and [Bool]($_Path.connectionID % 2)) 
                            { 
                                
                                $_IsEnabled = $false 
                            
                            }
                            
                            elseif ([Bool]$EvenPathDisabled.IsPresent -and [Bool]!($_Path.connectionID % 2)) 
                            { 
                                
                                $_IsEnabled = $false 

                            }

                            "[{0})] Setting Connection ID '{1}' path Enabled: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Path.connectionID, $_IsEnabled | Write-Verbose

                            $serverProfile.sanStorage.volumeAttachments[$v].storagePaths[$p].isEnabled = $_IsEnabled
                            $p++

                        }

                        $v++

                    }
                    
                }

            }

        }

        "[{0}] Profile: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($ServerProfile | out-string) | Write-Verbose

        # if ($PSBoundParameters['Scope'] -or (($ConnectedSessions | Where-Object Name -eq $ApplianceConnection).ActivePermissions ))
        # {


        # }

        if (-not $Passthru.IsPresent)
        {

            "[{0}] Sending request" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {
            
                $Resp = Send-HPOVRequest -Uri $ServerProfilesUri -Method POST -Body $ServerProfile -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            Try
            {

                $Resp = $Resp | Wait-HPOVTaskStart

                if ($Resp.taskState -eq 'Error')
                {

                    if ($Resp.taskErrors.message -match 'The selected server hardware has health status other than "OK"' -and 
                        $PSCmdlet.ShouldProcess($Server.name, 'The selected server hardware has health status other than "OK". Do you wish to override and assign the Server Profile'))
                    {

                        Try
                        {
                        
                            $_Uri = '{0}?force=all' -f $ServerProfilesUri

                            $Resp = Send-HPOVRequest -Uri $_Uri -Method POST -Body $ServerProfile -Hostname $ApplianceConnection
                
                        }
                
                        Catch
                        {
                
                            $PSCmdlet.ThrowTerminatingError($_)
                
                        }

                    }

                    else
                    {

                        $ExceptionMessage = $resp.taskErrors.message
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidOperation InvalidOperation 'AsyncronousTask' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }                

                }                

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Async'])
            {
            
                $Resp = Wait-HPOVTaskComplete -InputObject $Resp -ApplianceConnection $Resp.ApplianceConnection.Name
        
            }

            $Resp

        }

        else
        {

            # Return the server profile object back to the caller, who can directly modify it, and then use Save-HPOVServerProfile
            $ServerProfile

        }
        
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }    
    
}

# // TODO: DEVELOP DOCUMENTATION TEST
function Set-HPOVServerProfile
{

    Throw "Not implemented."

}

function Convert-HPOVServerProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('ServerProfile', 'Profile')]
        [Object]$InputObject,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$ServerHardwareType,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }     

        $_taskCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $_TransformType = [System.Collections.ArrayList]::new()

        $_ServerHardwareTypeUri = $null
        $_EnclosureGroupUri = $null

        # Process InputObject
        if ($InputObject.category -ne $ResourceCategoryEnum.ServerProfile)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object {0} is not supported. Only Server Profile is supported.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Process SHT
        if ($PSBoundParameters['ServerHardwareType'] -and $ServerHardwareType.category -ne $ResourceCategoryEnum.ServerHardwareType)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object {0} is not supported. Only Server Hardware Type is supported.' -f $ServerHardwareType.name
            $ErrorRecord = New-ErrorRecord HPOneview.ServerHardwareTypeResourceException InvalidServerHardwareTypeResource InvalidArgument "ServerHardwareType" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($PSBoundParameters['ServerHardwareType'])
        {

            $_ServerHardwareTypeUri = $ServerHardwareType.uri

            [void]$_TransformType.Add('server hardware type')

        }

        elseif (-not $PSBoundParameters['ServerHardwareType'])
        {

            $_ServerHardwareTypeUri = $InputObject.serverHardwareTypeUri

            [void]$_TransformType.Add('server hardware type')

        }

        # Process EG
        if ($PSBoundParameters['EnclosureGroup'] -and $EnclosureGroup.category -ne $ResourceCategoryEnum.EnclosureGroup)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object {0} is not supported. Only Enclosure Group is supported.' -f $EnclosureGroup.name
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureGroupResourceException InvalidEnclosureGroupResource InvalidArgument "EnclosureGroup" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        # Allow transformation of a Server Profile Template designed for DL/ML/Apollo to BL/WS
        elseif (($PSBoundParameters['EnclosureGroup'] -and $null -ne $InputObject.enclosureGroupUri) -or
                ($PSBoundParameters['EnclosureGroup'] -and $ServerHardwareType.model -match 'BL|WS|SY'))
        {

            $_EnclosureGroupUri = $EnclosureGroup.uri

            [void]$_TransformType.Add('enclosure group')

        }

        elseif (-not $PSBoundParameters['EnclosureGroup'] -and $null -ne $InputObject.enclosureGroupUri)
        {

            $_EnclosureGroupUri = $InputObject.enclosureGroupUri

            [void]$_TransformType.Add('enclosure group')

        }

        elseif ($PSBoundParameters['EnclosureGroup'] -and $null -eq $InputObject.enclosureGroupUri)
        {

            $ExceptionMessage = 'The provided Server Profile object {0} is likely a DL/ML/Apollo resource and does not support Enclosure Group objects.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureGroupResourceException InvalidEnclosureGroupResource InvalidOperation "EnclosureGroup" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Build final transformation URI
        $_Uri = '{0}/transformation?serverHardwareTypeUri={1}&enclosureGroupUri={2}' -f $InputObject.uri, $_ServerHardwareTypeUri, $_EnclosureGroupUri

        Try
        {

            $_TransformedServerProfile = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Show changes preview here.
        ForEach ($_previewChange in $_TransformedServerProfile.changes.GetEnumerator())
        {

            New-Object HPOneView.ServerProfile.TransformPreview($_previewChange)

        }

        $_ShouldProcessMessage = 'transform the server profile to new {0}' -f [String]::Join(' and ', $_TransformType.ToArray())

        if ($PSCmdlet.ShouldProcess($InputObject.Name, $_ShouldProcessMessage))
        {

            # Saving results back to appliance
            Try
            {

                $_TransformedServerProfileResults = Send-HPOVRequest -Uri $InputObject.uri -Method PUT -Body $_TransformedServerProfile.serverProfile -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Async'])
            {

                $_TransformedServerProfileResults | Wait-HPOVTaskComplete

            }

            else
            {

                $_TransformedServerProfileResults

            }

        }        
        
    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVServerProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'Default')]
    Param 
    (
        
        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Reapply')]    
        [Parameter (ValueFromPipeline, Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('profile','ServerProfile')]
        [object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Reapply')]
        [Switch]$Reapply,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$AdapterAndBoot,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$Connections,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$LocalStorage,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$SANStorage,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$BIOS,

        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$OSDeployment,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = 'Reapply')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Reapply')]
        [Switch]$Async

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {
            
            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection          = [System.Collections.ArrayList]::new()
        $_ServerProfileCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        if ($PipelineInput) 
        {
        
            "[{0}] Processing Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        # Process server profile resource name
        if ($InputObject -is [String])
        {

            Try
            {

                $InputObject = Get-HPOVServerProfile -Name $InputObject -ApplianceConnection $ApplianceConnect -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($InputObject.category -eq $ResourceCategoryEnum['ServerHardware'])
        {

            "[{0}] Server hardware resource provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($null -eq $InputObject.serverProfileUri)
            {

                $ExceptionMessage = 'The provided server hardware "{0}" does not have an assigned server profile.' -f $InputObject.name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareNullServerProfileAssignment InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Try
            {

                $InputObject = Send-HPOVRequest -Uri ($InputObject.serverProfileUri) -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Validate the Input object is the allowed category
        elseif ($InputObject.category -ne $ResourceCategoryEnum['ServerProfile'])
        {

            $ExceptionMessage = "The provided InputObject object ({0}) category '{1}' is not an allowed value. Expected category value is '{2}'. Please correct your input value." -f $InputObject.name, $InputObject.category, $ResourceCategoryEnum.ServerProfile
            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerProfilesCategory InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not $InputObject.ApplianceConnection)
        {

            $ExceptionMessage = "The provided InputObject object ({0}) does not contain the required 'ApplianceConnection' object property. Please correct your input value." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerProfileObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Processing Server Profile: '{1} [{2}]'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

        $_NotCompliant = $true

        $_PatchOperations = [System.Collections.ArrayList]::new()
        $_ReapplyOperations = [System.Collections.ArrayList]::new()

        switch ($PSCmdlet.ParameterSetName)
        {

            'Reapply'
            {

                "[{0}] Request is to reapply profile." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Error if the profile is not assigned to a server resource
                if ($null -eq $InputObject.serverHardwareUri)
                {

                    "[{0}] Profile is not assigned." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $ExceptionMessage = 'The Server Profile {0} is not assigned to a server hardware resource.' -f $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerProfilesAssignmet InvalidArgument 'ServerProfile' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }
                
                # Get power state of assigned profile
                Try
                {

                    $_server = Send-HPOVRequest -Uri $InputObject.serverHardwareUri -Hostname $ApplianceConnection
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)
                    
                }

                if ($_server.powerState -eq 'On')
                {

                    $ExceptionMessage = 'The associated server resource {0} to the Server Profile {1} is powered on. This operation only supports servers in a powered off state. Please use Stop-HPOVServer before continuing.' -f $_server.name, $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerProfilesAssignmet InvalidArgument 'ServerProfile' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_SpecificOperation = $false

                Switch ($PSBoundParameters.Keys)
                {

                    'Baseline'
                    {

                        "[{0}] Reapply baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_Operation = NewObject -PatchOperation
        
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/firmware/reapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)
                        [void]$_ReapplyOperations.Add('Baseline')

                        $_SpecificOperation = $true

                    }

                    'AdapterAndBoot'
                    {                
                        
                        "[{0}] Reapply AdapterAndBoot." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_Operation = NewObject -PatchOperation
        
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/serverHardwareReapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)
                        [void]$_ReapplyOperations.Add('AdapterAndBoot')

                        $_SpecificOperation = $true

                    }

                    'Connections'
                    {                    

                        "[{0}] Reapply connections." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_Operation = NewObject -PatchOperation
        
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/connectionSettings/reapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)
                        [void]$_ReapplyOperations.Add('Connections')

                        $_SpecificOperation = $true

                    }

                    'LocalStorage'
                    {                    

                        $_Operation = NewObject -PatchOperation
        
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/localStorage/reapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)
                        [void]$_ReapplyOperations.Add('LocalStorage')

                        $_SpecificOperation = $true

                    }

                    'SANStorage'
                    {                    

                        $_Operation = NewObject -PatchOperation
        
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/sanStorage/reapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)
                        [void]$_ReapplyOperations.Add('SANStorage')

                        $_SpecificOperation = $true

                    }

                    'BIOS'
                    {                    

                        $_Operation = NewObject -PatchOperation
        
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/bios/reapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)
                        [void]$_ReapplyOperations.Add('BIOS')

                        $_SpecificOperation = $true

                    }

                    'OSDeployment'
                    {
                        
                        if ($ApplianceConnection.ApplianceType -ne 'Composer')
                        {

                            $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. OS Deployment Plans are only supported with HPE Synergy.' -f $ApplianceConnection
                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        elseif ($null -eq $InputObject.osDeploymentSettings.osDeploymentPlanUri)
                        {

                            $ExceptionMessage = 'Server Profile {0} does not contain an OS Deployment Plan. In order to use the -OSDeployment switch, the HPE Synergy Server Profile needs to have an OS Deployment Plan associated.' -f $InputObject.name

                        }

                        else
                        {

                            $_Operation = NewObject -PatchOperation
        
                            $_Operation.op    = "replace"
                            $_Operation.path  = "/osDeploymentSettings/reapplyState"
                            $_Operation.value = "ApplyPending" 

                            [void]$_PatchOperations.Add($_Operation)
                            [void]$_ReapplyOperations.Add('OSDeployment')

                            $_SpecificOperation = $true

                        }                        

                    }

                }

                if (-not $_SpecificOperation)
                {

                    [void]$_ReapplyOperations.Add('All')

                    # BASELINE
                    $_Operation = NewObject -PatchOperation
    
                    $_Operation.op    = "replace"
                    $_Operation.path  = "/firmware/reapplyState"
                    $_Operation.value = "ApplyPending" 

                    [void]$_PatchOperations.Add($_Operation)

                    # ADAPTERANDBOOT
                    $_Operation = NewObject -PatchOperation
    
                    $_Operation.op    = "replace"
                    $_Operation.path  = "/serverHardwareReapplyState"
                    $_Operation.value = "ApplyPending" 

                    [void]$_PatchOperations.Add($_Operation)

                    # LOCALSTORAGE
                    $_Operation = NewObject -PatchOperation
    
                    $_Operation.op    = "replace"
                    $_Operation.path  = "/localStorage/reapplyState"
                    $_Operation.value = "ApplyPending" 

                    [void]$_PatchOperations.Add($_Operation)

                    # SANSTORAGE
                    $_Operation = NewObject -PatchOperation
    
                    $_Operation.op    = "replace"
                    $_Operation.path  = "/sanStorage/reapplyState"
                    $_Operation.value = "ApplyPending" 

                    [void]$_PatchOperations.Add($_Operation)

                    # BIOS
                    $_Operation = NewObject -PatchOperation
    
                    $_Operation.op    = "replace"
                    $_Operation.path  = "/bios/reapplyState"
                    $_Operation.value = "ApplyPending" 

                    [void]$_PatchOperations.Add($_Operation)

                    if ($ApplianceConnection.ApplianceType -eq 'Composer' -and $null -ne $InputObject.osDeploymentSettings.osDeploymentPlanUri)
                    {

                        $_Operation = NewObject -PatchOperation
    
                        $_Operation.op    = "replace"
                        $_Operation.path  = "/osDeploymentSettings/reapplyState"
                        $_Operation.value = "ApplyPending" 

                        [void]$_PatchOperations.Add($_Operation)

                    }

                }

                $_ShouldProcessMessage = "reapply server profile {0} configuration" -f [String]::Join(', ', $_ReapplyOperations.ToArray())

            }

            'Refresh'
            {

                $_Operation = NewObject -PatchOperation
        
                $_Operation.op    = "replace"
                $_Operation.path  = "/refreshState"
                $_Operation.value = "RefreshPending" 

                [void]$_PatchOperations.Add($_Operation)

                $_ShouldProcessMessage = "refresh server profile configuration."

            }

            default
            {

                $_Operation = NewObject -PatchOperation
        
                $_Operation.op    = "replace"
                $_Operation.path  = "/templateCompliance"
                $_Operation.value = "Compliant" 

                [void]$_PatchOperations.Add($_Operation)

                "{0}] Is Server Profile 'Compliant': {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.templateCompliance | Write-Verbose

                if ($InputObject.templateCompliance -ne 'Compliant')
                {

                    try
                    {

                        $_spUpdateOperations = Send-HPOVRequest -Uri ($InputObject.uri + '/compliance-preview') -Hostname $InputObject.ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $ReviewObject = New-Object HPOneView.ServerProfile.CompliancePreview ($InputObject.name, 
                                                                                          $_spUpdateOperations.isOnlineUpdate, 
                                                                                          $_spUpdateOperations.ApplianceConnection)

                    $_spUpdateOperations.automaticUpdates | ForEach-Object { [void]$ReviewObject.AutomaticUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
                    $_spUpdateOperations.manualUpdates | ForEach-Object { [void]$ReviewObject.ManualUpdates.Add((ConvertFromEmbeddedJsonString $_)) }

                    $_ShouldProcessMessage = "Update Server Profile configuration. WARNING: Depending on this action, there might be a brief outage."

                }

                else
                {

                    Write-Warning ('Skipping {0} Server Profile, as it is Compliant.' -f $InputObject.name)
                    $_NotCompliant = $false

                }

            }

        }

        if ($_NotCompliant -and $PSCmdlet.ShouldProcess($InputObject.name, $_ShouldProcessMessage))
        { 

            "[{0}] Sending request to {1} configuration" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSCmdlet.ParameterSetName | Write-Verbose

            Try
            {

                $_task = Send-HPOVRequest -Uri $InputObject.uri -Method PATCH -Body $_PatchOperations -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not($PSBoundParameters['Async']))
            {
            
                $_task = $_task | Wait-HPOVTaskComplete
        
            }

            $_task
            
        }

        elseif ($PSBoundParameters['WhatIf'])
        {
        
            "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Need to return the HPOneView.ServerProfile.ComplianceReview object
            if ($PSCmdlet.ParameterSetName -eq 'Default')
            {

                $ReviewObject

            }            
    
        }

        else 
        {

            "[{0}] User cancelled or server profile is compliant." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }    

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVServerProfileAssign
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Unassigned")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Profile')]
        [Object]$ServerProfile,
        
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$Server,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Unassigned")]
        [Switch]$Unassigned,

        [Parameter (Mandatory = $false, ParameterSetName = "Unassigned")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = "Unassigned")]
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Unassigned")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['ServerProfile']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }     

        $_taskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        # Look at Profile and Server if they are objects, and make sure ApplianceConnection.Name match
        if ($ServerProfile -is [PSCustomObject] -and $Server -is [PSCustomObject])
        {

            if ($ServerProfile.ApplianceConnection.Name -ne $Server.ApplianceConnection.Name)
            {

                "[{0}] Server Profile '{1}' and Server Hardware '{2}' ApplianceConnection do not match." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfile.ApplianceConnection.Name, $Server.ApplianceConnection.Name | Write-Verbose

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ProfileAndServerApplianceConnectionMismatch InvalidArgument 'Profile' -TargetType 'PSObject' -Message "The Server Profile ($($ServerProfile.ApplianceConnection.Name)) and Server Hardware ($($Server.ApplianceConnection.Name)) ApplianceConnection NoteProperty do not match. Please correct the value and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        # Looking for the $server DTO to be string
        if ($ServerProfile -is [String]) 
        {

            try 
            { 
                
                $ServerProfile = Get-HPOVServerProfile -name $ServerProfile -ApplianceConnection $ApplianceConnection -ErrorAction Stop
            
            }
            
            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)
                
            }

        }

        elseif ($ServerProfile -is [PSCustomObject] -and $ServerProfile.category -ne $ResourceCategoryEnum.ServerProfile)
        {

            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ProfileObjectInvalidCategory InvalidArgument 'Profile' -TargetType 'PSObject' -Message "The Server Profile ({0}) is an unsupported resource category type, '{1}'. Only '{2}' are supported. Please correct the value and try again." -f $ServerProfile.name, $ServerProfile.category, $ResourceCategoryEnum.ServerProfile
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Server Profile Object: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfile.name, $ServerProfile.uri | Write-Verbose
        
        # Check to make sure the server hardware the profile is assigned to is powered off
        if ($ServerProfile.serverHardwareUri) 
        {

            Try
            {

                $_ServerResource = Send-HPOVRequest $ServerProfile.serverHardwareUri -Hostname $ServerProfile.ApplianceConnection.Name

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ServerResource.powerState -ne "Off") 
            {

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerPowerState InvalidResult 'Profile' -Message "The Server '$($_ServerResource.name)' is currently powered On. Please power off the server and then perform the operation again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        # Looking for the $server DTO to be string
        if ($Server -is [String]) 
        {

            try 
            { 

                $Server = Get-HPOVServer -name $Server -ErrorAction Stop -ApplianceConnection $ApplianceConnection

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($Server -is [PSCustomObject] -and $Server.category -ne 'server-hardware')
        {

            $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareResourceException ServerObjectInvalidCategory InvalidArgument 'Server' -TargetType 'PSObject' -Message "The Server ($($Server.name)) is an unsupported resource category type, '$($Server.category)'. Only 'server-hardware' are supported. Please correct the value and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # "[{0}] Server Object: $($Server | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        if ($PSBoundParameters['Unassigned'])
        {

            $ServerProfile.serverHardwareUri = $Null
            
            if ($ServerProfile.enclosureUri) 
            {

                $ServerProfile.enclosureUri      = $Null
                $ServerProfile.enclosureBay      = $Null    

            }

        }

        else 
        {

            if ($Server.serverHardwareTypeUri -ne $ServerProfile.serverHardwareTypeUri) 
            {

                "[{0}] Server Profile assigned serverHardwareTypeUri does not match the destination Server resource. Updating Server Profile with new serverHardwareTypeUri value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ServerProfile.serverHardwareTypeUri = $Server.serverHardwareTypeUri
            
            }

            $ServerProfile.serverHardwareUri = $server.uri

            if ($server.locationUri) 
            {

                $ServerProfile.enclosureUri = $server.locationUri
                $ServerProfile.enclosureBay = $server.position    

            }            

        }

        $_Uri = $ServerProfile.uri

        if ($Force)
        {

            $_Uri += "?force=all"

        }

        try 
        { 

            $_resp = Send-HPOVRequest -Uri $_Uri -Method PUT -Body $ServerProfile -Hostname $ApplianceConnection.Name

        }

        catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        Try
        {

            $_resp = $_resp | Wait-HPOVTaskStart

            if ($_resp.taskState -eq 'Error')
            {

                if ($_resp.taskErrors.message -match 'The selected server hardware has health status other than "OK"' -and 
                    $PSCmdlet.ShouldProcess($Server.name, 'The selected server hardware has health status other than "OK". Do you wish to override and assign the Server Profile'))
                {

                    Try
                    {
                    
                        $_Uri = '{0}?force=all' -f $ServerProfilesUri

                        $_resp = Send-HPOVRequest -Uri $_Uri -Method PUT -Body $ServerProfile -Hostname $ApplianceConnection
            
                    }
            
                    Catch
                    {
            
                        $PSCmdlet.ThrowTerminatingError($_)
            
                    }

                }

                else
                {

                    $ExceptionMessage = $_resp.taskErrors.message
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidOperation InvalidOperation 'AsyncronousTask' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                }                

            }                

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {
        
            $_resp = Wait-HPOVTaskComplete -InputObject $_resp -ApplianceConnection $_resp.ApplianceConnection.Name
    
        }

        $_resp    

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Copy-HPOVServerProfile 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [Alias ('sname','src','SourceName')]
        [ValidateNotNullOrEmpty()]
        [object]$InputObject,
        
        [Parameter (Mandatory = $false)]
        [Alias ('dname','dst')]
        [String]$DestinationName,
        
        [Parameter (Mandatory = $false)]
        [object]$Assign = "unassigned",

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        if($ApplianceConnection.count -gt 1)
        {
        
            # Check for appliance specific URI Parameters and error if more than one appliance connection supplied
            if (($InputObject -is [String]) -and ($InputObject.StartsWith($ServerProfilesUri))) 
            {
                    
                "[{0}] InputObject is a Server Profile URI: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'InputObject' -Message "The input Parameter 'InputObject' is a URI. For multiple appliance connections this is not supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
            }

            if (($assign -is [String]) -and ($assign.StartsWith($ServerHardwareUri))) 
            {
                
                "[{0}] Assign is a Server Profile URI: $($SourceName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'Assign' -Message "The input Parameter 'Assign' is a URI. For multiple appliance connections this is not supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }

        $taskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        if (!$InputObject) 
        { 
        
            $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'InputObject' -Message "The input Parameter 'InputObject' was Null. Please provide a value and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
        }

        if (($InputObject -is [String]) -and (!$InputObject.StartsWith($ServerProfilesUri))) 
        {
            
            "[{0}] InputObject is a Server Profile Name: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] Getting Server Profile URI" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_Profile = Get-HPOVServerProfile -Name $InputObject -appliance $ApplianceConnection -ErrorAction Stop
                
                $profileSourceSHT = $_Profile.serverHardwareTypeUri

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Checking if the input is System.String and IS a URI - Should not Process on multi-appliance connections
        elseif (($InputObject -is [String]) -and ($InputObject.StartsWith($ServerProfilesUri))) 
        {
            
            "[{0}] InputObject is a Server Profile URI: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_Profile = Send-HPOVRequest -uri $InputObject -appliance $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            $profileSourceSHT = $_Profile.serverHardwareTypeUri
        
        }

        # Checking if source is object or object collection
        elseif (($InputObject -is [PSCustomObject]) -and ($InputObject.category -ieq $ResourceCategoryEnum.ServerProfile)) 
        {
            
            "[{0}] InputObject is a Server Profile object: $($InputObject.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            # For multi-appliance connections retrieve the source object only for this connection
            $_Profile = $InputObject.PSObject.Copy()

            $profileSourceSHT = $InputObject.serverHardwareTypeUri
        
        }

        else 
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message "The Parameter -InputObject value is invalid. Please validate the InputObject Parameter value you passed and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($assign -ine 'unassigned') 
        {
            
            # Target Server is the server device name. Could be any empty bay assignment
            if (($assign -is [String]) -and (-not ($assign.StartsWith($ServerHardwareUri)))) 
            {
                
                # Get-HPOVServer needs to be in a try/catch since it may be an empty bay
                Try
                {
                
                    $serverDevice = Get-HPOVServer -Name $assign -appliance $ApplianceConnection
                    
                }
                
                Catch 
                {
                
                    "[{0}] $($assign) server resource does not exist." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    "[{0}] Check for empty bay assignment." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        if(!$serverDevice -and ($assign -match "bay"))
                        {
                            

                            $assign = $assign.split(',').trim()

                            try
                            {

                                $thisEnc = Get-HPOVEnclosure -Name $assign[0] -appliance $ApplianceConnection -ErrorAction Stop

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                            
                            [Int]$thisBay = (($assign[1]) -replace "bay", "").trim()

                            $presence = $thisEnc.deviceBays[($thisBay - 1)].devicePresence
                            
                            # If presence is null, invalid device bay
                            if(!$presence) 
                            {
                            
                                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'Copy-HPOVProfile' -Message "The bay number $thisBay is not valid or not present."

                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                            }
                            
                            else 
                            {
                            
                                $_Profile.enclosureGroupUri = $thisEnc.uri
                                $_Profile.enclosureBay = $thisBay
                                $profileDestSHT = $profileSourceSHT
                            
                            } 
                        
                        }

                        else 
                        {
                        
                            $profileDestSHT = $serverDevice.serverHardwareTypeUri
                            
                        }
                        
                    }

                    Catch 
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                        
                    }
                        
                }                    
                
            }

            # Checking if the input is System.String and IS a URI
            elseif (($assign -is [String]) -and ($assign.StartsWith($ServerHardwareUri))) 
            {
            
                "[{0}] Assign to the Server hardware URI: $($assign)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $serverDevice = Send-HPOVRequest $assign -appliance $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                                    
                $profileDestSHT = $serverDevice.serverHardwareTypeUri
        
            }

            # Checking if the input is PSCustomObject, and the category type is server-profiles, which would be passed via pipeline input
            elseif (($assign -is [PSCustomObject]) -and ($assign.category -ieq "server-hardware")) 
            {
                
                "[{0}] Assign to the Server object: $($assign.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $serverDevice = $assign | Where-Object { $_.applianceConnection.name -eq $ApplianceConnection.name }
                $profileDestSHT = $serverDevice.serverHardwareTypeUri
        
            }

            else 
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Copy-HPOVProfile' -Message "The Parameter -Assign value is invalid. Please validate the Assign Parameter value you passed and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Checking if the input is PSCustomObject, and the category type is server-hardware, which would be passed via pipeline input
            if ($serverDevice.serverProfileUri) 
            {

                $ExceptionMessage = "A server profile is already assigned to {0} ({1}). Please try specify another server." -f $serverDevice.name, (Send-HPOVRequest $serverDevice.serverProfileUri -appliance $ApplianceConnection).name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerPropfileResourceAlreadyExists ResourceExists 'ServerProfile' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)                
        
            }

        }

        elseif ($assign -ieq "unassigned") 
        {
            
            "[{0}] Server will be unassigned" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        # Check to see if the SHT is different from the Profile and Target Assign Server
        if (($profileDestSHT -ine $profileSourceSHT) -and ($assign -ine "unassigned") -and (!$_Profile.enclosureBay))
        {
        
            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareTypeMismatch InvalidOperation 'Copy-HPOVProfile' -Message "The Target Server Hardware Type does not match the source Profile Server Hardware Type. Please specify a different Server Hardware Device to assign."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)          
                
        }

        # Remove Profile Specifics:
        $_Profile = $_Profile | select-object -Property * -excludeproperty uri,etag,created,modified,uuid,status,state,inprogress,serialNumber,enclosureUri,enclosureBay,serverHardwareUri,taskUri #,sanStorage

        $newConnections = [System.Collections.ArrayList]::new()
        # Create new connections with excluded properties and add to the newConnections array

        '[{0}] Rebuilding fabric connections' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        $_Profile.connectionSettings.connections | select-object -property * -excludeproperty mac,wwnn,wwpn,deploymentstatus,interconnectUri, applianceConnection | ForEach-Object {
        
            # Assign the newConnections array to $_Profile.connections
            [void]$newConnections.Add($_)
        
        }

        $_Profile.connectionSettings.connections = $newConnections

        # Null compliant property
        $_Profile.templateCompliance = $null

        # Process SAN Volume Attachments
        if ($_Profile.sanStorage -and $_Profile.sanStorage.volumeAttachments) 
        { 

            $newVolumeAttachments = @()
        
            "[{0}] Processing SAN Volume Attachments" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($attachVolume in $_Profile.sanStorage.volumeAttachments ) 
            {

                $tempVolume = [PSCustomObject]@{}
        
                "[{0}] Found attached volume ID $($attachVolume.id). Getting Volume properties." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $volume = Send-HPOVRequest $attachVolume.volumeUri -appliance $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Process shared volume
                if ($volume.shareable) 
                {
        
                    "[{0}] Adding Shareable Volume." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $tempVolume = $attachVolume | Select-Object id,volumeUri,lunType,lun,storagePaths
                    $tempVolume.lun = $Null
                    $tempVolume.storagePaths = ($attachVolume.storagePaths | ForEach-Object { $_ | select-object * -exclude status } )

                }

                # Process private volume
                else 
                {

                    "[{0}] Adding Private Volume." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    "[{0}] Checking for unique volume name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Get list of existing volumes from Index
                    
                    Try
                    {
                        
                        $indexVolumes = Send-HPOVRequest ($indexUri + "?category=storage-volumes&count=-1&start=0&sort=name:asc") -appliance $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $regex = " \((([0-9]|[1-9][0-9]|[1-9][0-9][0-9])+)\)"

                    $tempVolumeName = $volume.name -replace $regex,""

                    for ($i = 1; $i -le $volume.name.length; $i++) 
                    {
                    
                        if (-not ($indexVolumes.members -contains ($tempVolumeName + " ($i)"))) 
                        {
        
                            $attachVolumeName = $tempVolumeName + " ($i)"
                            
                            # Verify the name is unique by searching the index.
                            Try
                            {
                            
                                $results = Send-HPOVRequest ($indexUri + "?category=storage-volumes&filter=name='$attachVolumeName'&count=-1&start=0&sort=name:asc") -appliance $ApplianceConnection
                            
                            }
                            
                            Catch
                            {
                            
                                $PSCmdlet.ThrowTerminatingError($_)
                            
                            }

                            if ($results.count -eq 0) 
                            {    

                                "[{0}] Setting Volume Name to '$attachVolumeName'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                break

                            }

                        }

                    }

                    $tempVolume | Add-Member -NotePropertyName id -NotePropertyValue $attachVolume.id
                    $tempVolume | Add-Member -NotePropertyName volumeName -NotePropertyValue $attachVolumeName
                    $tempVolume | Add-Member -NotePropertyName volumeUri -NotePropertyValue $Null
                    $tempVolume | Add-Member -NotePropertyName volumeStoragePoolUri -NotePropertyValue $attachVolume.volumeStoragePoolUri 
                    $tempVolume | Add-Member -NotePropertyName volumeStorageSystemUri  -NotePropertyValue $attachVolume.volumeStorageSystemUri 
                    $tempVolume | Add-Member -NotePropertyName volumeProvisionType  -NotePropertyValue $volume.provisionType
                    $tempVolume | Add-Member -NotePropertyName volumeProvisionedCapacityBytes  -NotePropertyValue $volume.provisionedCapacity
                    $tempVolume | Add-Member -NotePropertyName volumeShareable   -NotePropertyValue $False
                    $tempVolume | Add-Member -NotePropertyName lunType   -NotePropertyValue $attachVolume.lunType
                    
                    if ($attachVolume.lunType -eq "Auto") { $tempVolume | Add-Member -NotePropertyName lun  -NotePropertyValue $Null }
                    else { $tempVolume | Add-Member -NotePropertyName lun  -NotePropertyValue $attachVolume.lun }
                    
                    $tempVolume | Add-Member -NotePropertyName storagePaths  -NotePropertyValue ($attachVolume.storagePaths | ForEach-Object { $_ | select-object * -exclude status } )
                    $tempVolume | Add-Member -NotePropertyName permanent -NotePropertyValue $volume.isPermanent

                }

                # "[{0}] Copied volume details: $($tempVolume | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $newVolumeAttachments += $tempVolume

            }

            $_Profile.sanStorage.volumeAttachments = $newVolumeAttachments

        }

        # Need to parse through local storage policies to null out Logical Drive ID
        if ($_Profile.localStorage.controllers.Count -gt 0)
        {

            ForEach ($_controller in $_Profile.localStorage.controllers)
            {

                For ($_ld = 0; $_ld -lt $_controller.logicalDrives.Count; $_ld++)
                {

                    '[{0}] Setting "{1}" Controller Logical Drive "{2}" drive number to null' -f $MyInvocation.InvocationName.ToString().ToUpper(), $_controller.deviceSlot, $_controller.logicalDrives[$_ld].name | Write-Verbose

                    $_controller.logicalDrives[$_ld].driveNumber = $null

                }

            }

        }

        # Set iscsiInitiatorName to null
        $_Profile.iscsiInitiatorName = $null

        # If DestinationName is provided, change to the profile name to value
        if ($DestinationName) 
        {

            "[{0}] New Server Profile name provided $($DestinationName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            $_Profile.name = $destinationName
        
        }
        
        # If no DestinationName is provided, add "Copy Of " prefix.
        else 
        {

            "[{0}] No new Server Profile name provided. Setting to `"Copy of $($_Profile.name)`"" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            $_Profile.name = "Copy of {0}" -f $_Profile.name

        }

        # If the server hardware device is present, add the property to the object
        if ($serverDevice) 
        {

            $_Profile | Add-Member @{ serverHardwareUri = $serverDevice.Uri }
        
        }

        # "[{0}] New Server Profile object: $($_Profile | Format-List * )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        # Send request to create new copied profile
        "[{0}] Sending request"  -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        Try
        {
        
            $Resp = Send-HPOVRequest -Uri $ServerProfilesUri -Method POST -Body $_Profile -appliance $ApplianceConnection

            Try
            {

                $Resp = $Resp | Wait-HPOVTaskStart

                if ($Resp.taskState -eq 'Error')
                {

                    if ($Resp.taskErrors.message -match 'The selected server hardware has health status other than "OK"' -and 
                        $PSCmdlet.ShouldProcess($serverDevice.name, 'The selected server hardware has health status other than "OK". Do you wish to override and assign the Server Profile'))
                    {

                        Try
                        {
                        
                            $_Uri = '{0}?force=all' -f $ServerProfilesUri

                            $Resp = Send-HPOVRequest -Uri $_Uri -Method POST -Body $_Profile -Hostname $ApplianceConnection
                
                        }
                
                        Catch
                        {
                
                            $PSCmdlet.ThrowTerminatingError($_)
                
                        }

                    }

                    else
                    {

                        $ExceptionMessage = $resp.taskErrors.message
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidOperation InvalidOperation 'AsyncronousTask' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }                

                }                

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }
        
        $resp

    }

    End 
    {
        
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVServerProfile 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('uri','name','profile')]
        [Object]$ServerProfile,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$force
    
    )

   Begin 
   {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['ServerProfile']))
        {

            $PipelineINput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        if($ApplianceConnection.count -gt 1)
        {

            # Check for appliance specific URI Parameters and error if more than one appliance connection supplied
            if (($ServerProfile -is [String]) -and ($ServerProfile.StartsWith($ServerProfilesUri))) 
            {
                    
                "[{0}] SourceName is a Server Profile URI: $($ServerProfile)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'Remove-HPOVServerProfile' -Message "The input Parameter 'profile' is a resource URI. For multiple appliance connections this is not supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            }

            if (($ServerProfile -is [array]) -and ($ServerProfile.getvalue(0).gettype() -is [String]) -and $ServerProfile -match '/rest/') 
            {
                
                "[{0}] Assign is a Server Profile URI: $($SourceName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'Remove-HPOVServerProfile' -Message "The input Parameter 'profile' is a resource URI. For multiple appliance connections this is not supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }

    }

    Process 
    {

        "[{0}] Profile input type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfile.gettype() | Write-Verbose

        foreach ($_profile in $ServerProfile) 
        {

            if ($_profile -is [String] -and (-not($_profile.StartsWith.($ServerProfilesUri)))) 
            {

                Try
                {

                    $_profile = Get-HPOVServerProfile -Name $_profile -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($_profile -is [String])
            {

                Try
                {

                    $_profile = Send-HPOVRequest $_profile -Hostname $ApplianceConnection

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($_profile -is [PSCustomObject] -and $_profile.category -ine $ResourceCategoryEnum.ServerProfile) 
            {
                
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'SeverProfile' -Message ("Invalid profile object provided: {0}. Please verify the object and try again." -f $_profile.name )
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($PSCmdlet.ShouldProcess($ApplianceConnection.Name,("remove Server Profile {0} from appliance?" -f $_profile.name )))
            {   
                
                $uri = $_profile.uri

                if ($PSBoundParameters['Force'])
                {

                    $uri += '?force=true'

                }

                Try
                {

                    Send-HPOVRequest -Uri $uri -Method DELETE -AddHeader @{'If-Match' = $_profile.eTag } -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['Whatif'])
            {

                "[{0}] -WhatIf provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVServerProfileTemplate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ParameterSetName = "Detailed", Mandatory = $false)]
        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [Alias ('profile')]
        [ValidateNotNullorEmpty()]
        [String]$Name,        

        [Parameter (ValueFromPipeline, ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ValueFromPipeline, ParameterSetName = "Detailed", Mandatory = $false)]
        [Parameter (ValueFromPipeline, ParameterSetName = "Export", Mandatory = $false)]
        [object]$ServerHardwareType,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ParameterSetName = "Detailed", Mandatory = $false)]
        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Parameter (ParameterSetName = "Detailed", Mandatory = $false)]
        [Parameter (ParameterSetName = "Export", Mandatory = $false)]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (ParameterSetName = "Detailed", Mandatory)]
        [Switch]$Detailed,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Detailed")]
        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false, ParameterSetName = "Export")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),
        
        [Parameter (ParameterSetName = "Export", Mandatory)]
        [Alias ("x")]
        [Switch]$Export,

        [Parameter (ParameterSetName = "Export", Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Alias ("save")]
        [String]$Location

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Validate the path exists. If not, create it.
        if (($Export) -and (-not(Test-Path $Location)))
        { 
        
            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            New-Item -path $Location -ItemType Directory
        
        }

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $TemplateCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.ServerProfileTemplate

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['ServerHardwareType'])
            {

                switch ($ServerHardwareType.GetType().Name)
                {

                    'String'
                    {

                        Try
                        {

                            $ServerHardwareType = Get-HPOVServerHardwareType -Name $ServerHardwareType -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    'PSCustomObject'
                    {

                        if ($ServerHardwareType.category -ne 'server-hardware-types')
                        {

                            $ExceptionMessage = "The provided ServerHardwareType parameter value, '{0}', is not a supported resource type. Please check the value, and try again." -f $ServerHardwareType.name
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerHardwareTypeResourceException ServerHardwareTypeInvalidObject InvalidParameter 'ServerHardwareType' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }

                }

                $_ResourcesFromIndexCol = $_ResourcesFromIndexCol | Where-Object { $_.serverHardwareTypeUri -eq $ServerHardwareType.uri }

            }
            
            if($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] Profile Template Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose
                
                $ExceptionMessage = "The specified Server Profile Template '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerProfileResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)
                
            }

            else
            {

                foreach ($_member in $_ResourcesFromIndexCol)
                {
                
                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.ServerProfileTemplate')
                        
                    [void]$TemplateCollection.Add($_member)
                    
                }

            }

        }

    }

    End 
    {

        "[{0}] Done. {1} server profile template resource(s) found." -f $MyInvocation.InvocationName.ToString().ToUpper(), $TemplateCollection.count | Write-Verbose 

        # If user wants to export the profile configuration
        if ($export) 
        {

            # Get the unique applianceConnection.name properties from the profile collection for grouping the output files
            $ProfileGroupings = $TemplateCollection.ApplianceConnection.name | Select-Object -Unique

            ForEach ($pg in $ProfileGroupings)
            {
                
                $outputProfiles = [System.Collections.ArrayList]::new()

                $templates = $TemplateCollection | Where-Object { $_.ApplianceConnection.Name -eq $pg }

                # Loop through all profiles
                foreach ($_profile in $templates) 
                {

                    # Trim out appliance unique properties

                    $_profile = $_profile | select-object -Property * -excludeproperty uri,etag,created,modified,status,state,inprogress,enclosureUri,enclosureBay,serverHardwareUri,taskUri,ApplianceConnection
                    $_profile.serialNumberType = "UserDefined"

                    # Loop through the connections to save the assigned address
                    $i = 0
                    foreach ($connection in $profile.connectionSettings.connections) 
                    {

                        if ($profile.connectionSettings.connections[$i].mac) { $_profile.connectionSettings.connections[$i].macType = "UserDefined" }
                        if ($profile.connectionSettings.connections[$i].wwpn) { $_profile.connectionSettings.connections[$i].wwpnType = "UserDefined" }
                        $i++

                    }

                    [void]$outputProfiles.Add($_profile)
                    
                }

                # Save profile to JSON file
                "[{0}] Saving Server Profile Templates to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($location + '\' + $pg + '_ServerProfileTemplates.json') | Write-Verbose

                convertto-json -InputObject $outputProfiles -depth 99 | new-item ($location + '\' + $pg + '_ServerProfileTemplates.json') -itemtype file

            }

        }

        else 
        {

            Return $TemplateCollection

        }

    }

}

function New-HPOVServerProfileTemplate 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")] 
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [String]$Description,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")] 
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [String]$ServerProfileDescription,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Boolean]$ManageConnections = $true,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [array]$Connections = @(),

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'Minimum', 'None')]
        [String]$ConnectionsConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Alias ('eg')]
        [object]$EnclosureGroup,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Alias ('sht')]
        [object]$ServerHardwareType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Firmware,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'None')]
        [String]$FirmwareConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias ('FirmwareMode')]
        [ValidateSet ('FirmwareOnly', 'FirmwareAndSoftware', 'FirmwareOffline', 'FirmwareAndOSDrivers', 'FirmwareOnly', 'FirmwareOnlyOfflineMode')]
        [String]$FirmwareInstallMode = 'FirmwareAndSoftware',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Immediate', 'Scheduled', 'NotScheduled')]
        [String]$FirmwareActivationMode = 'Immediate',
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [object]$Baseline,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Switch]$ForceInstallFirmware,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.OSDeploymentPlan]$OSDeploymentPlan,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'None')]
        [String]$OSDeploymentConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter[]]$OSDeploymentPlanAttributes,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Bios,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [array]$BiosSettings=@(),

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'None')]
        [String]$BiosConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]        
        [ValidateSet ("UEFI", "UEFIOptimized", "BIOS", 'Unmanaged', IgnoreCase = $False)]
        [String]$BootMode = "BIOS",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'None')]
        [String]$BootModeConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]        
        [ValidateSet ("Auto", "IPv4", "IPv6", "IPv4ThenIPv6", "IPv6ThenIPv4", IgnoreCase = $False)]
        [String]$PxeBootPolicy = "Auto",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias ('boot')]
        [Bool]$ManageBoot = $true,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [array]$BootOrder,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Unmanaged", "Enabled", "Disabled", IgnoreCase = $False)]
        [String]$SecureBoot = 'Unmanaged',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Switch]$LocalStorage,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'None')]
        [String]$LocalStorageConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias('LogicalDisk')]
        [ValidateNotNullorEmpty()]
        [Object]$StorageController,

        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [Switch]$SANStorage,

        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('Exact', 'Minimum', 'None')]
        [String]$SANStorageConsistencyChecking = 'Exact',  # Will need to use $ConsistencyCheckingEnum for API value

        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ('CitrixXen','CitrixXen7','AIX','IBMVIO','RHEL4','RHEL3','RHEL','RHEV','RHEV7','VMware','Win2k3','Win2k8','Win2k12','Win2k16','OpenVMS','Egenera','Exanet','Solaris9','Solaris10','Solaris11','ONTAP','OEL','HPUX11iv1','HPUX11iv2','HPUX11iv3','SUSE','SUSE9','Inform', IgnoreCase = $true)]
        [Alias ('OS')]
        [String]$HostOStype,

        [Parameter (Mandatory, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [object]$StorageVolume,

        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias ('Even')]
        [Switch]$EvenPathDisabled,

        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Alias ('Odd')]
        [Switch]$OddPathDisabled,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Bay","BayAndServer", IgnoreCase=$false)]
        [String]$Affinity = "Bay",
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Virtual", "Physical", "UserDefined", IgnoreCase = $true)]
        [String]$MacAssignment = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Virtual", "Physical", "'UserDefined", IgnoreCase = $true)]
        [String]$WwnAssignment = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Virtual", "Physical", "UserDefined", IgnoreCase = $true)]
        [String]$SnAssignment = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateSet ("Virtual", "UserDefined", IgnoreCase = $true)]
        [String]$IscsiInitiatorNameAssignmet = "Virtual",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Bool]$HideUnusedFlexNics = $True,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [Switch]$PassThru,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SANStorageAttach")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)        
        
    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Check for URI values in Parameters and validate that only one appliance connection is provided in the call
        if($ApplianceConnection.Count -gt 1)
        {
            
            # SHT
            if($serverHardwareType -is [String] -and $serverHardwareType.StartsWith($ServerHardwareTypesUri))
            {
                
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Server Hardware Type as URI is not supported for multiple appliance connections"
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }
            
            if($serverHardwareType -is [String] -and $serverHardwareType.StartsWith("/rest"))
            {
            
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Server Hardware Type as URI is not supported for multiple appliance connections."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

            # EG
            if(($enclosureGroup -is [String] -and $enclosureGroup.StartsWith("/rest")))
            {
            
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Enclosure Group as URI is not supported for multiple appliance connections."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

            #Baseline
            if (($baseline -is [String]) -and ($baseline.StartsWith('/rest'))) 
            {
                
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'New-HPOVPropfile' -Message "Baseline as URI is not supported for multiple appliance connections."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }

        ForEach ($_key in $PSBoundParameters.keys.GetEnumerator())
        {

            if ('ImportLogicalDisk','Initialize','ControllerMode','Bootable','RaidLevel' -contains $_key)
            {

                Write-Warning ("The -{0} parameter is deprecated. To configure local storage, please use the New-HPOVServerProfileLogicalDisk and New-HPOVServerProfileLogicalDiskController Cmdlets." -f $_key)

            }

        }

        $uri = $ServerProfileTemplatesUri

        $colStatus = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {
        
        # New Server Resource Object
        $_spt = NewObject -ServerProfileTemplate
            
        $_spt.name                          = $Name
        $_spt.description                   = $Description
        $_spt.serverProfileDescription      = $ServerProfileDescription        
        $_spt.affinity                      = $Affinity

        if (-not $ManageBoot -and ($PSBoundParameters['BootMode'] -or $PSBoundParameters['BootOrder'] -or $PSBoundParameters['PxeBootPolicy']))
        {

            $ExceptionMessage = "Attempting to set Boot Mode or Boot Order and not enabling ManageBoot is not supported. Either remove the -BootOrder,-PxeBootPolicy and/or -BootMode parameters, or add -ManageBoot switch parameter."
            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileTemplateResourceException InvalidManageBootModeState InvalidArgument 'ManageBoot' -TargetType 'Boolean' -Message    $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
                            
        # Check to see if the serverHardwareType or enclosureGroup is null, and generate error(s) then break.
        if (-not($ServerHardwareType))
        {

            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidServerHardwareTypeObject InvalidArgument 'ServerHardwareType' -Message "Server Hardware Type is missing. Please provide a Server Hardware Type using the -sht Parameter and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        # If the URI is passed as the Server Hardware Type, then set the serverHardwareTypeUri variable
        If ($ServerHardwareType -is [String])
        {

            if ($ServerHardwareType.StartsWith($ServerHardwareTypesUri))
            { 
                        
                "[{0}] SHT URI Provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType | Write-Verbose

                $_spt.serverHardwareTypeUri = $ServerHardwareType

                Try
                {
                        
                    $ServerHardwareType = Send-HPOVRequest -Uri $ServerHardwareType -Hostname $ApplianceConnection
                        
                }
                        
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
                
            # Otherwise, perform a lookup ofthe SHT based on the name
            else 
            {

                "[{0}] SHT Name Provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType | Write-Verbose

                Try
                {

                    $ServerHardwareType = Get-HPOVServerHardwareType -Name $ServerHardwareType -Appliance $ApplianceConnection -ErrorAction Stop

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                "[{0}] SHT URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.uri | Write-Verbose
                
                $_spt.serverHardwareTypeUri = $ServerHardwareType.uri

            }

        }
        
        # Else the SHT object is passed
        else 
        { 

            "[{0}] ServerHardwareType object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            "[{0}] ServerHardwareType Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.name | Write-Verbose
            "[{0}] ServerHardwareType Uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.uri | Write-Verbose

            $_spt.serverHardwareTypeUri = $serverHardwareType.uri
                    
        }

        if ('BladeServer', 'ComputeModule' -contains $ServerHardwareType.platform)
        {

            $_spt.hideUnusedFlexNics = $PSBoundParameters['HideUnusedFlexNics']
            $_spt.serialNumberType   = $SnAssignment 
            $_spt.macType            = $MacAssignment
            $_spt.wwnType            = $WwnAssignment

            if ($PSBoundParameters['IscsiInitiatorNameAssignmet'])
            {

                $_spt.iscsiInitiatorNameType = $IscsiInitiatorNameAssignmetEnum[$IscsiInitiatorNameAssignmet]

            }
            

            if (-not($EnclosureGroup))
            {
                
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureGroupObject InvalidArgument 'EnclosureGroup' -Message "Enclosure Group is missing. Please provide an Enclosure Group using the -eg Parameter and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($EnclosureGroup -is [String])
            {

                # If the URI is passed as the Enclosure Group, then set the enclosureGroupUri variable
                if ($EnclosureGroup.StartsWith('/rest'))
                { 
                
                    $_spt.enclosureGroupUri = $EnclosureGroup
            
                }

                # Otherwise, perform a lookup ofthe Enclosure Group
                else
                {

                    Try
                    {

                        $EnclosureGroup = Get-HPOVEnclosureGroup -name $EnclosureGroup -appliance $ApplianceConnection

                    }
                
                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    "[{0}] EG URI: $enclosureGroupUri" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose                        
                
                    $_spt.enclosureGroupUri = $EnclosureGroup.uri
                
                }

            }
                
            # Else the EG object is passed
            elseif (($EnclosureGroup -is [PSObject]) -and ($EnclosureGroup.category -eq "enclosure-groups")) 
            { 

                # Retrieve only EG from this appliance connection
                "[{0}] Enclosure Group object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Enclosure Group Name: $($EnclosureGroup.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                "[{0}] Enclosure Group Uri: $($EnclosureGroup.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Retrieve only EG from this appliance connection
                $_spt.enclosureGroupUri = $EnclosureGroup.uri

            }

            else 
            { 

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidEnclosureGroupObject InvalidArgument 'EnclosureGroup' -TargetType $EnclosureGroup.GetType().Name -Message "Enclosure Group is invalid. Please specify a correct Enclosure Group name, URI or object and try again."

                # Generate Terminating Error
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }            

        # Handle DL Server Profiles by setting BL-specific properties to NULL
        else
        {

            "[{0}]] Server Hardware Type platform is a RackServer, setting 'macType', 'wwnType', 'serialNumberType', 'affinity' and 'hideUnusedFlexNics' to supported values." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_spt.macType            = 'Physical'
            $_spt.wwnType            = 'Physical'
            $_spt.serialNumberType   = 'Physical'
            $_spt.hideUnusedFlexNics = $true
            $_spt.affinity           = $Null

        }

        # Handle Boot Order and BootManagement
        switch ($ServerHardwareType.generation)
        {
                
            {$_ -match 'Gen7|Gen8'}
            {

                # User provided UEFI or UEFIOptimized for a non-Gen9 platform.
                if ('Unmanaged','BIOS' -notcontains $BootMode)
                {

                    $ExceptionMessage = "The -BootMode Parameter was provided and the Server Hardware model '{0}' does not support this Parameter. Please verify the Server Hardware Type is at least an HPE ProLiant Gen9." -f $ServerHardwareType.model
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException BootModeNotSupported InvalidArgument 'BootMode' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)    

                }

                if (-not($PSboundParameters['BootOrder']) -and $ManageBoot)
                {

                    "[{0}] No boot order provided for Gen8 Server resource type. Defaulting to 'CD','Floppy','USB','HardDisk','PXE'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    [System.Collections.ArrayList]$_spt.boot.order = ('CD','Floppy','USB','HardDisk','PXE')

                }

            }

            # {$_ -match 'Gen9|Gen10'}
            default
            {

                "[{0}] '{1}' Server, setting BootMode to: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.generation, $BootMode | Write-Verbose 

                if ($ManageBoot)
                {

                    $_spt.bootMode = NewObject -ServerProfileBootMode

                    switch ($BootMode) 
                    {

                        'Unmanaged'
                        {

                            $_spt.bootMode.manageMode = $false                        

                        }

                        "BIOS" 
                        {

                            $_spt.bootMode = NewObject -ServerProfileBootModeLegacyBios

                            $_spt.bootMode.manageMode = $true;
                            $_spt.bootMode.mode       = $BootMode;                        
                            
                        }

                        { "UEFI","UEFIOptimized" -match $_ } 
                        {
                            
                            $_spt.bootMode.manageMode    = $true;
                            $_spt.bootMode.mode          = $BootMode;
                            $_spt.bootMode.pxeBootPolicy = $PxeBootPolicy
                            
                            if ($ServerHardwareType.model -match 'DL|XL|ML')
                            {

                                $_spt.boot.manageBoot = $false

                            }

                            if ($ServerHardwareType.model -match "Gen9" -and -not $PSBoundParameters['SecureBoot'])
                            {

                                $_spt.bootMode.secureBoot = 'Unmanaged'

                            }
                            
                        }

                    }

                    "[{0}] Processing '{1}' Server BootOrder settings." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.generation | Write-Verbose 

                    if ($_spt.boot.manageBoot -and ($BootOrder -contains "Floppy") -and ($BootMode -match "UEFI"))
                    {
                            
                        $ExceptionMessage = "The -BootOrder Parameter contains 'Floppy' which is an invalid boot option for a UEFI-based system."
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidUEFIBootOrderParameterValue InvalidArgument 'BootOrder' -TargetType 'Array' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ((-not ($PSBoundParameters["BootOrder"])) -and $_spt.boot.manageBoot -and $BootMode -eq "BIOS") 
                    {

                        "[{0}] No boot order provided for Gen9 Server resource type. Defaulting to 'CD','USB','HardDisk','PXE'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [System.Collections.ArrayList]$_spt.boot.order = @('CD','USB','HardDisk','PXE')
                
                    }

                    elseif ((-not ($PSBoundParameters["BootOrder"])) -and $_spt.boot.manageBoot -and $BootMode -match 'UEFI' -and $ServerHardwareType.model -notmatch 'DL')
                    {

                        "[{0}] No boot order provided for BL Gen9 Server resource type. Defaulting to 'HardDisk'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [System.Collections.ArrayList]$_spt.boot.order = @('HardDisk')
                
                    }

                    elseif (($BootOrder.count -gt 1) -and $_spt.boot.manageBoot -and $BootMode -match 'UEFI')
                    {

                        $ExceptionMessage = "The -BootOrder Parameter contains more than 1 entry, and the system BootMode is set to {0}, which is invalud for a UEFI-based system. Please check the -BootOrder Parameter and make sure either 'HardDisk' or 'PXE' are the only option." -f $BootMode
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidUEFIBootOrderParameterValue InvalidArgument 'BootOrder' -TargetType 'Array' -Message    $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                    }

                    elseif ($BootOrder -and $_spt.boot.manageBoot -and $BootMode -match 'UEFI' -and $ServerHardwareType.model -notmatch 'DL')
                    {

                        "[{0}] Adding provided BootOrder {1} to Server Profile object." -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', $BootOrder) | Write-Verbose 

                        [System.Collections.ArrayList]$_spt.boot.order = $BootOrder

                    }

                }

                else
                {

                    $_spt.boot.manageBoot = $false
                    $_spt.boot.order = $null

                }
                
            }

        }

        if ($PSBoundParameters['OSDeploymentPlan'])
        {

            If ($ApplianceConnection.ApplianceType -ne 'Composer')
            {

                $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. OS Deployment Plans are only supported with HPE Synergy.' -f $ApplianceConnection.Name
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Setting OS Deployment Plan." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_spt | Add-Member -NotePropertyName osDeploymentSettings -NotePropertyValue (NewObject -SPTOSDeploymentSettings)

            if ($PSBoundParameters['OSDeploymentConsistencyChecking'])
            {

                $_spt.osDeploymentSettings.complianceControl = $ConsistencyCheckingEnum.$OSDeploymentConsistencyChecking
                
            }
            
            "[{0}] Setting OS Deployment Plan URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $OSDeploymentPlan.uri | Write-Verbose
            $_spt.osDeploymentSettings.osDeploymentPlanUri = $OSDeploymentPlan.uri

            "[{0}] Number of OS Deployment Plan Custom Attributes to set: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $OSDeploymentPlanAttributes.Count | Write-Verbose
            "[{0}] Setting OS Deployment Plan Custom Attributes: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($OSDeploymentPlanAttributes | Out-String) | Write-Verbose
            $_spt.osDeploymentSettings.osCustomAttributes  = $OSDeploymentPlanAttributes

        }

        # Exmamine the profile connections Parameter and pull only those connections for this appliance connection
        If ($PSBoundParameters['Connections'] -and $ManageConnections) # -and $ServerHardwareType.capabilities -contains "VCConnections")
        {

            if ($PSBoundParameters['ConnectionsConsistencyChecking'])
            {

                $_spt.connectionSettings.complianceControl = $ConsistencyCheckingEnum.$ConnectionsConsistencyChecking
                
            }

            # Check if non BL or SY, and set the search value to only get the list of Fibre Channel networks that are not Direct Attach?
            if ($ServerHardwareType.capabilities -notcontains 'VCConnections')
            {

                ForEach ($c in $Connections)
                {

                    # Validate the connection specified is FibreChannel; throw error if not
                    if ($c.functionType -ne 'FibreChannel')
                    {

                        $ExceptionMessage = 'The provided connection {0} is an Ethernet connection, which is not allowed. Only unmanaged Fibre Channel connections can be provisioned with non-Virtual Connect configurations.' -f $c.id
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException UnsupportedConnectionType InvalidArgument 'Connections' -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    "[{0}] Adding unmanaged connection {1} to profile." -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.id | Write-Verbose

                    $_c = [ServerProfileUnmanagedFCConnection]::new($c) | Select * -exclude wwpn

                    [void]$_spt.connectionSettings.connections.Add($_c)

                }

            }

            else
            {

                "[{0}] Getting available Network resources based on SHT and EG." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Get avaialble Networks based on the EG and SHT
                $_uri = $ServerProfilesAvailableNetworksUri + '?serverHardwareTypeUri={0}&enclosureGroupUri={1}' -f $ServerHardwareType.uri,$EnclosureGroup.uri

                Try
                {

                    $_AvailableNetworkResources = Send-HPOVRequest -Uri $_uri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_c = 0

                $BootableConnections = [System.Collections.ArrayList]::new()

                ForEach ($c in $Connections)
                {

                    $Message = $null

                    # Remove connection Parameters not permitted in Template
                    $c = $c | Select-Object -property * -ExcludeProperty macType, wwnType, wwpnType, mac, wwnn, wwpn, ApplianceConnection
                    $c.boot = $c.boot | Select-Object -property * -ExcludeProperty bootTargetName, bootTargetLun, initiatorName, initiatorIp, chapName, mutualChapName, chapSecret, mutualChapSecret

                    switch (($c.networkUri.Split('\/'))[2])
                    {

                        'ethernet-networks'
                        {
                        
                            if (-not($_AvailableNetworkResources.ethernetNetworks | Where-Object uri -eq $c.networkUri))
                            {

                                $Message = "The Ethernet network {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                            }

                            else
                            {

                                "[{0}] {1} is available for Connection {2} in this SPT." -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.networkUri, $c.id | Write-Verbose 

                            }
                        
                        }

                        'network-sets'
                        {
                        
                            if (-not($_AvailableNetworkResources.networkSets | Where-Object uri -eq $c.networkUri))
                            {

                                $Message = "The network set {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                            }
                        
                            else
                            {

                                "[{0}] {1} is available for Connection {2} in this SPT." -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.networkUri, $c.id | Write-Verbose 

                            }

                        }

                        {'fc-networks','fcoe-networks' -contains $_}
                        {
                        
                            if (-not($_AvailableNetworkResources.fcNetworks | Where-Object uri -eq $c.networkUri))
                            {

                                $Message = "The FC/FCoE network {0} specified in Connection {1} was not found to be provisioned to the provided Enclosure Group, {2}, and SHT, {3}. Please verify that the network is a member of an Uplink Set in the associated Logical Interconnect Group." -f (Send-HPOVRequest $c.networkUri -Hostname $ApplianceConnection).name, $c.id, $EnclosureGroup.name, $ServerHardwareType.name

                            }
                        
                            else
                            {

                                "[{0}] {1} is available for Connection {2} in this SPT." -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.networkUri, $c.id | Write-Verbose 

                            }

                        }

                    }

                    if ($Message)
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException NetworkResourceNotProvisioned InvalidArgument 'Connections' -TargetType 'PSObject' -Message $Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    if ($null -ne $c.boot -and $c.boot.priority -ne "NotBootable") 
                    {

                        "[{0}] Found bootable connection ID: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $c.id | Write-Verbose

                        [void]$BootableConnections.Add($c.id)

                    }
                    
                    [void]$_spt.connectionSettings.connections.Add($c)

                    $_c++
                
                }
            
                "[{0}] Server Profile Template Connections to add: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_spt.connectionSettings.connections | Format-List * -force | Out-String) | Write-Verbose 

                if (-not $PSBoundParameters['ManageBoot'] -and $BootableConnections.count -gt 0) 
                {

                    $ExceptionMessage = "Bootable Connections {0} were found, however the -ManageBoot switch Parameter was not provided. Please correct your command syntax and try again." -f [String]::Join(', ', $BootableConnections.ToArray())
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException BootableConnectionsFound InvalidArgument 'manageBoot' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                } 

            }

        }

        else
        {

            "[{0}] Setting SPT to not track Connections with derived Server Profiles: {1}." -f $MyInvocation.InvocationName.ToString().ToUpper(), (-not [Bool]$ManageConnections.IsPresent) | Write-Verbose

            $_spt.connectionSettings.manageConnections = $ManageConnections.IsPresent

        }

        # Check to make sure Server Hardware Type supports Firmware Management (OneView supported G7 blade would not support this feature)
        if ($PSBoundParameters['Firmware'])
        {

            if ($PSBoundParameters['FirmwareConsistencyChecking'])
            {

                $_spt.firmware.complianceControl = $ConsistencyCheckingEnum.$FirmwareConsistencyChecking
                
            }

            "[{0}] Firmware Baseline: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Baseline | Write-Verbose

            if ($serverHardwareType.capabilities -contains "FirmwareUpdate" ) 
            {

                "[{0}] SHT is capable of firmware management" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $_spt.firmware.manageFirmware         = [Bool]$firmware
                $_spt.firmware.forceInstallFirmware   = [Bool]$forceInstallFirmware
                $_spt.firmware.firmwareInstallType    = $ServerProfileFirmwareControlModeEnum[$FirmwareInstallMode]
                $_spt.firmware.firmwareActivationType = $ServerProfileFirmareActivationModeEnum[$FirmwareActivationMode]

                if ('FirmwareOffline', 'FirmwareOnlyOfflineMode' -contains $_spt.firmware.firmwareInstallType -and $FirmwareActivationMode -eq 'Scheduled')
                {

                    $ExceptionMessage = "The specifying a scheduled firmware installation and performing offline method is not supported. Please choose an online method."
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileTemplateResourceException InvalidFirmwareInstallMode InvalidArgument 'FirmwareActivateDateTime' -TargetType 'Switch' -Message    $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }

                # Validating that the baseline value is a string type and that it is an SPP name.
                if (($baseline -is [String]) -and (-not ($baseline.StartsWith('/rest'))) -and ($baseline -match ".iso")) 
                {
                    
                    try 
                    {
                        
                        $FirmwareBaslineName = $Baseline.Clone()

                        $Baseline = Get-HPOVBaseline -FileName $Baseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                        If (-not $_BaseLinePolicy)
                        {

                            $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }
                        
                        $_spt.firmware.firmwareBaselineUri = $Baseline.uri
                    
                    }

                    catch 
                    {
                        
                        "[{0}] Error caught when looking for Firmware Baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }
                
                }

                # Validating that the baseline value is a string type and that it is an SPP name.
                elseif (($baseline -is [String]) -and (-not ($baseline.StartsWith('/rest')))) 
                {

                    try 
                    {

                        $FirmwareBaslineName = $Baseline.Clone()

                        $Baseline = Get-HPOVBaseline -SppName $Baseline -ApplianceConnection $ApplianceConnection -ErrorAction SilentlyContinue

                        If (-not $_BaseLinePolicy)
                        {

                            $ExceptionMessage = "The provided Baseline '{0}' was not found." -f $FirmwareBaslineName
                            $ErrorRecord = New-ErrorRecord HPOneView.Appliance.BaselineResourceException BaselineResourceNotFound ObjectNotFound 'Baseline' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_spt.firmware.firmwareBaselineUri = $baseline.uri

                    }

                    catch 
                    {

                        "[{0}] Error caught when looking for Firmware Baseline." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }
        
                # Validating that the baseline value is a string type and that it is the Baseline URI
                elseif (($Baseline -is [String]) -and ($Baseline.StartsWith('/rest'))) 
                {
            
                    Try
                    {

                        $baselineObj = Send-HPOVRequest -Uri $Baseline -Hostname $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                        

                    if ($baselineObj.category -eq "firmware-drivers") 
                    {
                    
                        "[{0}] Valid Firmware Baseline provided: $($baselineObj.baselineShortName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        $_spt.firmware.firmwareBaselineUri = $baselineObj.uri 
                    
                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidBaselineResource ObjectNotFound 'Baseline' -Message "The provided SPP Baseline URI '$($baseline)' is not valid or the correct resource category (expected 'firmware-drivers', received '$($baselineObj.category)'. Please check the -baseline Parameter value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

                # Else we are expecting the SPP object that contains the URI.
                elseif (($Baseline) -and ($Baseline -is [object])) 
                {

                    $_spt.firmware.firmwareBaselineUri = $Baseline.uri
                
                }

                elseif (!$baseline)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareMgmtFeatureNotSupported NotImplemented 'New-HPOVServerProfileTemplate' -Message "Baseline is required if manage firmware is set to true."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }
                
            }

            else 
            {

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareMgmtFeatureNotSupported NotImplemented 'Firmware' -Message "`"$($serverHardwareType.name)`" Server Hardware Type does not support Firmware Management."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
            }

        }
        
        # Check to make sure Server Hardware Type supports Bios Management (OneView supported G7 blade do not support this feature)
        if ($PSBoundParameters['Bios']) 
        {

            if ($serverHardwareType.capabilities -match "ManageBIOS" ) 
            {

                if ($PSBoundParameters['BiosConsistencyChecking'])
                {

                    $_spt.bios.complianceControl = $ConsistencyCheckingEnum.$BiosConsistencyChecking
                    
                }
                    
                if ($BiosSettings.GetEnumerator().Cout -gt 0)
                {

                        # Check for any duplicate keys
                        $biosFlag = $false
                        $hash = @{}
                        $BiosSettings.id | ForEach-Object { $hash[$_] = $hash[$_] + 1 }

                        foreach ($biosItem in ($hash.GetEnumerator() | Where-Object {$_.value -gt 1} | ForEach-Object {$_.key} )) 
                        {
                                
                            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException BiosSettingsNotUnique InvalidOperation 'BiosSettings' -TargetType 'Array' -Message "'$(($serverHardwareType.biosSettings | where { $_.id -eq $biosItem }).name)' is being set more than once. Please check your BIOS Settings are unique. This setting might be a depEndency of another BIOS setting/option."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                    }
                    
                    $_spt.bios.manageBios = $True
                    $_spt.bios.overriddenSettings = $BiosSettings

                }

                else 
                { 

                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerHardwareMgmtFeatureNotSupported NotImplemented 'New-HPOVServerProfile' -Message "`"$($serverHardwareType.name)`" Server Hardware Type does not support BIOS Management."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)                
                
                }

        }

        # Manage Secure Boot settings
        if ($PSBoundParameters['SecureBoot'])
        {

            # Check to make sure Server Hardware supports SecureBoot
            if ($ServerHardwareType.capabilities.Contains('SecureBoot') -and $BootMode -eq 'UEFIOptimized')
            {

                $_spt.bootMode.secureBoot = $SecureBoot

            }

            # Generate exception if not
            elseif ($ServerHardwareType.capabilities.Contains('SecureBoot') -and $BootMode -ne 'UEFIOptimized')
            {

                $ExceptionMessage = 'The Server Hardware Type "{0}" supports managing SecureBoot, but BootMode was not set to "UEFIOptimized".' -f $ServerHardwareType.name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidBootModeManageValue InvalidArgument 'BootMode' -TargetType 'Bool' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif (-not $ServerHardwareType.capabilities.Contains('SecureBoot') -and $BootMode -eq 'UEFIOptimized')
            {

                $ExceptionMessage = 'The Server Hardware Type "{0}" does not support managing SecureBoot.' -f $ServerHardwareType.name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidSecureBootManageValue InvalidArgument 'SecureBoot' -TargetType 'Bool' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        # Set Local Storage Management and Check to make sure Server Hardware Type supports it (OneView supported G7 blade would not support this feature)
        if (($PSBoundParameters['StorageController']) -and ($ServerHardwareType.capabilities.Contains("ManageLocalStorage"))) 
        {

            if ($PSBoundParameters['LocalStorageConsistencyChecking'])
            {

                $_spt.localStorage.complianceControl = $ConsistencyCheckingEnum.$LocalStorageConsistencyChecking
                
            }

            # Loop through Controllers provided by user, which should have LogicalDisks attached.
            ForEach ($_Controller in $StorageController)
            {

                # Copy the object so PowerShell doesn't modify the original object from the caller
                $__controller = $_Controller.PSObject.Copy()

                "[{0}] Processing {1} Controller" -f $MyInvocation.InvocationName.ToString().ToUpper(), $__controller.slotNumber | Write-Verbose
                
                # Check if controll has imporrtConfiguration set to True, which is unsupported with SPT
                if ($__controller.importConfiguration)
                {

                    $Message = "The StorageController configuration contains the -ImportExistingConfiguration option set, which is not supported with Server Profile Templates."
                    $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedImportConfigurationSetting InvalidOperation "StorageController" -TargetType 'PSObject' -Message $Message
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)                        

                }

                "[{0}] SHT supports Controller RAID mode: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($__controller.mode -eq 'RAID' -and ('Mixed','RAID' -notcontains $ServerHardwareType.storageCapabilities.controllerModes)) | Write-Verbose

                # Validate the SHT.storageCapabilities controllerModes -> mode, raidLevels -> logicalDrives.raidLevel and maximumDrives -> numPhysicalDrives
                if ($__controller.mode -eq 'RAID' -and ($ServerHardwareType.storageCapabilities.controllerModes -notcontains 'Mixed' -and $ServerHardwareType.storageCapabilities.controllerModes -notcontains 'RAID'))
                {
                    
                    $_ExceptionMessage = "Unsupported LogicalDisk policy with Virtual Machine Appliance. The requested Controller Mode '{0}' is not supported with the expected Server Hardware Type, which only supports '{1}'" -f $__controller.mode, ([System.String]::Join("', '", $ServerHardwareType.storageCapabilities.controllerModes)) 
                    $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedImportConfigurationSetting InvalidOperation "StorageController" -TargetType 'PSObject' -Message $_ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Controller mode needs to be set to Mixed
                elseif ($__controller.mode -eq 'RAID' -and 'Mixed' -eq $ServerHardwareType.storageCapabilities.controllerModes)
                {

                    $__controller.mode = 'Mixed'

                }

                $_l = 1

                "[{0}] Storage Controller has {1} LogicalDrives to Process" -f $MyInvocation.InvocationName.ToString().ToUpper(), $__controller.logicalDrives.count | Write-Verbose

                "[{0}] Server Hardware supports '{1}' drives." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerHardwareType.storageCapabilities.maximumDrives | Write-Verbose

                $_NewLogicalDisksCollection = [System.Collections.ArrayList]::new()

                # Validate the SHT.storageCapabilities .raidLevels -> logicalDrives.raidLevel and .maximumDrives -> numPhysicalDrives
                ForEach ($_ld in $__controller.logicalDrives)
                {

                    "[{0}] Processing {1} of {2} LogicalDisk: {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_l, $__controller.logicalDrives.count, $_ld.name | Write-Verbose

                    "[{0}] {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ld | Out-String) | Write-Verbose

                    if ($_ld.PSObject.Properties.Match('SasLogicalJBOD').Count)
                    {

                        "[{0}] Processing SasLogicalJbod {1} (ID:{2}) in Controller {3}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ld.SasLogicalJBOD.name, $_ld.SasLogicalJbodId, $__controller.deviceSlot | Write-Verbose

                        If ($ApplianceConnection.ApplianceType -ne 'Composer')
                        {

                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. The LogicalDisk within the StorageController contains a SasLogicalJbod configuration with is only supported with HPE Synergy.' -f $ApplianceConnection.Name)
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        [void]$_spt.localStorage.sasLogicalJBODs.Add($_ld.SasLogicalJBOD)

                        # Needed for D3940 RAID drive attachment
                        if (-not [String]::IsNullOrEmpty($_ld.raidLevel))
                        {

                            $_ld = $_ld | Select-Object * -ExcludeProperty SasLogicalJBOD

                            [Void]$_NewLogicalDisksCollection.Add($_ld)

                        }

                    }

                    else
                    {

                    if ($ServerHardwareType.storageCapabilities.raidLevels -notcontains $_ld.raidLevel)
                    {

                        $_ExceptionMessage = "Unsupported LogicalDisk RAID Level '{0}' policy with '{1}' logical disk. The Server Hardware Type only supports '{2}' RAID level(s). " -f $_ld.raidLevel, $_ld.name, [System.String]::Join("', '", $ServerHardwareType.storageCapabilities.raidLevels) 
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedLogicalDriveRaidLevel InvalidOperation "StorageController" -TargetType 'PSObject' -Message $_ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($_ld.numPhysicalDrives -gt $ServerHardwareType.storageCapabilities.maximumDrives)
                    {

                        $_ExceptionMessage = "Invalid number of drives requested '{0}'. The Server Hardware Type only supports a maximum of '{1}'." -f $_ld.numPhysicalDrives, $ServerHardwareType.storageCapabilities.maximumDrives 
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedNumberofDrives InvalidOperation "StorageController" -TargetType 'PSObject' -Message $_ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_ld = $_ld | Select-Object * -ExcludeProperty SasLogicalJBOD

                    [Void]$_NewLogicalDisksCollection.Add($_ld)

                    }
                    
                    $_l++

                }

                $__controller.logicalDrives = $_NewLogicalDisksCollection

                $__controller = $__controller | Select-Object * -Exclude importConfiguration

                [void]$_spt.localStorage.controllers.Add($__controller)    
            
            }
                                                        
        }

        # StRM Support
        if ($PSBoundParameters['SANStorage'] -and $ServerHardwareType.capabilities -Contains 'VCConnections')
        { 

            "[{0}] SAN Storage being requested" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_spt.sanStorage = NewObject -ServerProfileTemplateSanStorage
            $_spt.sanStorage.hostOSType        = $ServerProfileSanManageOSType[$HostOsType];
            $_spt.sanStorage.manageSanStorage  = [Bool]$SANStorage;

            if ($PSBoundParameters['SANStorageConsistencyChecking'])
            {

                $_spt.sanStorage.complianceControl = $ConsistencyCheckingEnum.$SANStorageConsistencyChecking

            }

            $_AllNetworkUrisCollection  = [System.Collections.ArrayList]::new()

            #Build list of network URI's from connections
            ForEach ($_Connection in ($_spt.connectionSettings.connections | Where-Object { -not $_.networkUri.StartsWith($NetworkSetsUri)})) 
            {

                [void]$_AllNetworkUrisCollection.Add($_Connection.networkUri)

            }

            # Copy the Parameter array into a new object
            $_VolumesToAttach = [System.Collections.ArrayList]::new()

            $StorageVolume | ForEach-Object { 

                if ($_)
                {
                
                    [void]$_VolumesToAttach.Add($_)

                }
                
            }
            
            "[{0}] Number of Volumes to Attach: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumesToAttach.Count | Write-Verbose

            $_v = 0
            
            foreach ($_Volume in $_VolumesToAttach) 
            {  

                $_v++

                "[{0}] Processing Volume {1} of {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_v, $_VolumesToAttach.Count | Write-Verbose

                # Ephemeral Volume Support
                if ($null -eq $_Volume.volumeUri -and $_Volume.volume.properties.storagePool)
                {

                    $_uri        = "{0}?networks='{1}'&filter=uri='{2}'" -f $ReachableStoragePoolsUri, ([String]::Join(',', $_AllNetworkUrisCollection.ToArray())), $_Volume.volume.properties.storagePool
                    $_VolumeName = $_Volume.volume.properties.name
                    $_VolumeUri  = 'StoragePoolUri:{0}' -f $_Volume.volumeStoragePoolUri

                }

                # Provisioned Volume Support
                else
                {

                    Try
                    {

                        $_VolumeName = (Send-HPOVRequest -uri $_Volume.volumeUri).Name

                    }

                    catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $_uri = "{0}?networks='{1}'&filter=name='{2}'" -f $AttachableStorageVolumesUri, ([String]::Join(',', $_AllNetworkUrisCollection.ToArray())), $_VolumeName
                    $_VolumeUri = $_Volume.uri                                        

                }

                "[{0}] Processing Volume ID: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Volume.id | Write-Verbose 
                "[{0}] Looking to see if volume '{1} ({2})' is attachable" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumeName, $_VolumeUri |Write-Verbose 

                try
                {

                    $_resp = Send-HPOVRequest -Uri $_uri -appliance $ApplianceConnection

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Members found
                if ($_resp.count -gt 0)
                {

                    "[{0}] '{1} ({2})' volume is attachable" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumeName, $_VolumeUri | Write-Verbose

                    if (($_Volume.id -eq 0) -or (-not($_Volume.id)))
                    {

                        "[{0}] No VolumeID value provided. Getting next volume id value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $id = 1

                        $Found = $false

                        While (-not $Found -and $id -lt 256)
                        {

                            if (-not($_VolumesToAttach | Where-Object id -eq $id))
                            {

                                "[{0}] Setting Volume ID to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $id | Write-Verbose

                                $_Volume.id = $id

                                $Found = $true

                            }

                            $id++

                        }

                    }

                    # If the storage paths array is null, Process connections to add mapping
                    if ($_Volume.storagePaths.Count -eq 0)
                    {

                        "[{0}] Storage Paths value is Null. Building connection mapping." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        # This should only be 1 within members array
                        foreach ($_member in $_resp.members) 
                        {

                            if ($_Member.deviceSpecificAttributes.iqn -or $_Member.family -eq 'StoreVirtual')
                            {

                                "[{0}] Looking for Ethernet connections." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $_StorageTypeUri = '/rest/ethernet-networks'
                                
                            }

                            else
                            {

                                "[{0}] Looking for FC/FCoE connections." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $_StorageTypeUri = '/rest/fc'

                            }

                            # Figure out which connections "should" map based on identified storage connectivity type
                            [Array]$_ProfileConnections = $_spt.connectionSettings.connections | Where-Object { $_.networkUri.StartsWith($_StorageTypeUri) }

                            "[{0}] Number of connections that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ProfileConnections.Count | Write-Verbose

                            if ($_ProfileConnections.Count -gt 0)
                            {

                                "[{0}] Connections that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', [Array]$_ProfileConnections.id) | Write-Verbose

                            }

                            [Array]$_ReachableNetworkUris = $_Member.reachableNetworks | Where-Object { $_.StartsWith($_StorageTypeUri) }

                            "[{0}] Number of reachable networks that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ReachableNetworkUris.Count | Write-Verbose

                            if ($_ReachableNetworkUris.Count -gt 0)
                            {

                                "[{0}] Reachable networks that match the volume connectivity type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', [Array]$_ReachableNetworkUris) | Write-Verbose

                            }

                            ForEach ($_ReachableNetworkUri in $_ReachableNetworkUris)
                            {

                                "[{0}] Processing reachable network URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ReachableNetworkUri | Write-Verbose

                                ForEach ($_ProfileConnection in ($_ProfileConnections | Where-Object { $_.networkUri -eq $_ReachableNetworkUri }))
                                {

                                    "[{0}] Mapping connectionId '{1}' -> volumeId '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ProfileConnection.id, $_Volume.id | Write-Verbose

                                    $_StoragePath = NewObject -StoragePath

                                    $_StoragePath.connectionId = $_ProfileConnection.id
                                    $_StoragePath.isEnabled    = $True

                                    if ($_Volume.TargetPortAssignmentType)
                                    {

                                        "[{0}] Getting FC network to get associated SAN." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                        #$_uri = "{0}/reachable-ports?query=expectedNetworkUri EQ '{1}'" -f $_VolumeToStorageSystem.uri, $profileConnection.networkUri
                                        $_StoragePath.targetSelector = 'TargetPorts'

                                        Try
                                        {

                                            $_ServerProfileConnectionNetwork = Send-HPOVRequest -Uri $profileConnection.networkUri -Hostname $ServerProfile.ApplianceConnection

                                        }

                                        Catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                        # // TODO: Need to get storage system ports to finalize initiator to target port mapping
                                        $_StorageSystemExpectedMappedPorts = $_AvailStorageSystems.ports | Where-Object expectedSanUri -eq $_ServerProfileConnectionNetwork.managedSanUri

                                        ForEach ($_PortID in $_Volume.TargetAddresses)
                                        {

                                            "[{0}] Looking for {1} host port from available storage system." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PortID | Write-Verbose

                                            if ($WwnAddressPattern.Match($_PortID).Success)
                                            {

                                                $_PortType = 'name'

                                            }

                                            elseif ($StoreServeTargetPortIDPattern.Match($_PortID).Success)
                                            {

                                                $_PortType = 'address'

                                            }

                                            ForEach ($_HostPort in ($_StorageSystemExpectedMappedPorts | Where-Object $_PortType -match $_PortID))
                                            {

                                                "[{0}] Adding {1} ({2}) host port to targets." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_HostPort.address, $_HostPort.name | Write-Verbose

                                                [void]$_StoragePath.targets.Add($_HostPort.address)

                                            }

                                        }

                                    }

                                    [void]$_Volume.storagePaths.Add($_StoragePath)

                                }

                            }

                            if ($_Volume.storagePaths.Count -eq 0)
                            {

                                Write-Warning ('No available connections were found that could attach to {0} Storage Volume. Storage Volumes may not be attached.' -f $_VolumeName)

                            }

                            [void]$_spt.sanStorage.volumeAttachments.Add($_Volume)

                        }

                    }

                    else
                    {
                    
                        [void]$_spt.sanStorage.volumeAttachments.Add($_Volume)
                    
                    }

                }

                # No members found, generate exception
                else
                {

                    $ExceptionMessage = "'{0}' Volume is not available to be attached to the profile. Please check the volume or available storage pools and try again." -f $_VolumeName
                    $ErrorRecord = New-ErrorRecord InvalidOperationException StorageVolumeUnavailableForAttach ResourceUnavailable 'StorageVolume' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

        }

        "[{0}] Profile JSON Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_spt | ConvertTo-Json -depth 99) | Write-Verbose

        if ($PassThru.IsPresent)
        {

            $_spt

        }

        else
        {

            Try
            {

                $resp = Send-HPOVRequest -uri $ServerProfileTemplatesUri -Method POST -Body $_spt -appliance $ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Async'])
            {

                $Resp

            }

            else
            {

                Try
                {

                    $Resp | Wait-HPOVTaskComplete -OutVariable Resp

                    if ($Resp.taskState -eq 'Error')
                    {

                        $ExceptionMessage = $resp.taskErrors.message
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileTemplateResourceException InvalidOperation InvalidOperation 'AsyncronousTask' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

        }        

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }    

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Set-HPOVServerProfileTemplate
{

    Throw "Not implemented."

}

function Join-HPOVServerProfileToTemplate 
{
        
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("t")]
        [object]$Template,

        [Parameter (Mandatory)]
        [Alias ("p", 'Profile')] 
        [object]$ServerProfile,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = $Global:ConnectedSessions

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        # If multiple appliance connections check for URI values in the Parameters
        If($ApplianceConnection.count -gt 1)
        {
            
            If ($template -is [String] -and $template.startswith('/rest/'))
            {

                "[{0}] $template" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidTemplateParameter InvalidArgument 'Template' -Message "Template Parameter as URI is not supported with multiple appliance connections."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            If ($ServerProfile -is [String] -and $ServerProfile.startswith('/rest/'))
            {

                "[{0}] $ServerProfile" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException InvalidProfileParameter InvalidArgument 'ServerProfile' -Message "ServerProfile Parameter as URI is not supported with multiple appliance connections."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        $uri = $ServerProfilesUri

        $colStatus = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {
        
        ForEach($_Connection in $ApplianceConnection)
        {
        
            # Process the template Parameter
            # Template passed as string
            if ($template -is [String])
            {
                
                # If the URI is passed as set the Template Uri variable. Should not Process if multiple connections identified
                if ($template.StartsWith('/rest'))
                { 

                    "[{0}] Template URI: $template" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $templateUri = $template
            
                }

                # Otherwise, perform a lookup of the Enclosure Group
                else
                {

                    "[{0}] Template Name: $template" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose                        
                
                    Try 
                    {

                        $templateUri = (Get-HPOVServerProfileTemplate -Name $template -appliance $ApplianceConnection -ErrorAction Stop).Uri

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                
                }

            }
                                    
            # Else the template object or template object collection is passed
            elseif (($template -is [Object]) -and ($template.category -eq $ResourceCategoryEnum.ServerProfileTemplate)) 
            { 

                "[{0}] Template object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $thisTemplate = $template | Where-Object { $_.ApplianceConnection.name -eq $_Connection.name }

                $templateUri = $thisTemplate.uri

                "[{0}] Enclosure Group Name: $($thisTemplate.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Enclosure Group Uri: $($thisTemplate.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            # Process the profile Parameter
            # Profile passed as string
            if ($ServerProfile -is [String])
            {
                
                # If the URI is passed as set the Template Uri variable. Should not Process if multiple connections identified
                if ($ServerProfile.StartsWith('/rest'))
                { 

                    "[{0}] Template URI: $ServerProfile" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $thisProfile = Send-HPOVRequest $ServerProfile -appliance $_Connection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                
                }

                # Otherwise, perform a lookup of the Enclosure Group
                else
                {

                    "[{0}] Template Name: $ServerProfile" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose                        
                
                    Try
                    {

                        $thisProfile = Get-HPOVServerProfile -Name $ServerProfile -appliance $_Connection -ErrorAction Stop

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }
                                    
            # Else the template object or template object collection is passed
            elseif (($ServerProfile -is [Object]) -and ($ServerProfile.category -eq $ResourceCategoryEnum.ServerProfile)) 
            { 

                "[{0}] Profile object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $thisProfile = $ServerProfile | Where-Object { $_.ApplianceConnection.name -eq $_Connection.name }

                "[{0}] Enclosure Group Name: $($thisProfile.name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Enclosure Group Uri: $($thisProfile.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            if ($thisProfile.ApplianceConnection.name -eq $_Connection.name)
            {
                
                $thisProfile.serverProfileTemplateUri = $templateUri

                Try
                {

                    $task = Set-HPOVResource $thisProfile -appliance $_Connection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [void]$colStatus.Add($task)

            }

        }

    } # End Process Block

    End 
    {

        return $colStatus

    }

}

function Convert-HPOVServerProfileTemplate
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('ServerProfileTemplate', 'SPT')]
        [Object]$InputObject,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$ServerHardwareType,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Object]$EnclosureGroup,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }     

        $_taskCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $_TransformType = [System.Collections.ArrayList]::new()

        $_ServerHardwareTypeUri = $null
        $_EnclosureGroupUri = $null

        # Process InputObject
        if ($InputObject.category -ne $ResourceCategoryEnum.ServerProfileTemplate)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object {0} is not supported. Only Server Profile Template is supported.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Process SHT
        if ($PSBoundParameters['ServerHardwareType'] -and $ServerHardwareType.category -ne $ResourceCategoryEnum.ServerHardwareType)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object {0} is not supported. Only Server Hardware Type is supported.' -f $ServerHardwareType.name
            $ErrorRecord = New-ErrorRecord HPOneview.ServerHardwareTypeResourceException InvalidServerHardwareTypeResource InvalidArgument "ServerHardwareType" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($PSBoundParameters['ServerHardwareType'])
        {

            $_ServerHardwareTypeUri = $ServerHardwareType.uri

            [void]$_TransformType.Add('server hardware type')

        }

        elseif (-not $PSBoundParameters['ServerHardwareType'])
        {

            $_ServerHardwareTypeUri = $InputObject.serverHardwareTypeUri

            [void]$_TransformType.Add('server hardware type')

        }

        # Process EG
        if ($PSBoundParameters['EnclosureGroup'] -and $EnclosureGroup.category -ne $ResourceCategoryEnum.EnclosureGroup)
        {

            # Throw exception
            $ExceptionMessage = 'The provided object {0} is not supported. Only Enclosure Group is supported.' -f $EnclosureGroup.name
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureGroupResourceException InvalidEnclosureGroupResource InvalidArgument "EnclosureGroup" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        # Allow transformation of a Server Profile Template designed for DL/ML/Apollo to BL/WS
        elseif (($PSBoundParameters['EnclosureGroup'] -and $null -ne $InputObject.enclosureGroupUri) -or
                ($PSBoundParameters['EnclosureGroup'] -and $ServerHardwareType.model -match 'BL|WS|SY'))
        {

            $_EnclosureGroupUri = $EnclosureGroup.uri

            [void]$_TransformType.Add('enclosure group')

        }

        elseif (-not $PSBoundParameters['EnclosureGroup'] -and $null -ne $InputObject.enclosureGroupUri)
        {

            $_EnclosureGroupUri = $InputObject.enclosureGroupUri

            [void]$_TransformType.Add('enclosure group')

        }

        elseif ($PSBoundParameters['EnclosureGroup'] -and $null -eq $InputObject.enclosureGroupUri)
        {

            $ExceptionMessage = 'The provided Server Profile Template object {0} is likely a DL/ML/Apollo resource and does not support Enclosure Group objects.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.EnclosureGroupResourceException InvalidEnclosureGroupResource InvalidOperation "EnclosureGroup" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Build final transformation URI
        $_Uri = '{0}/transformation?serverHardwareTypeUri={1}&enclosureGroupUri={2}' -f $InputObject.uri, $_ServerHardwareTypeUri, $_EnclosureGroupUri

        Try
        {

            $_TransformedServerProfileTemplate = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # Show changes preview here.
        ForEach ($_previewChange in $_TransformedServerProfileTemplate.changes.GetEnumerator())
        {

            New-Object HPOneView.ServerProfile.TransformPreview($_previewChange)

        }

        $_ShouldProcessMessage = 'transform the server profile template to new {0}' -f [String]::Join(' and ', $_TransformType.ToArray())

        if ($PSCmdlet.ShouldProcess($InputObject.Name, $_ShouldProcessMessage))
        {

            # Saving results back to appliance
            Try
            {

                $_TransformedServerProfileTemplateResults = Send-HPOVRequest -Uri $InputObject.uri -Method PUT -Body $_TransformedServerProfileTemplate.serverProfileTemplate -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Async'])
            {

                $_TransformedServerProfileTemplateResults | Wait-HPOVTaskComplete

            }

            else
            {

                $_TransformedServerProfileTemplateResults

            }

        }
        
    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function ConvertTo-HPOVServerProfileTemplate
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (
    
        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("source",'ServerProfile')]
        [Object]$InputObject,

        [Parameter (Mandatory = $False)] 
        [String]$Name,

        [Parameter (Mandatory = $False)] 
        [String]$Description,

        [Parameter (Mandatory = $False)] 
        [Switch]$Async,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        # Process Pipeline Input here
        if ($InputObject -is [PSCustomObject])
        {

            "[{0}] Received Server Profile object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

            $_ProfileToConvert = $InputObject.PSObject.Copy()
            $_SourceName       = $InputObject.name.Clone()

        }

        # Process everything else
        else
        {

            "[{0}] Received Server Profile name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

            Try
            {

                $_ProfileToConvert = Get-HPOVServerProfile -Name $InputObject -ErrorAction Stop
                $_SourceName       = $InputObject.Clone()

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

        # Generate SPT from API
        try
        {

            $_uri = '{0}/new-profile-template' -f $_ProfileToConvert.uri

            $_ConvertedSPT = Send-HPOVRequest -Uri $_uri -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSBoundParameters['Name'])
        {

            $_ConvertedSPT.name = $Name

        }

        else
        {

            $_ConvertedSPT.name = "Temporary Name - {0}" -f $_SourceName
        
        }

        if ($PSBoundParameters['Description'])
        {

            $_ConvertedSPT.description = $Description

        }

        else
        {

            $_ConvertedSPT.description = "Created from '{0}' source Server Profile." -f $_SourceName

        }

        try
        {

            $_uri = '{0}/new-profile-template' -f $_ProfileToConvert.uri

            $_result = Send-HPOVRequest -Uri $ServerProfileTemplatesUri -Method POST -Body $_ConvertedSPT -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_result | Wait-HPOVTaskComplete

        }

        else
        {

            $_result

        }                

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVServerProfileTemplate
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdLetBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('spt','name')]
        [Object]$ServerProfileTemplate,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$force
    
    )

   Begin 
   {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['ServerProfileTemplate']))
        {

            $PipelineINput = $true

        }
        
        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {
                
                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
                    
                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        if ($ApplianceConnection.count -gt 1)
        {

            # Check for appliance specific URI Parameters and error if more than one appliance connection supplied
            if (($ServerProfileTemplate -is [String]) -and ($ServerProfileTemplate.StartsWith($ServerProfileTemplatessUri))) 
            {
                    
                "[{0}] SourceName is a Server Profile Template URI: $($ServerProfileTemplate)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'ServerProfileTemplate' -Message "The input Parameter 'ServerProfileTemplate' is a resource URI. For multiple appliance connections this is not supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            }

            if (($ServerProfileTemplate -is [array]) -and ($ServerProfileTemplate.getvalue(0).gettype() -is [String]) -and $ServerProfileTemplate -match '/rest/') 
            {
                
                "[{0}] Assign is a Server Profile URI: $($ServerProfileTemplate)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'ServerProfileTemplate' -Message "The input Parameter 'ServerProfileTemplate' is a resource URI. For multiple appliance connections this is not supported."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

        }

        $taskCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        "[{0}] Profile input type: $($ServerProfileTemplate.gettype())" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        foreach ($_spt in $ServerProfileTemplate) 
        {

            if ($_spt -is [String] -and (-not($_spt.StartsWith.($ServerProfileTemplatessUri)))) 
            {

                Try
                {

                    $_spt = Get-HPOVServerProfileTemplate -Name $_spt -ApplianceConnection $ApplianceConnection -ErrorAction Stop

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($_spt -is [String])
            {

                Try
                {

                    $_spt = Send-HPOVRequest -Uri $_spt -Hostname $ApplianceConnection

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($_spt -is [PSCustomObject] -and $_spt.category -ine $ResourceCategoryEnum.ServerProfileTemplate) 
            {
                
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'ServerProfileTemplate' -Message ("Invalid profile template object provided: {0}. Please verify the object and try again." -f $_spt.name )
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($PSCmdlet.ShouldProcess($ApplianceConnection.Name,("remove Server Profile Template {0} from appliance?" -f $_spt.name )))
            {   
                
                $uri = $_spt.uri

                if ($PSBoundParameters['Force'])
                {

                    $uri += '?force=true'

                }

                Try
                {

                    Send-HPOVRequest -uri $uri -method DELETE -AddHeader @{'If-Match' = $_spt.eTag } -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['Whatif'])
            {

                "[{0}] -WhatIf provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVServerProfileConnectionList 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding ()]
    Param 
    (
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $allConnections = [System.Collections.ArrayList]::new()

    }

    Process 
    {
        
        ForEach($_Connection in $ApplianceConnection)
        {

            $profiles = [System.Collections.ArrayList]::new()
    
            # Get profiles
            if ($Name)
            {

                $uri = "{0}?filter=name='{1}'" -f $ServerProfilesUri, $Name

                Try
                {

                    $profile = (Send-HPOVRequest $uri -appliance $_Connection).members

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not ($profile)) 
                { 

                    $ErrorRecord = New-ErrorRecord InvalidOperationException ProfileResourceNotFound ObjectNotFound 'Get-HPOVServerProfileConnectionList' -Message "Server Profile '$name' was not found."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }
            
                [void]$profiles.Add($profile)
    
            } 

            else 
            {

                Try
                {

                    $index = Send-HPOVRequest -Uri $ServerProfileIndexListUri -appliance $_Connection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

                if ($index.count -eq 0) 
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException ProfileResourceNotFound ObjectNotFound 'Get-HPOVServerProfileConnectionList' -Message "No Server Profile resources found. Use New-HPOVServerProfile to create one."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)            
                    
                }
    
                foreach ($entry in $index.members)
                {

                    Try
                    {

                        $profile = Send-HPOVRequest $entry.uri -appliance $_Connection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }
    
                    [void]$profiles.Add($profile)

                }     
                       
            }
    
            # Get connections
            $conns = [System.Collections.ArrayList]::new()

            foreach($p in $profiles)
            {
    
                foreach($c in $p.connectionSettings.connections) 
                { 

                    Try
                    {

                        $c | add-member -membertype noteproperty -name cid -value $c.id;
                        $c | add-member -membertype noteproperty -name serverProfile -value $p.name;
                        $c | add-member -membertype NoteProperty -name Network -value (Send-HPOVRequest $c.networkUri -appliance $_Connection).Name
                        $c | Add-Member -NotePropertyName Appliance -NotePropertyValue $_Connection.name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                    if($c.boot.targets) 
                    {

                        $c | add-member -membertype noteproperty -name arrayTarget -value $c.boot.targets[0].arrayWwpn
                        $c | add-member -membertype noteproperty -name lun -value $c.boot.targets[0].lun

                    }
    
                    if($c.portId) 
                    { 

                        $c.portId = $c.portId.Replace("Flexible", "")

                    } 

                    else 
                    {
                         
                        $name = "Dev:" + $c.deviceNumber + '-' + $c.physicalPortNumber

                        $c | add-member -membertype noteproperty -name portId -value $name

                    }
    
                   if($c.boot) { $c.boot = $c.boot.priority; }

                   if($c.boot -eq "NotBootable") { $c.boot = "-"; }      
                   
                   [void]$conns.Add($c)

                }

            }

            # Output
            [void]$allConnections.Add($conns)
        
        }   

    }
    
    End 
    {

        $allConnections | Sort-Object serverProfile, cid | format-table -Property serverProfile, cid, portId, functionType, Network, mac, wwpn, boot, arrayTarget, lun, Appliance  -AutoSize

    } 

}

function New-HPOVServerProfileConnection 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdLetBinding (DefaultParameterSetName = "Common")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Common")]
        [Parameter (Mandatory, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory, ParameterSetName = "FC")]
        [Parameter (Mandatory, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Alias ('id')]
        [Int]$ConnectionID = 1,

        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ("Ethernet", "FibreChannel", "Eth", "FC", 'FCoE', 'iSCSI', IgnoreCase)]
        [Alias ('type')]
        [String]$ConnectionType = "Ethernet",

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Common")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "FC")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [object]$Network,

        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$PortId = "Auto",

        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateScript( { [String]$_ -eq 'Auto' -or ([Int]$_ -le 20000 -and [Int]$_ -ge 100) })]
        [String]$RequestedBW = 2500,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Switch]$UserDefined,

        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateScript({$MacAddressPattern.Match($_).Success})]
        [String]$MAC,
    
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [ValidateScript({$WwnAddressPattern.Match($_).Success})]
        [String]$WWNN,
        
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [ValidateScript({$WwnAddressPattern.Match($_).Success})]
        [String]$WWPN,

        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [ValidateScript( { [Int]$_ -ge 0 -or [String]$_ -eq 'Auto' } )] 
        [String]$Virtualfunctions,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Bootable,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateSet ('LAG1', 'LAG2', 'LAG3', 'LAG4', 'LAG5', 'LAG6', 'LAG7', 'LAG8', 'LAG9', 'LAG10', 'LAG11', 'LAG12', 'LAG13', 'LAG14', 'LAG15', 'LAG16', 'LAG17', 'LAG18', 'LAG19', 'LAG20', 'LAG21', 'LAG22', 'LAG23', 'LAG24')]
        [String]$LagName,

        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateSet ('AdapterBIOS', 'ManagedVolume', 'UserDefined', IgnoreCase = $false)]
        [String]$BootVolumeSource = 'AdapterBIOS',
    
        [Parameter (Mandatory = $false, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('NotBootable', 'Primary', 'Secondary', 'IscsiPrimary', 'IscsiSecondary', 'LoadBalanced', IgnoreCase)]
        [String]$Priority = "NotBootable",
    
        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Alias ('ArrayWwpn')]
        [ValidateScript({$WwnAddressPattern.Match($_).Success})]
        [String]$TargetWwpn,

        [Parameter (Mandatory = $false, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateRange(0,254)]
        [Int]$LUN = 0,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateSet ('DHCP', 'UserDefined', 'SubnetPool', IgnoreCase)]
        [String]$IscsiIPv4AddressSource,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$ISCSIInitatorName,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Net.IPAddress]$IscsiIPv4Address,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$IscsiIPv4SubnetMask,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Net.IPAddress]$IscsiIPv4Gateway,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$IscsiBootTargetIqn,
    
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Net.IPAddress]$IscsiPrimaryBootTargetAddress,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateRange(1,65535)]
        [Int]$IscsiPrimaryBootTargetPort = 3260,
        
        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Net.IPAddress]$IscsiSecondaryBootTargetAddress,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateRange(1,65535)]
        [Int]$IscsiSecondaryBootTargetPort = 3260,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateSet ('None','CHAP','MutualCHAP')]
        [String]$IscsiAuthenticationProtocol,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$ChapName,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$ChapSecret,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [String]$MutualChapName,

        [Parameter (Mandatory = $false, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$MutualChapSecret,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Common")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Ethernet")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "FC")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "ISCSI")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        "[{0}] ParameterSetName: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSCmdlet.ParameterSetName | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($PSBoundParameters['Network'])
        {

            if ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            $Pipeline = $true

        }        

        # Validate Boot settings
        if (('FC','FibreChannel' -contains $ConnectionType) -and $BootVolumeSource -eq 'UserDefined' -and (-not $TargetWwpn))
        {

            $Message     = 'A bootable Fibre Channel connection that is set for "UserDefined" must have the -TargetWwpn Parameter specified.'
            $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException NoTargetWwpnParam InvalidArgument 'BootVolumeSource' -Message $Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
                
        # Init object collection
        $_Connections = [System.Collections.ArrayList]::new()

    }

    Process 
    {    

        if ($Pipeline)
        {

            $ApplianceConnection = ($ConnectedSessions | Where-Object Name -eq $Network.ApplianceConnection.Name)
            
        }

        # Also sets connection functionType property
        switch ($Network.Gettype().Name) 
        {

            "PSCustomObject" 
            {

                if ("fcoe-networks", "fc-networks", "ethernet-networks", "network-sets" -contains $Network.category) 
                {
                
                    "[{0}] Network resource provided via Parameter" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                    "[{0}] Network Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Network.name | Write-Verbose 
                    "[{0}] Network Category: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Network.category | Write-Verbose 
                    "[{0}] Creating ConnectionType: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ConnectionType | Write-Verbose 

                    switch ($Network.category)
                    {

                        {"ethernet-networks", "network-sets" -contains $_}
                        {

                            if ($ConnectionType -eq 'iSCSI' -or ('IscsiPrimary', 'IscsiSecondary' -contains $Priority) -or $PSCmdlet.ParameterSetName -eq "ISCSI")
                            {

                                $_conn = NewObject -ServerProfileIscsiConnection

                            }

                            else
                            {

                                $_conn = NewObject -ServerProfileEthernetConnection

                            }

                        }

                        {"fcoe-networks", "fc-networks" -contains $_}
                        {

                            $_conn = NewObject -ServerProfileFCConnection

                        }

                    }
                        
                    $_conn.id = [Int]$connectionId;

                    if (-not $PSBoundParameters['ConnectionType'])
                    {

                        $_conn.functionType = [String]$ServerProfileConnectionTypeEnum[$Network.category];

                    }

                    else
                    {

                        $_conn.functionType = [String]$ServerProfileConnectionTypeEnum[$ConnectionType];

                    }
                    
                    $_conn.name                = [String]$name;
                    $_conn.portId              = [String]$portId; 
                    $_conn.requestedMbps       = [Int]$requestedBW; 
                    $_conn.ApplianceConnection = $Network.ApplianceConnection
                    $_conn.networkUri          = $Network.uri

                    if ($PSBoundParameters['LagName'] -and $_conn.functionType -eq 'Ethernet' -and $ApplianceConnection.ApplianceType -eq 'Composer')
                    {

                        $_conn.lagName = $LagName

                    }

                    elseif ($PSBoundParameters['LagName'] -and $ApplianceConnection.ApplianceType -ne 'Composer')
                    {

                        $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. The LagName is only supported with HPE Synergy.' -f $ApplianceConnection.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($PSBoundParameters['LagName'])
                    {

                        $ExceptionMessage = "The -Network value category '{0}' does not support LAG configuration. The LagName parameter is only supported with Ethernet connections." -f $Network.category
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException InvalidLagConfiguration InvalidArgument 'Network' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }
                
                }

                # Generate Error due to incorrect cagtegory
                else 
                {

                    $ExceptionMessage = "The -Network value category '{0}' is not 'ethernet-networks', 'fc-networks' or 'network-sets'. Please check the value and try again." -f $Network.category
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException InvalidNetworkCategory InvalidArgument 'Network' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            default 
            {

                $ExceptionMessage = "The -Network paramter is an invalid type, {0}. Please supply a network object or object collection." -f $Network.GetType().Name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException InvalidNetworkCategory InvalidArgument 'Network' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        # Set conneciton boot settings
        if ($PSboundParameters['Bootable'])
        {

            if ($Priority -eq 'NotBootable')
            {

                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException InvalidBootPriority InvalidArgument 'Priority' -Message "The Connection is set to be bootable, however no priority value was set. Please provide either 'Primary' or 'Secondary'."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($_conn.functionType -eq 'FibreChannel') 
            {

                "[{0}] FibreChannel Connection. Processing boot settings." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_conn.boot = NewObject -ServerProfileFcBootableConnection
                $_conn.boot.bootVolumeSource = $BootVolumeSource

                If((-not $PSBoundParameters['TargetWwpn']) -and $BootVolumeSource -eq "UserDefined")
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException InvalidFcBootTargetParameters InvalidArgument 'TargetWwpn' -Message "FC Boot specified, and no array target WWPN is provided."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                if ($PSBoundParameters['TargetWwpn'])
                {

                    $_conn.boot.bootVolumeSource = 'UserDefined'

                    $bootTarget = NewObject -ServerProfileConnectionFcBootTarget
                    
                    $bootTarget.arrayWwpn = $TargetWwpn
                    $bootTarget.lun       = $lun.ToString()

                    [void]$_conn.boot.targets.Add($bootTarget)

                }

            }

            else
            {

                if ($PSCmdlet.ParameterSetName -eq 'ISCSI' -or $ConnectionType -eq 'iSCSI')
                {

                    # Software iSCSI only supported with Synergy
                    if ($ConnectionType -eq 'Ethernet' -and $ApplianceConnection.ApplianceType -ne 'Composer')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message ('The ApplianceConnection {0} is not a Synergy Composer. The LogicalDisk within the StorageController contains a SasLogicalJbod configuration with is only supported with HPE Synergy.' -f $ApplianceConnection.Name)
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    # HW iSCSI Connection
                    if ($ConnectionType -eq 'ISCSI')
                    {

                        "[{0}] Connection will be HW iSCSI type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_conn.boot = NewObject -ServerProfileIscsiBootableConnectionWithTargets

                    }

                    # SW iSCSI Connection
                    elseif ($ConnectionType -eq 'Ethernet')
                    {

                        "[{0}] Connection will be SW iSCSI type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_conn.boot                  = NewObject -ServerProfileEthBootableConnectionWithTargets
                        $_conn.boot.ethernetBootType = 'iSCSI'                        

                    }

                    $_conn.boot.iscsi = NewObject -IscsiBootEntry
                    # $_conn.ipv4 | Add-Member -NotePropertyName ipv4 -NotePropertyValue (NewObject -IscsiIPv4Configuration)
                    $_conn.ipv4 = NewObject -IscsiIPv4Configuration

                    if ($PSBoundParameters['BootVolumeSource'])
                    {

                        $_conn.boot.bootVolumeSource = $BootVolumeSource

                    }

                    elseif ($_conn.functionType -eq 'Ethernet')
                    {

                        $_conn.boot.bootVolumeSource = 'UserDefined'

                    }

                    else
                    {

                        $ExceptionMessage = 'The connection is bootable, but the -BootVolumeSource parameter was not provided. Please specify a BootVOlumeSource value.'
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileConnectionException InvalidBootableConnectionParameters InvalidArgument 'Bootable' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)                        

                    }

                    if ($PSBoundParameters['IscsiIPv4AddressSource'])
                    {

                        switch ($IscsiIPv4AddressSource)
                        {

                            'UserDefined'
                            {

                                "[{0}]Setting iSCSI connection IPv4 settings will be 'UserDefined'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $_conn.ipv4.ipAddressSource = 'UserDefined'

                                if ($PSBoundParameters['IscsiIPv4Address'] -or $PSBoundParameters['IscsiIPv4SubnetMask'])
                                {                    

                                    "[{0}]Setting iSCSI connection IPv4 Address: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IscsiIPv4Address.IPAddressToString | Write-Verbose
                                    "[{0}]Setting iSCSI connection IPv4 Gateway: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IscsiIPv4Gateway.IPAddressToString | Write-Verbose

                                    if ($PSBoundParameters['IscsiIPv4SubnetMask'].Length -le 2)
                                    {

                                        Try
                                        {

                                            "[{0}] Converting Subnet CIDR Bit value to Subnet Mask Address." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                            [Int64]$_Int64Value = ([convert]::ToInt64(('1' * $IscsiIPv4SubnetMask + '0' * (32 - $IscsiIPv4SubnetMask)), 2))

                                            [IPAddress]$IscsiIPv4SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($_Int64Value / 16777216)).ToString(),
                                                                                ([math]::Truncate(($_Int64Value % 16777216) / 65536)).ToString(),
                                                                                ([math]::Truncate(($_Int64Value % 65536)/256)).ToString(),
                                                                                ([math]::Truncate($_Int64Value % 256)).ToString()

                                        }

                                        Catch
                                        {

                                            $PSCmdlet.ThrowTerminatingError($_)

                                        }

                                    }

                                    $_conn.ipv4.ipAddress  = $IscsiIPv4Address.IPAddressToString
                                    $_conn.ipv4.subnetMask = ([IPAddress]$IscsiIPv4SubnetMask).IPAddressToString
                                    $_conn.ipv4.gateway    = $IscsiIPv4Gateway.IPAddressToString

                                }

                            }
                            
                            default
                            {

                                if ($IscsiIPv4AddressSource -eq 'SubnetPool' -and $ApplianceConnection.ApplianceType -ne 'Composer')
                                {

                                    $ExceptionMessage = 'The ApplianceConnection {0} is not a Synergy Composer. The LogicalDisk within the StorageController contains a SasLogicalJbod configuration with is only supported with HPE Synergy.' -f $ApplianceConnection.Name
                                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ComposerNodeException InvalidOperation InvalidOperation 'ApplianceConnection' -Message $ExceptionMessage
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                                $_conn.ipv4.ipAddressSource = $IscsiIPv4AddressSource

                            }

                        }

                    }

                    if ($PSBoundParameters['ISCSIInitatorName'])
                    {

                        $_conn.boot.iscsi.initiatorNameSource = "UserDefined"
                        $_conn.boot.iscsi.initiatorName       = $ISCSIInitatorName

                    }

                    if ($PSBoundParameters['IscsiAuthenticationProtocol'])
                    {

                        "[{0}] Setting iSCSI auth protocol" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                        
                        $_conn.boot.iscsi.chapLevel = $IscsiAuthenticationProtocol
                        
                        switch ($IscsiAuthenticationProtocol)
                        {

                            'Chap'
                            {

                                "[{0}] CHAP" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                                $_conn.boot.iscsi.chapName = $ChapName

                                if ($PSBoundParameters['ChapSecret'])
                                {

                                    "[{0}] Setting CHAP secret." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
                                    $_conn.boot.iscsi.chapSecret = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ChapSecret))

                                }                        

                            }

                            'MutualChap'
                            {

                                "[{0}] MutualCHAP" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                                $_conn.boot.iscsi.chapName       = $ChapName
                                $_conn.boot.iscsi.mutualChapName = $MutualChapName

                                if ($PSBoundParameters['ChapSecret'])
                                {

                                    "[{0}] Setting CHAP secret." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                                    $_conn.boot.iscsi.chapSecret = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ChapSecret))

                                }    

                                if ($PSBoundParameters['MutualChapSecret'])
                                {

                                    "[{0}] Setting MutualCHAP secret." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

                                    $_conn.boot.iscsi.mutualChapSecret = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($MutualChapSecret))

                                }                        

                            }

                        }

                    }
                    
                    if ($PSBoundParameters['IscsiPrimaryBootTargetAddress'])
                    {

                        "[{0}] Setting iSCSI Primary boot target: {1}:{2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IscsiPrimaryBootTargetAddress.IPAddressToString, $IscsiPrimaryBootTargetPort | Write-Verbose 

                        $_conn.boot.bootVolumeSource          = 'UserDefined'
                        $_conn.boot.iscsi.firstBootTargetIp   = $IscsiPrimaryBootTargetAddress.IPAddressToString
                        $_conn.boot.iscsi.firstBootTargetPort = $IscsiPrimaryBootTargetPort

                    }
                    

                    if ($PSBoundParameters['IscsiSecondaryBootTargetAddress'])
                    {

                        "[{0}] Setting iSCSI Secondary boot target: {1}:{2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IscsiSecondaryBootTargetAddress.IPAddressToString, $IscsiSecondaryBootTargetPort | Write-Verbose 

                        $_conn.boot.iscsi.secondBootTargetIp   = $IscsiSecondaryBootTargetAddress.IPAddressToString
                        $_conn.boot.iscsi.secondBootTargetPort = $IscsiSecondaryBootTargetPort

                    }

                    "[{0}] Setting iSCSI boot target name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $IscsiBootTargetIqn | Write-Verbose 
                    "[{0}] Setting iSCSI boot target LUN: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LUN | Write-Verbose 
                    
                    $_conn.boot.iscsi.bootTargetName = $IscsiBootTargetIqn
                    $_conn.boot.iscsi.bootTargetLun  = $LUN

                }

                else
                {

                    "[{0}] Ethernet type Connection. Processing boot settings." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                    $_conn.boot = NewObject -ServerProfileEthBootableConnection

                }
                
            }

            "[{0}] Connection object boot priority: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ServerProfileConnectionBootPriorityEnum[$Priority] | Write-Verbose 

            $_conn.boot.priority = $ServerProfileConnectionBootPriorityEnum[$Priority]            

        }        

        if ($PSboundParameters['Virtualfunctions'] -and $_conn.functionType -eq 'Ethernet' -and $PSCmdlet.ParameterSetName -ne 'ISCSI') 
        {

            $_conn.requestedVFs = $Virtualfunctions

        }

        if ($PSboundParameters['UserDefined'])
        {

            if ($_conn.functionType -eq 'Ethernet')
            {

                $_conn.macType = "UserDefined"
                $_conn.mac     = $mac

            }

            if ($_conn.functionType -eq "FibreChannel")
            {

                if($PSBoundParameters['mac'])
                {

                    $_conn.macType  = "UserDefined" 
                    $_conn.mac      = $mac 

                }

                $_conn.wwpnType = "UserDefined" 
                $_conn.wwnn     = $wwnn
                $_conn.wwpn     = $wwpn 

            }

        }

        # $_conn = $_conn | Select-Object * -Exclude requestedVFs

        "[{0}] Connection object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_conn | ConvertTo-Json) | Write-Verbose 

        $_conn
 
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 

    }

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Add-HPOVServerProfileConnection
{

    <#
 
    # .ExternalHelp HPOneView.500.psm1-help.xml
     
    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (
 
        # Server Profile resource
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'PassThru')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,
 
        # Connections to add, from New-HPOVServerProfileConnection helper Cmdlet
        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'PassThru')]
        [ValidateNotNullOrEmpty()]
        [Object]$Connections,
 
        [Parameter (Mandatory, ParameterSetName = 'PassThru')]
        [Switch]$PassThru,
 
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Switch]$Async,
 
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default']
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'PassThru']
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | ? Default)
 
    )
 
    #>




    Throw "Not implemented."

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Set-HPOVServerProfileConnection
{

    <#
 
    # .ExternalHelp HPOneView.500.psm1-help.xml
     
    [CmdletBinding (DefaultParameterSetName = "ConnectionName")]
    Param
    (
 
        # Server Profile resource
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ConnectionName")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,
 
        [Parameter (Mandatory, ParameterSetName = "ConnectionName")]
        [ValidateNotNullOrEmpty()]
        [String]$ConnectionName,
 
        [Parameter (Mandatory, ParameterSetName = "ConnectionID")]
        [ValidateNotNullOrEmpty()]
        [Int]$ConnectionID
 
        # Should contain the simliar parameters from New-HPOVServerProfileConnection
 
        [Object]$Network,
 
        [Int]$TypicalBandwidth,
 
        [Int]$MaximumBandwidth,
 
        [Boolean]$Bootable,
 
        [String]$BootPriority,
 
        [Parameter (Mandatory, ParameterSetName = 'PassThru')]
        [Switch]$PassThru,
 
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Switch]$Async,
 
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | ? Default)
 
    )
 
    #>


    Throw "Not implemented."

}

# // TODO: DEVELOP DOCUMENTATION TEST
function Remove-HPOVServerProfileConnection
{

    <#
 
    # .ExternalHelp HPOneView.500.psm1-help.xml
     
    [CmdletBinding (DefaultParameterSetName = "ConnectionName")]
    Param
    (
 
        # Server Profile resource
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ConnectionName")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "PassThru")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,
 
        [Parameter (Mandatory, ParameterSetName = "ConnectionName")]
        [ValidateNotNullOrEmpty()]
        [String]$ConnectionName,
 
        [Parameter (Mandatory, ParameterSetName = "ConnectionID")]
        [ValidateNotNullOrEmpty()]
        [Int]$ConnectionID
 
        [Parameter (Mandatory, ParameterSetName = 'PassThru')]
        [Switch]$PassThru,
 
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Switch]$Async,
 
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | ? Default)
 
    )
 
    #>


    Throw "Not implemented."

}

function Save-HPOVServerProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        # Server Profile resource
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        If (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($InputObject.category -ne $ResourceCategoryEnum.ServerProfile)
        {

            $ExceptionMessage = 'The provided object {0} is not supported. Only Server Profile are supported resources.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Attempting to save '{1}' Server Profile resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        $_method = "PUT"

        # If eTag property is null, then this profile needs to be created.
        if (-not $InputObject.eTag)
        {

            $_method = "POST"

        }

        Try
        {

            $_Resp = Send-HPOVRequest -Uri $InputObject.uri -Method $_method -Body $InputObject -Hostname $InputObject.ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_Resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_Resp

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Save-HPOVServerProfileTemplate
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        # Server Profile resource
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        If (-not $PSBoundParameters['InputObject'])
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($InputObject.category -ne $ResourceCategoryEnum.ServerProfileTemplate)
        {

            $ExceptionMessage = 'The provided object {0} is not supported. Only Server Profile Template are supported resources.' -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Attempting to save '{1}' Server Profile Template resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

        $_method = "PUT"

        # If eTag property is null, then this profile needs to be created.
        if (-not $InputObject.eTag)
        {

            $_method = "POST"

        }

        Try
        {

            $_Resp = Send-HPOVRequest -Uri $InputObject.uri -Method $_method -Body $InputObject -Hostname $InputObject.ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $PSBoundParameters['Async'])
        {

            $_Resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_Resp

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVServerProfileLogicalDisk 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false , ParameterSetName = "SynergyJBOD")]
        [ValidateSet ('RAID0', 'RAID1', 'RAID1ADM', 'RAID10', 'RAID5', 'RAID6', 'NONE')]
        [String]$RAID = 'RAID1',

        [Parameter (Mandatory = $false , ParameterSetName = "Default")]
        [Parameter (Mandatory = $false , ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [Int]$NumberofDrives = 2,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SynergyJBOD")]
        [ValidateSet ('SAS', 'SATA', 'SASSSD', 'SATASSD', 'NVMeSas', 'NVMeSata', 'Auto')]
        [String]$DriveType = 'Auto',

        [Parameter (Mandatory = $false, ParameterSetName = "SynergyJBOD")]
        [ValidateSet ('DriveType', 'SizeAndTechnology')]
        [String]$DriveSelectionBy = 'SizeAndTechnology',

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Storage.AvailableDriveType]$AvailableDriveType,

        [Parameter (Mandatory = $false , ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SynergyJBOD")]
        [ValidateSet ('Internal', 'External')]
        [String]$StorageLocation = "External",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('Enabled', 'Disabled', "SsdSmartPath", "Unmanaged")]
        [String]$Accelerator = "Unmanaged",

        [Parameter (Mandatory = $false, ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [Int]$MinDriveSize,

        [Parameter (Mandatory = $False, ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [Int]$MaxDriveSize,

        [Parameter (Mandatory = $False, ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [Bool]$EraseDataOnDelete = $false,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "SynergyJBOD")]
        [ValidateNotNullOrEmpty()]
        [Bool]$Bootable

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Helper cmdlet does not require authentication." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
        # Init object collection
        $_LogicalDiskCol = [System.Collections.ArrayList]::new()
        if ($PSCmdlet.ParameterSetName -eq 'Default' -and $StorageLocation -eq 'External')
        {

            $StorageLocation = 'Internal'

        }

    }

    Process 
    {

        switch ($PSCmdlet.ParameterSetName)
        {

            'Default'
            {

                # Perform validation
                if ($RAID -eq 'RAID1' -and $NumberofDrives -ne 2)
                {

                    $ExceptionMessage = "The specified RAID Mode 'RAID1' is invalid with more or less than 2 drives. Please correct either the -RAID or -NumberofDrives parameter to the supported value."
                    $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException InvalidRaidModeForNumberofDrives InvalidArgument "NumberofDrives" -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif ($RAID -eq 'RAID1ADM' -and $NumberofDrives -ne 3)
                {

                    $ExceptionMessage = "The specified RAID Mode 'RAID1ADM' is invalid with more or less than 3 drives. Please correct either the -RAID or -NumberofDrives parameter to the supported value."
                    $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException InvalidRaidModeForNumberofDrives InvalidArgument "NumberofDrives" -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $_LogicalDisk = NewObject -ServerProfileLocalStorageLogicalDrive

                $_LogicalDisk.name              = $Name
                $_LogicalDisk.bootable          = [Bool]$Bootable
                $_LogicalDisk.raidLevel         = $RAID.ToUpper()
                $_LogicalDisk.numPhysicalDrives = $NumberofDrives
                $_LogicalDisk.driveTechnology   = $LogicalDiskTypeEnum[$DriveType]

                if ($PSBoundParameters['Accelerator'])
                {

                    Switch ($Accelerator)
                    {

                        'SsdSmartPath'
                        {

                            if ($DriveType -Match "SSD")
                            {

                                $_LogicalDisk.accelerator = "IOBypass"

                            }

                            else
                            {

                                $ExceptionMessage = "Accelerator parameter value 'SsdSmartPath' is only supported with SSD drives."
                                $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "Accelerator" -Message $ExceptionMessage
                                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                            }

                        }

                        "Enabled"
                        {

                            $_LogicalDisk.accelerator = "ControllerCache"

                        }

                        "Disabled"
                        {

                            $_LogicalDisk.accelerator = "None"

                        }

                        # "Unmanaged" is the default setting from NewObject call

                    }

                }

            }

            'SynergyJBOD'
            {

                $_SasLogicalJBOD = NewObject -ServerProfileSasLogicalJBOD
                $_LogicalDisk    = NewObject -ServerProfileLocalStorageLogicalDrive
                
                $_SasLogicalJBOD.id                = 1;
                $_SasLogicalJBOD.name              = $Name
                $_SasLogicalJBOD.eraseData         = $EraseDataOnDelete
                $_SasLogicalJBOD.numPhysicalDrives = $NumberofDrives

                if ($AvailableDriveType)
                {

                    $_SasLogicalJBOD.driveTechnology = $LogicalDiskTypeEnum[$AvailableDriveType.Type]
                    $_SasLogicalJBOD.driveMinSizeGB  = $AvailableDriveType.Capacity
                    $_SasLogicalJBOD.driveMaxSizeGB  = $AvailableDriveType.Capacity

                }

                else
                {

                    $_SasLogicalJBOD.driveMinSizeGB  = $MinDriveSize
                    $_SasLogicalJBOD.driveMaxSizeGB  = if (-not $PSBoundParameters['MaxDriveSize']) { $MinDriveSize } Else { $MaxDriveSize }
                    $_SasLogicalJBOD.driveTechnology = $LogicalDiskTypeEnum[$DriveType]

                }                

                if ($PSBoundParameters['RAID'])
                {

                    if ($DriveType -eq 'Auto' -and -not $AvailableDriveType -and $StorageLocation -eq 'External')
                    {

                        $ExceptionMessage = "DriveType parameter must not be 'Auto' when configuring an HP Synergy D3940 LogicalDisk."
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "DriveType" -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if ($RAID -eq 'RAID1' -and $NumberofDrives -ne 2)
                    {

                        $ExceptionMessage = "The specified RAID Mode 'RAID1' is invalid with more or less than 2 drives. Please correct either the -RAID or -NumberofDrives parameter to the supported value."
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException InvalidRaidModeForNumberofDrives InvalidArgument "NumberofDrives" -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif ($RAID -eq 'RAID1ADM' -and $NumberofDrives -ne 3)
                    {

                        $ExceptionMessage = "The specified RAID Mode 'RAID1ADM' is invalid with more or less than 3 drives. Please correct either the -RAID or -NumberofDrives parameter to the supported value."
                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException InvalidRaidModeForNumberofDrives InvalidArgument "NumberofDrives" -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_LogicalDisk.raidLevel        = $RAID.ToUpper()
                    $_LogicalDisk.sasLogicalJBODId = 1
                    $_LogicalDisk.bootable         = [Bool]$Bootable

                }

                else
                {

                    $_LogicalDisk.sasLogicalJBODId = 1

                }

                $_LogicalDisk | Add-Member -NotePropertyName SasLogicalJBOD -NotePropertyValue $_SasLogicalJBOD -Force
                
            }

        }       

        "[{0}] Created Logical Disk object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_LogicalDisk | Format-List * | Out-String) | Write-Verbose

        $_LogicalDisk
        
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVServerProfileLogicalDiskController
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [ValidateSet ('Embedded','Mezz 1','Mezz 2','Mezz 3','Mezz 3')]
        [Object]$ControllerID = 'Embedded',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [ValidateSet ('HBA','RAID','MIXED')]
        [String]$Mode = 'RAID',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [Switch]$Initialize,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [ValidateSet ('Enabled', 'Disabled', "Unmanaged")]
        [String]$WriteCache = "Unmanaged",

        [Parameter (Mandatory = $false, ParameterSetName = "Import")]
        [Switch]$ImportExistingConfiguration,

        [Parameter (Mandatory = $false, ParameterSetName = "Default", ValueFromPipeline)]
        [Object]$LogicalDisk

    )
        
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Helper cmdlet does not require authentication." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
        # Init object collection
        $_ServerProfileController = NewObject -ServerProfileLocalStorageController
        $_ServerProfileController.deviceSlot          = $ControllerID
        $_ServerProfileController.mode                = $Mode

        if ($ControllerID -notmatch 'Mezz')
        {

            $_ServerProfileController.importConfiguration = $ImportExistingConfiguration.IsPresent
            $_ServerProfileController.initialize          = $Initialize.IsPresent

        }

        if ($PSBoundParameters['WriteCache'])
        {

            "[{0}] Setting controller write cache: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $WriteCache | Write-Verbose

            $_ServerProfileController.driveWriteCache = $WriteCache

        }

        $_id = 1

    }

    Process
    {    

        # THIS IS NOT CORRECT. HBA MODE SUPPORTS LOGICALDISK
        # # Generate terminating error
        # if ($PSBoundParameters['Mode'] -eq 'HBA' -and $PSBoundParameters['LogicalDisk'])
        # {

        # $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "Mode" -Message "The provide 'HBA' mode does not support assigning of Logical Disks."
        # $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        # }

        if ($PSBoundParameters['ImportExistingConfiguration'] -and $PSBoundParameters['LogicalDisk'])
        {

            $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException SupportedParameterUse InvalidArgument "ImportExistingConfiguration" -Message "Combining ImportExistingConfiguration and LogicalDisk Parameters is not supported."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Is an Array
        if ($LogicalDisk -is [System.Collections.IEnumerable])
        {

            "[{0}] Processing LogicalDisks collection" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose            

            ForEach ($_ld in $LogicalDisk)
            {

                "[{0}] {1} of {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ld, $LogicalDisk.Count | Write-Verbose

                if ($_ld.SasLogicalJBOD)
                {

                    if ($_ServerProfileController.deviceSlot -eq 'Embedded')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "LogicalDisks" -TargetType 'PSObject' -Message "The provided Logical Disks contains a SAS JBOD policy, which is not supported with the 'Embedded' Controller."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    $_ld.SasLogicalJBOD.deviceSlot = $_ServerProfileController.deviceSlot

                    # Figure out new SasLogicalJBODId
                    if ($_ServerProfileController.logicalDrives.sasLogicalJbod.id)
                    {

                        while ($_ServerProfileController.logicalDrives.sasLogicalJbod.id -contains $_id)
                        {

                            $_id++

                        }            

                    }

                    $_ld.SasLogicalJBOD.id         = $_id
                    $_ld.sasLogicalJBODId          = $_id    

                }

                if (($_ld.raidLevel -and $PSBoundParameters['Mode'] -eq 'HBA') -or (-not($_ld.raidLevel) -and $PSBoundParameters['Mode'] -eq 'RAID'))
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "Mode" -Message "The Controller can only operate in a single mode: RAID or HBA. One or more of the provided LogicalDisks are defined for the opposite mode."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_ServerProfileController.logicalDrives.Add($_ld)

            }

        }

        elseif ($LogicalDisk -is [PSCustomObject])
        {

            "[{0}] Processing Logical Disk: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LogicalDisk.name | Write-Verbose

            if ($LogicalDisk.SasLogicalJBOD)
            {

                if ($_ServerProfileController.deviceSlot -eq 'Embedded')
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "LogicalDisks" -TargetType 'PSObject' -Message "The provided Logical Disks contains a SAS JBOD policy, which is not supported with the 'Embedded' Controller."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $LogicalDisk.SasLogicalJBOD.deviceSlot = $_ServerProfileController.deviceSlot

                # Figure out new SasLogicalJBODId
                if ($_ServerProfileController.logicalDrives.sasLogicalJbod.id)
                {

                    while ($_ServerProfileController.logicalDrives.sasLogicalJbod.id -contains $_id)
                    {

                        $_id++

                    }

                    $LogicalDisk.SasLogicalJBOD.id = $_id
                    $LogicalDisk.sasLogicalJBODId  = $_id                        

                }

            }

            if (($LogicalDisk.raidLevel -and $PSBoundParameters['Mode'] -eq 'HBA') -or (-not($LogicalDisk.raidLevel) -and $PSBoundParameters['Mode'] -eq 'RAID'))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.ServerProfile.LogicalDiskException UnsupportedControllerMode InvalidArgument "Mode" -Message "The Controller can only operate in a single mode: RAID or HBA. One or more of the provided LogicalDisks are defined for the opposite mode."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$_ServerProfileController.logicalDrives.Add($LogicalDisk)        

        }



    }

    End
    {

        Return $_ServerProfileController

    }

}

function New-HPOVServerProfileAttachVolume 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdLetBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateScript ({ $ResourceCategoryEnum.ServerProfile,$ResourceCategoryEnum.ServerProfileTemplate -contains $_.category })]
        [Object]$ServerProfile,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Switch]$PassThru,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [Alias ('id')]
        [Int]$VolumeID = 1,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "ServerProfileObject")]
        [ValidateScript({$_ | Where-Object { 'storage-volumes' -contains $_.category}})]
        [Array]$Volume,

        [Parameter (Mandatory, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [object]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [object]$VolumeTemplate,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Storage.StoragePool]$StoragePool,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Storage.StoragePool]$SnapshotStoragePool,

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [object]$StorageSystem,

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [int64]$Capacity,

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateSet ('Thin', 'Full', 'ThinDeduplication')]
        [String]$ProvisioningType = 'Thin',

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Switch]$Full,

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Switch]$Permanent,

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateSet ('NetworkRaid0None','NetworkRaid5SingleParity','NetworkRaid10Mirror2Way','NetworkRaid10Mirror3Way','NetworkRaid10Mirror4Way','NetworkRaid6DualParity')]
        [String]$DataProtectionLevel,

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Switch]$EnableAdaptiveOptimization,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [HPOneView.Storage.PerformancePolicy]$PerformancePolicy,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Bool]$EnableEncryption,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Bool]$CachePinning,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [HPOneView.Storage.VolumeSet]$VolumeSet,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Bool]$EnableIOPSLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateRange (256,4294967295)]
        [Int]$IOPSLimit = 256,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Bool]$EnableDataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Int]$DataTransferLimit,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [HPOneView.Storage.NimbleFolder]$Folder,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateSet ("Auto","Manual", IgnoreCase = $true)]
        [Alias ('type')]
        [String]$LunIdType = "Auto",

        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateRange(0,254)]
        [Int]$LunID,

        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateSet ('CitrixXen','CitrixXen7','AIX','IBMVIO','RHEL4','RHEL3','RHEL','RHEV','RHEV7','VMware','Win2k3','Win2k8','Win2k12','Win2k16','OpenVMS','Egenera','Exanet','Solaris9','Solaris10','Solaris11','ONTAP','OEL','HPUX11iv1','HPUX11iv2','HPUX11iv3','SUSE','SUSE9','Inform', IgnoreCase = $true)]
        [Alias ('OS')]
        [String]$HostOStype,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $false, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [Alias ('Bootable')]
        [Switch]$BootVolume,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateSet ('Auto', 'TargetPorts')]
        [String]$TargetPortAssignment = 'Auto',

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $False, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [Alias ('wwpns')]
        [Array]$TargetAddresses,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "ServerProfileObject")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "ServerProfileObjectEphmeralVol")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        If (-not($PSBoundParameters['Volume']))
        {

            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        
        
        if ($LunIdType -eq "Manual" -and (-not($PSBoundParameters.ContainsKey("LunId"))))
        { 
        
            $ExceptionMessage = "'Manual' LunIdType was specified, but no LUN ID value was provided. Please include the -LunId Parameter or a value in the Parameters position and try again."
            $ErrorRecord = New-ErrorRecord ArgumentNullException ParametersNotSpecified InvalidArgument 'LunIdType' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($LunIdType -eq "Auto" -and $PSBoundParameters.ContainsKey("LunId")) 
        { 
        
            $ExceptionMessage = "'Auto' LunIdType was specified and a specific LUN ID were provided. Please either specify -LunIdType 'Manual' or omit the -LunId Parameter and try again."
            $ErrorRecord = New-ErrorRecord ArgumentException ParametersSpecifiedCollision InvalidArgument 'LunIdType' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
        if ($PSBoundParameters['Full'])
        {

            $ExceptionMessage = 'The -Full parameter isbeing deprecated. Please update your scripts to use the -ProvisioningType parameter instead.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $PSBoundParameters.Add('ProvisioningType', $StorageVolumeProvisioningTypeEnum['Full'])

        }

        if ($PSBoundParameters['ProvisioningType'] -eq 'TPDD')
        {

            $ExceptionMessage = 'The -ProvisioningType "TPDD" value is being deprecated. Please update your script(s) to use the "Thin" value and -EnableCompression $True parameter.'
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

            $ProvisioningType = $StorageVolumeProvisioningTypeEnum['Thin']
            $PSBoundParameters.Add('EnableCompression', $True)
            
        }

        if ($PSBoundParameters['StorageSystem'])
        {

            $ExceptionMessage = "The -StorageSystem is deprecated. Please update your script(s) to use Get-HPOVStoragePool to get the specific pool object."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidProvisionTypeParameter InvalidOperation 'StorageSystem' -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        $_AllowedNimbleParams = "PerformancePolicy", "LockPerformancePolicy", "EnableEncryption", "CachePinning", "VolumeSet", "EnableIOPSLimit", "IOPSLimit", "EnableDataTransferLimit", "DataTransferLimit", "Folder"
        $_AllowedSSParams     = "EnableCompression", "EnableDeduplication", "SnapshotStoragePool"
        $_AllowedSVParams     = "DataProtectionLevel", "EnableAdaptiveOptimization"
        $_NotAllowedNimbleParams = $_AllowedSSParams + $_AllowedSVParams
        $_NotAllowedSSParams     = $_AllowedNimbleParams + $_AllowedSVParams
        $_NotAllowedVSParams     = $_AllowedSSParams + $_AllowedNimbleParams
        $_SafeParams          = "Name", "Description", "StoragePool", "StorageSystem", "VolumeTemplate", "Capacity", "ProvisioningType", "Full", "Shared", "Scope", "Async", "ApplianceConnection"

        if ($PSBoundParameters['ServerProfile'])
        {

            if ($ServerProfile -isnot [PSCustomObject])
            {

                $ExceptionMessage = "The provided Server Profile {0} is not an Object. Please provide a Server Profile object." -f $ServerProfile
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException UnsupportedServerHardwareResource InvalidArgument 'ServerProfile' -TargetType $ServerProfile.GetType().Name -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

            }

        }

        # Initialize collection to hold multiple volume attachments objects
        $_volumeAttachments = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $ExceptionMessageString = "The provided {0} parameter is not supported by the {1} storage family."

        if ($PSBoundParameters['Volume']) 
        {

            ForEach ($_vol in $Volume)
            {

                $_volumeAttachment = NewObject -ServerProfileStorageVolume

                "[{0}] Processing Volume: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (ConvertTo-Json $_vol -Depth 99) | Write-Verbose

                $_volumeAttachment.volumeUri              = $_vol.uri
                $_volumeAttachment.volumeStoragePoolUri   = $_vol.storagePoolUri

                if ($PSBoundParameters['SnapshotStoragePool'])
                {

                    $_volumeAttachment | Add-Member -NotePropertyName snapshotPool -NotePropertyValue $SnapshotStoragePool.uri
                    
                }

                $_volumeAttachment.volumeStorageSystemUri = $_vol.storageSystemUri

                if ($PSBoundParameters['VolumeID'])
                {

                    $_volumeAttachment.id = $VolumeID

                }
                
                if ($LunIdType -ne 'Auto')
                {

                    $_volumeAttachment.lunType = $LunIdType
                    $_volumeAttachment.lun     = $LunID

                }

                if ($PSBoundParameters['BootVolume'])
                {

                    if ($ServerProfile -and ($ServerProfile.sanStorage.volumeAttachments | Where-Object bootVolumePriority -eq 'Primary'))
                    {

                        $_Message = 'The Server Profile already had a Bootable Device, {0}. Please omit the -BootVolume Parameter switch or set the "bootVolumePriority" poperty of the Volume Attachment to "NotBootable".' -f ($ServerProfile.sanStorage.volumeAttachments | Where-Object bootVolumePriority -eq 'Bootable').id
                        $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException MultipleBootVolumesNotSupported InvalidOperation 'BootVolume' -TargetType 'SwitchParameter' -Message $_Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    if (-not ($_volumeAttachments | Where-Object bootVolumePriority -eq 'Primary'))
                    {

                        "[{0}] Setting Volume as Boot Volume: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_vol.volumeName | Write-Verbose

                        $_volumeAttachment.bootVolumePriority = 'Primary'

                    }

                    else
                    {

                        $_ConflictVolume = $Volume | Where-Object uri -contains ($_volumeAttachments | Where-Object bootVolumePriority -eq 'Primary').volumeUri

                        $_Message = 'An existing volume is already marked as a Bootable Device, {0}. Multiple Storage Volumes via Pipeline or Parameter input along with -BootVolume Parameter is not supported.' -f $_ConflictVolume.volumeName
                        $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException MultipleBootVolumesNotSupported InvalidOperation 'BootVolume' -TargetType 'SwitchParameter' -Message $_Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                        
                    }

                }

                $_volumeAttachment.ApplianceConnection = $_vol.ApplianceConnection

                [void]$_volumeAttachments.Add($_volumeAttachment)

            }

        }

        # Ephmeral Volume Support
        else
        {

            "[{0}] Creating dynamic volume attach object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
            $_volumeAttachment = NewObject -EphemeralStorageVolume

            if ($PSBoundParameters['StoragePool']) 
            {

                switch ($StoragePool.GetType().Name) 
                {

                    "String" 
                    { 
                        
                        if ($StoragePool.StartsWith($StoragePoolsUri)) 
                        {
                            
                            "[{0}] Storage Pool URI provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),  $StoragePool | Write-Verbose

                            Try
                            {
                                    
                                $_StoragePool = Send-HPOVRequest $StoragePool -appliance $ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }
                            
                        }

                        elseif ($StoragePool.StartsWith("/rest/")) 
                        {
                            
                            "[{0}] Invalid storage pool URI provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StoragePool | Write-Verbose

                            $ErrorRecord = New-ErrorRecord ArgumentException InvalidStoragePoolURI InvalidArgument 'StoragePool' -Message "The provided URI value for the -StoragePool Parameter '$StroagePool' is invalid. The StoragePool URI must Begin with /rest/storage-pools. Please check the value and try again."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        else 
                        {
                            
                            if ($StorageSystem) 
                            {
                                    
                                # If both storagepool and storagesystem were provided, look that up first
                                Try
                                {
                                    
                                    $_StoragePool = Get-HPOVStoragePool -poolName $StoragePool -storageSystem $StorageSystem -appliance $ApplianceConnection -ErrorAction Stop

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }
                                
                            }

                            else 
                            {

                                Try
                                {

                                    # If both storagepool and storagesystem were provided, look that up first
                                    $_StoragePool = Get-HPOVStoragePool -poolName $StoragePool -appliance $ApplianceConnection -ErrorAction Stop

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                                if ($_StoragePool -and $_StoragePool.count -gt 1) 
                                {

                                    # Generate Error that StoragePool name is not unique and must supply the StorageSystem as well.
                                    "[{0}] {1} StoragePool resource found" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException MultipleStoragePoolsFound InvalidResult 'New-HPOVServerProfileAttachVolume' -Message "Multiple StoragePool resources found with the name '$StoragePool'. Please use the -StorageSystem Parameter to specify the Storage System the Storage Pool is to be used."
                                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                                }

                            }
                            
                        }
                        
                    }

                    'StoragePool'
                    {

                        $_StoragePool = $StoragePool.PSObject.Copy()

                    }

                    default
                    { 
                        
                        # Validate the object
                        if ($StoragePool.category -eq $ResourceCategoryEnum.StoragePool) 
                        { 
                                
                            $_StoragePool = $StoragePool.PSObject.Copy()
                            
                        }

                        else 
                        {

                            $ExceptionMessage = "Invalid -StoragePool Parameter value. Expected Resource Category '{0}', received '{1}'." -f $ResourceCategoryEnum.StoragePool, $VolumeTemplate.category
                            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException InvalidStoragePoolCategory InvalidArgument 'StoragePool' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }              
                        
                    }

                }

                # Get the associated storage system family
                try
                {

                    "[{0}] Get storage system family associated with the provided Storage Pool." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $StorageSystem = Send-HPOVRequest -Uri $_StoragePool.storageSystemUri -Hostname $_StoragePool.ApplianceConnection

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Get Storage System Root Volume Template
                Try
                {
                    
                    "[{0}] Get storage system root volume template." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Uri = "{0}/templates?query=isRoot EQ true" -f $_StoragePool.storageSystemUri
                    $_StorageSystemRootVolumeTemplate = Send-HPOVRequest -Uri $_Uri -ApplianceConnection $ApplianceConnection
                    
                    $VolumeTemplate = $_StorageSystemRootVolumeTemplate.members[0]
                    $_VolumeTemplateUri = $VolumeTemplate.uri

                    "[{0}] Storage System root volume template URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.uri | Write-Verbose
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['VolumeTemplate'])
            {

                if ($VolumeTemplate.category -ne 'storage-volume-templates')
                {

                    $ExceptionMessage = "The value provided for VolumeTemplate is not the allowed resource type, storage-volume-templates."
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeTemplateResourceException InvalidStorageVolumeTemplateResource InvalidArgument 'VolumeTemplate' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Storage Volume Template provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.name | Write-Verbose
                "[{0}] Storage Volume Template family: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.family | Write-Verbose

                $_VolumeTemplateUri = $VolumeTemplate.uri

                Try
                {

                    "[{0}] Getting Storage Pool from SVT" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    $_StoragePool = Send-HPOVRequest -Uri $VolumeTemplate.storagePoolUri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Try
                {

                    "[{0}] Getting Storage System from Storage Pool" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $StorageSystem = Send-HPOVRequest -Uri $_StoragePool.storageSystemUri -Hostname $ApplianceConnection
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

            "[{0}] Setting templateUri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_VolumeTemplateUri | Write-Verbose
            $_volumeAttachment.volume.templateUri = $_VolumeTemplateUri

            # Create properties hashtable specific to the volume template and associated storage system family
            ForEach ($_Prop in ($VolumeTemplate.properties.PSObject.Members | Where-Object MemberType -eq 'NoteProperty'))
            {
    
                $_PropName = $_Prop.Name

                "[{0}] Adding volume property to hashtable: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PropName | Write-Verbose
                $_volumeAttachment.volume.properties.Add($_PropName, $VolumeTemplate.properties.$_PropName.default)

            }

            $_Family = $StorageSystem.family

            # Look to see if $PSBoundParameters contains unallowed parameters
            ForEach ($_Param in $PSBoundParameters.Keys)
            {

                # First check if the param is not within the safe, allowed params for all
                if ($_SafeParams -notcontains $_Param)
                {

                    $ExceptionMessage = $null

                    switch ($_Family)
                    {

                        'Nimble'
                        {

                            # Generate an error that the parameter is not supported by the storage system family
                            if ($_NotAllowedNimbleParams -contains $_Param)
                            {

                                $ExceptionSource = 'Invalid{0}Parameter' -f $_Param
                                $ExceptionMessage = $ExceptionMessageString -f $_Param, $_Family
                        
                            }

                        }

                        'StoreVirtual'
                        {

                            # Generate an error that the parameter is not supported by the storage system family
                            if ($_NotAllowedVSParams -contains $_Param)
                            {

                                $ExceptionSource = 'Invalid{0}Parameter' -f $_Param
                                $ExceptionMessage = $ExceptionMessageString -f $_Param, $_Family

                            }

                        }

                        '3Par'
                        {

                            # Generate an error that the parameter is not supported by the storage system family
                            if ($_NotAllowedSSParams -contains $_Param)
                            {

                                $ExceptionSource = 'Invalid{0}Parameter' -f $_Param
                                $ExceptionMessage = $ExceptionMessageString -f $_Param, $_Family

                            }

                        }

                    }

                    if (-not [String]::IsNullOrEmpty($ExceptionMessage))
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException $ExceptionSource InvalidOperation $_Param -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            switch ($_Family)
            {

                'StoreVirtual'
                {

                    "[{0}] Will create StoreVirtual Ephemeral volume." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                '3Par'
                {

                    "[{0}] Will create StoreServe Ephemeral volume." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                'Nimble'
                {

                    "[{0}] Will create Nimble Ephemeral volume." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }

            switch ($_volumeAttachment.volume.properties.GetEnumerator().Name)
            {

                # Common properties
                'name'
                {

                    "[{0}] Setting volume name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose
                    $_volumeAttachment.volume.properties.$_ = $Name

                }

                'description'
                {

                    if ($PSBoundParameters['Description'])
                    {

                        "[{0}] Setting volume description: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Description | Write-Verbose
                        $_volumeAttachment.volume.properties.$_ = $Description

                    }                

                }

                'templateVersion'
                {

                    "[{0}] Setting volume {1}: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.version | Write-Verbose
                    $_volumeAttachment.volume.properties.$_ = $VolumeTemplate.version

                }

                'storagePool'
                {

                    # If SVT enforces, set it
                    if ($VolumeTemplate.properties.$_.meta.locked -or -not $PSBoundParameters['StoragePool'])
                    {

                        "[{0}] Volume Template enforces StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.storagePool.default | Write-Verbose

                        $_volumeAttachment.volume.properties.$_ = $VolumeTemplate.properties.$_.default
                    
                    }

                    else
                    {

                        "[{0}] Setting StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePool.uri | Write-Verbose

                        $_volumeAttachment.volume.properties.storagePool = $_StoragePool.uri

                    }

                }

                'size'
                {

                    if ($VolumeTemplate.properties.size.meta.locked -or (-not $PSBoundParameters['Capacity'] -and -not $VolumeTemplate.properties.size.meta.locked))
                    {

                        "[{0}] Volume Template enforces volume capacity: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.size.default | Write-Verbose

                        $_volumeAttachment.volume.properties.size = $VolumeTemplate.properties.size.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.size = $Capacity * 1GB

                    }

                }

                'provisioningType'
                {

                    if ($VolumeTemplate.properties.provisioningType.meta.locked -or (-not $PSBoundParameters['Full'] -and -not $PSBoundParameters['ProvisioningType'] -and -not $VolumeTemplate.properties.provisioningType.meta.locked))
                    {

                        "[{0}] Volume Template enforces volume provisioningType: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.provisioningType.default | Write-Verbose
                        $_volumeAttachment.volume.properties.provisioningType = $VolumeTemplate.properties.provisioningType.default

                    }
                
                    else
                    {

                        if ($PSBoundParameters['ProvisioningType'])
                        {

                            "[{0}] Setting volume provisioningType via ProvisioningType param: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageVolumeProvisioningTypeEnum[$ProvisioningType] | Write-Verbose

                            $_volumeAttachment.volume.properties.provisioningType = $StorageVolumeProvisioningTypeEnum[$ProvisioningType]

                        }

                        else
                        {

                            "[{0}] Setting volume provisioningType via not full param: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $StorageVolumeProvisioningTypeEnum['Thin'] | Write-Verbose

                            $_volumeAttachment.volume.properties.provisioningType = $StorageVolumeProvisioningTypeEnum['Thin']

                        }

                    }

                }

                'isShareable'
                {

                    if ($VolumeTemplate.properties.isShareable.meta.locked -or (-not $PSBoundParameters['Shared'] -and -not $VolumeTemplate.properties.isShareable.meta.locked))
                    {

                        "[{0}] Volume Template enforces volume shareable state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isShareable.default | Write-Verbose

                        $_volumeAttachment.volume.properties.isShareable = $VolumeTemplate.properties.isShareable.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.isShareable = $Shared.IsPresent

                    }

                }

                # 3Par specific
                'snapshotPool'
                {

                    "[{0}] Family is StoreServ, attempting to set snapshot pool" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # If SVT enforces, set it
                    if ($VolumeTemplate.properties.snapshotPool.meta.locked)
                    {

                        "[{0}] Volume Template enforces Snapshot StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.snapshotPool.default | Write-Verbose

                        $_volumeAttachment.volume.properties.snapshotPool = $VolumeTemplate.properties.snapshotPool.default
                    
                    }

                    else
                    {

                        if ($PSBoundParameters['SnapshotStoragePool'])
                        {

                            if ($SnapshotStoragePool -is [String])
                            {

                                try
                                {

                                    $SnapshotStoragePool = GetStoragePool -Name $SnapshotStoragePool -StorageSystem $StorageSystem -ApplianceConnection $ApplianceConnection

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                            }

                            "[{0}] Setting SnapshotStoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $SnapshotStoragePool.uri | Write-Verbose
                        
                            $_volumeAttachment.volume.properties.snapshotPool = $SnapshotStoragePool.uri

                        }

                        elseif (-not $PSBoundParameters['SnapshotStoragePool'] -and -not $PSBoundParameters['StoragePool'])
                        {

                            "[{0}] Setting SnapshotStoragePool to StoragePool from Volume Template: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.snapshotPool.default | Write-Verbose

                            $_volumeAttachment.volume.properties.snapshotPool = $VolumeTemplate.properties.snapshotPool.default

                        }
                    
                        else
                        {

                            "[{0}] Setting SnapshotStoragePool to StoragePool: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_StoragePool.uri | Write-Verbose

                            $_volumeAttachment.volume.properties.snapshotPool = $_StoragePool.uri

                        }                        

                    }

                }

                'isDeduplicated'
                {

                    "[{0}] Family is StoreServ, attempting to set Deduplicated" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # If SVT enforces, set it
                    if ($VolumeTemplate.properties.$_.meta.locked -or $PSBoundParameters -notcontains 'EnableDeduplication')
                    {

                        "[{0}] Volume Template enforces Deduplicate: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isDeduplicated.default | Write-Verbose

                        $_volumeAttachment.volume.properties.isDeduplicated = $VolumeTemplate.properties.isDeduplicated.default
                    
                    }

                    else
                    {

                        "[{0}] Setting Deduplicate: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableDeduplication | Write-Verbose

                        $_volumeAttachment.volume.properties.isDeduplicated = $EnableDeduplication

                    }

                }

                'isCompressed'
                {

                    "[{0}] Family is 3Par, attempting to set Compression" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # If SVT enforces, set it
                    if ($VolumeTemplate.properties.isCompressed.meta.locked -or -not $PSBoundParameters['EnableCompression'])
                    {

                        "[{0}] Volume Template enforces Compression: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isCompressed.default | Write-Verbose

                        $_volumeAttachment.volume.properties.isCompressed = $VolumeTemplate.properties.isCompressed.default
                    
                    }

                    else
                    {

                        "[{0}] Setting Deduplication: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $EnableDeduplication | Write-Verbose

                        $_volumeAttachment.volume.properties.isCompressed = $EnableDeduplication

                    }

                }

                # StoreVirtual specific
                'dataProtectionLevel'
                {

                    if ($VolumeTemplate.properties.dataProtectionLevel.meta.locked -or (-not $PSBoundParameters['DataProtectionLevel'] -and -not $VolumeTemplate.properties.dataProtectionLevel.meta.locked))
                    {

                        "[{0}] Volume Template enforces DataProtectionLevel: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.dataProtectionLevel.default | Write-Verbose

                        $_volumeAttachment.volume.properties.dataProtectionLevel = $VolumeTemplate.properties.dataProtectionLevel.default

                    }
                
                    else
                    {

                        $_DataProtectionLevel = $VolumeTemplate.properties.dataProtectionLevel.enum | Where-Object { $_ -eq $DataProtectionLevel }

                        if (-not $_DataProtectionLevel)
                        {

                            $ExceptionMessage = "The requested data protection level, {0}, is not supported with the storage system. Please correctthe value with one of the following options: {1}" -f $DataProtectionLevel, ([String]::Join(', ', $VolumeTemplate.properties.dataProtectionLevel.enum))
                            $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedProtectionLevelValue InvalidArgument 'DataProtectionLevel' -TargetType $DataProtectionLevel.gettype().Name -Message $ExceptionMessage
                    
                            # Generate Terminating Error
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord) 

                        }

                        $_volumeAttachment.volume.properties.dataProtectionLevel = $_DataProtectionLevel

                    }

                }

                'isAdaptiveOptimizationEnabled'
                {

                    if ($VolumeTemplate.properties.isAdaptiveOptimizationEnabled.meta.locked -or (-not $PSBoundParameters['EnableAdaptiveOptimization'] -and -not $VolumeTemplate.properties.isAdaptiveOptimizationEnabled.meta.locked))
                    {

                        "[{0}] Volume Template enforces AdaptiveOptimizationEnabled: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.isAdaptiveOptimizationEnabled.default | Write-Verbose

                        $_volumeAttachment.volume.properties.isAdaptiveOptimizationEnabled = $VolumeTemplate.properties.isAdaptiveOptimizationEnabled.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.isAdaptiveOptimizationEnabled = $EnableAdaptiveOptimization.IsPresent

                    }

                }

                # Nimble specific
                'performancePolicy'
                {

                    if ($VolumeTemplate.properties.performancePolicy.meta.locked -or (-not $PSBoundParameters['PerformancePolicy'] -and -not $VolumeTemplate.properties.performancePolicy.meta.locked))
                    {

                        "[{0}] Volume Template enforces performancePolicy state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.PerformancePolicy.default | Write-Verbose

                        $_volumeAttachment.volume.properties.performancePolicy = $VolumeTemplate.properties.performancePolicy.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.PerformancePolicy = $PerformancePolicy.Id

                    }

                }

                'folder'
                {

                    if ($VolumeTemplate.properties.folder.meta.locked -or (-not $PSBoundParameters['Folder'] -and -not $VolumeTemplate.properties.folder.meta.locked))
                    {

                        "[{0}] Volume Template enforces folder state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.folder.default | Write-Verbose

                        $_volumeAttachment.volume.properties.folder = $VolumeTemplate.properties.folder.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.folder = $Folder.Id

                    }

                }

                'volumeSet'
                {

                    if ($VolumeTemplate.properties.volumeSet.meta.locked -or (-not $PSBoundParameters['VolumeSet'] -and -not $VolumeTemplate.properties.volumeSet.meta.locked))
                    {

                        "[{0}] Volume Template enforces volumeSet state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.volumeSet.default | Write-Verbose

                        $_volumeAttachment.volume.properties.volumeSet = $VolumeTemplate.properties.volumeSet.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.volumeSet = $VolumeSet.Uri

                    }

                }

                'isEncrypted'
                {

                    if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'EnableEncryption' -and -not $VolumeTemplate.properties.$_.meta.locked))
                    {

                        "[{0}] Volume Template enforces isEncrypted state: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VolumeTemplate.properties.$_.default | Write-Verbose

                        $_volumeAttachment.volume.properties.$_ = $VolumeTemplate.properties.$_.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.$_ = $EnableEncryption

                    }

                }

                'isPinned'
                {

                    if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'CachePinning' -and -not $VolumeTemplate.properties.$_.meta.locked))
                    {

                        "[{0}] Volume Template enforces {1} state: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.properties.$_.default | Write-Verbose

                        $_volumeAttachment.volume.properties.$_ = $VolumeTemplate.properties.$_.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.$_ = $CachePinning

                    }

                }

                'iopsLimit'
                {

                    if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'EnableIOPSLimit' -and -not $VolumeTemplate.properties.$_.meta.locked))
                    {

                        "[{0}] Volume Template enforces {1} state: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.properties.$_.default | Write-Verbose

                        $_volumeAttachment.volume.properties.$_ = $VolumeTemplate.properties.$_.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.$_ = $IOPSLimit

                    }

                }

                'dataTransferLimit'
                {

                    if ($VolumeTemplate.properties.$_.meta.locked -or ($PSBoundParameters.Keys -notcontains 'EnableDataTransferLimit' -and -not $VolumeTemplate.properties.$_.meta.locked))
                    {

                        "[{0}] Volume Template enforces {1} state: {2}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_, $VolumeTemplate.properties.$_.default | Write-Verbose

                        $_volumeAttachment.volume.properties.$_ = $VolumeTemplate.properties.$_.default

                    }
                
                    else
                    {

                        $_volumeAttachment.volume.properties.$_ = $DataTransferLimit

                    }

                }

            }
            

            $_volumeAttachment.volume.isPermanent = [Bool]$PSBoundParameters['Permanent']

            if (-not($PSBoundParameters['VolumeID']) -and $ServerProfile)
            {

                "[{0}] No VolumeID value provided. Getting next volume id value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $id = 1

                $Found = $false

                While (-not($Found))
                {

                    if (-not($ServerProfile.sanStorage.volumeAttachments | Where-Object id -eq $id))
                    {

                        $VolumeID = $id

                        $Found = $true

                    }

                    $id++

                }

            }

            $_volumeAttachment.id = $VolumeID

            if ($LunIdType -ne 'Auto')
            {

                $_volumeAttachment.lunType = $LunIdType
                $_volumeAttachment.lun     = $LunID

            }

            if ($PSBoundParameters['BootVolume'])
            {

                if (-not($_volumeAttachments | Where-Object bootVolumePriority))
                {

                    "[{0}] Setting Volume as Boot Volume: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_volumeAttachment.volumeName | Write-Verbose

                    $_volumeAttachment.bootVolumePriority = 'Primary'

                }

                else
                {

                    $_Message = 'An existing volume is already marked as a Bootable Device, {0}. Multiple Storage Volumes via Pipeline or Parameter input along with -BootVolume Parameter is not supported.' -f [String]::Join(' ', ($_volumeAttachments | Where-Object bootVolumePriority -eq 'Primary').volumeName)
                    $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException MultipleBootVolumesNotSupported InvalidOperation 'BootVolume' -TargetType 'SwitchParameter' -Message $_Message
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            $_volumeAttachment.ApplianceConnection = $_Connection

            [void]$_volumeAttachments.Add($_volumeAttachment)

        }

        "[{0}] VolumeAttachments Added to collection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_volumeAttachments.Count | Write-Verbose

    }

    End 
    {

        # Process server profile object
        if ($PSBoundParameters['ServerProfile'])
        {

            # Copy the profile object so we don't overwrite the callers copy
            $_ServerProfile = $ServerProfile.PSObject.Copy()

            # Validate Server Profile and Server Hardware resource supports StRM operations
            Try
            {

                "[{0}] Checking SHT for SanStorage operation support" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_SHTResource = Send-HPOVRequest -uri $_ServerProfile.serverHardwareTypeUri -Hostname $_ServerProfile.ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # TODO: This will need to be updated for 5.0 and DL support
            if (-not [RegEx]::Match($_SHTResource.model,'BL|WS|SY', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase).Success)
            {
                    
                $ExceptionMessage = "The provided Server Profile {0} is not assigned to a supported Server Hardware Type Resource, {1}. Only WS/BL/SY Gen 8/Gen 9 or newer are supported." -f $_ServerProfile.name, $_SHTResource.model
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException UnsupportedServerHardwareResource InvalidArgument 'ServerProfile' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

            }

            # Validate Server Profile has SanStorage already set. If not, set it and add the necessary properties.
            if (-not $_ServerProfile.sanStorage.manageSanStorage)
            {

                "[{0}] Server Profile does not have manageSanStorage property set to True." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Generate Error that HostOSType is required
                if (-not($PSBoundParameters['HostOsType']))
                {

                    $ExceptionMessage = "The -HostOSType parmater is required when the Server Profile is not already configured for managing SAN Storage. Please specify the HostOSType Parameter in your call."
                    $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException MissingHostOSTypeParameterValue InvalidArgument 'ServerProfile' -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                }

                $_ServerProfile.sanStorage = [PSCustomObject]@{
                        
                    hostOSType        = $ServerProfileSanManageOSType[$HostOsType];
                    manageSanStorage  = $true;
                    volumeAttachments = [System.Collections.ArrayList]::new()
                    
                }

            }

            # Rebuild VolumeAttachments property to be an ArrayList
            else
            {

                if ($_ServerProfile.sanStorage.volumeAttachments.Count -gt 0)
                {

                    "[{0}] Rebuilding Server Profile Volume Attachment object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_ExistingVols = $_ServerProfile.sanStorage.volumeAttachments.Clone()                    

                    $_ServerProfile.sanStorage.volumeAttachments = [System.Collections.ArrayList]::new()

                    ForEach ($_vol in $_ExistingVols)
                    {

                        if ($_vol.volumeUri -contains $_volumeAttachments.volumeUri)
                        {

                            Try
                            {

                                $_ExistingVolume = Send-HPOVRequest -Uri $_vol.volumeUri -Hostname $_ServerProfile.ApplianceConnection

                            }

                            Catch
                            {

                                $PSCmdlet.ThrowTerminatingError($_)

                            }

                            [void]$_volumeAttachments.Remove($_)

                            $ExceptionMessage = 'Storage Volume {0} is already attached at ID {1}.' -f $_ExistingVolume.name, $_vol.id
                            $ErrorRecord = New-ErrorRecord HPOneView.StorageVolumeResourceException StorageVolumeAlreadyAttached ResourceExists 'Volume' -Targettype 'PSObject' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        [void]$_ServerProfile.sanStorage.volumeAttachments.Add($_vol)

                    }

                }

                else
                {

                    $_ServerProfile.sanStorage.volumeAttachments = [System.Collections.ArrayList]::new()

                }

            }

            $_AllNetworkUrisCollection  = [System.Collections.ArrayList]::new()

            # Build list of network URI's from connections
            ForEach ($_Connection in ($_ServerProfile.connectionSettings.connections | Where-Object { -not $_.networkUri.StartsWith($NetworkSetsUri)})) 
            {

                [void]$_AllNetworkUrisCollection.Add($_Connection.networkUri)

            }

            # Generate error if the server profile does not contain valid connections
            if ($_AllNetworkUrisCollection.Count -eq 0)
            {

                $ExceptionMessage = "The '{0}' server profile does not contain connections necessary to manage storage attachments. Please provide a server profile with atleast 1 valid connection." -f $_ServerProfile.name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException NoAvailableConnections ObjectNotFound 'Connections' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

            }
                    
            "[{0}] Volumes to Process {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_volumeAttachments | Convertto-Json -Depth 99 | out-string) | Write-Verbose 
                    
            $i = 0
            
            # Process volumes being passed
            foreach ($_volume in $_volumeAttachments) 
            {  

                if (-not [System.String]::IsNullOrWhiteSpace($_volume.volumeUri))
                {

                    Try
                    {

                        
                        $_VolumeObject = Send-HPOVRequest -Uri $_volume.volumeUri -Hostname $_ServerProfile.ApplianceConnection.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                if ($null -ne $_VolumeObject.name)
                {

                    $_volumeName = $_VolumeObject.name

                }

                else
                {
                
                    $_volumeName = $_volume.volume.properties.name
                
                }

                "[{0}] Processing '{1}' Storage Volume (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_volumeName, $_volumeAttachments.count | Write-Verbose
                
                # Validate if the volume is attachable
                if (-not [System.String]::IsNullOrWhiteSpace($_volume.volumeUri))
                {

                    "[{0}] Checking if the volume is available and attachable" -f $MyInvocation.InvocationName.ToString().ToUpper()| Write-Verbose
            
                    # Get list of available storage system targets and the associated Volumes based on the EG and SHT provided
                    Try
                    {

                        $_uri = "{0}?networks='{1}'&filter=name='{2}'" -f $AttachableStorageVolumesUri, ([String]::Join(',', $_AllNetworkUrisCollection.ToArray())), $_volumeName

                        $_ReachableOrAvailableStorageResource = (Send-HPOVRequest -Uri $_uri -Hostname $_ServerProfile.ApplianceConnection.Name).members
                
                    }
                
                    Catch
                    {
                
                        $PSCmdlet.ThrowTerminatingError($_)
                
                    }
                
                    "[{0}] Attachable Storage Volume: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_ReachableOrAvailableStorageResource | Out-String) | Write-Verbose
                    
                    # Error on no available storage systems
                    if (-not $_ReachableOrAvailableStorageResource)
                    {
                
                        $ExceptionMessage = "Unable to find attachable storage volumes for '{0}' Server Profile with available connection networks and '{1}'. Verify the Server Profile contains at least 1 Connection that is mapped to the storage system the volume is provisioned from." -f $_ServerProfile.name, [String]::Join(',', $_AllNetworkUrisCollection.ToArray())
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException NoAvailableStorageSystems ObjectNotFound 'SANStorage' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  
                
                    }
                    
                    $_AssociatedStorageSystemUri = $_ReachableOrAvailableStorageResource.storageSystemUri

                }

                # This is an ephemeral volume, need to validate the connections to the storage pool
                else
                {
                    
                    Try
                    {

                        $_uri = "{0}?networks='{1}'&filter=uri='{2}'" -f $ReachableStoragePoolsUri, ([String]::Join(',', $_AllNetworkUrisCollection.ToArray())), $_volume.volume.properties.storagePool

                        $_ReachableOrAvailableStorageResource = (Send-HPOVRequest -Uri $_uri -Hostname $_ServerProfile.ApplianceConnection).members
                
                    }
                
                    Catch
                    {
                
                        $PSCmdlet.ThrowTerminatingError($_)
                
                    }
                    
                    # Error that the provided storage pool is not reachable by the profile connections
                    if (-not $_ReachableOrAvailableStorageResource)
                    {
                
                        $ExceptionMessage = "The '{0}' Server Profile does not contain 1 or more connections that can reach the provided storage pool." -f $_ServerProfile.name
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException NoReachableStoragePool ObjectNotFound 'SANStorage' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  
                
                    }
                    
                    $_AssociatedStorageSystemUri = $_ReachableOrAvailableStorageResource.storageSystemUri
                
                }

                # Figure out volume ID
                if (-not $_volume.id)
                {

                    "[{0}] No VolumeID value provided. Getting next volume id value." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $id = 1

                    $Found = $false

                    While (-not $Found)
                    {

                        if (-not($_ServerProfile.sanStorage.volumeAttachments | Where-Object id -eq $id))
                        {

                            $_volume.id = $id

                            $Found = $true

                        }

                        $id++

                    }

                }

                # If the storage paths array is null, Process connections to add mapping
                if (-not $_volume.storagePaths)
                {

                    # Get the associated storage system to later identify the ports
                    Try
                    {
                    
                        $_AssociatedStorageSystem = Send-HPOVRequest -Uri $_AssociatedStorageSystemUri -Hostname $_ServerProfile.ApplianceConnection
                    
                    }
                    
                    Catch
                    {
                    
                        $PSCmdlet.ThrowTerminatingError($_)
                    
                    }

                    "[{0}] Storage Paths value is Null. Building connection mapping." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    # Loop through profile connections
                    $found = 0

                    foreach ($_reachableNetwork in $_ReachableOrAvailableStorageResource.reachableNetworks) 
                    {

                        $_StoragePath = NewObject -StoragePath

                        # Looking for $volConnection
                        $_ProfileConnection = $_ServerProfile.connectionSettings.connections | Where-Object networkUri -eq $_reachableNetwork

                        if ($_ProfileConnection) 
                        {

                            # Keep track of the connections found for error reporting later
                            $found++

                            "[{0}] Mapping connection ID '{1}' -> volume ID '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ProfileConnection.id, $_volumeAttachments[$i].id | Write-Verbose

                            $_StoragePath.connectionId = $_ProfileConnection.id
                            $_StoragePath.isEnabled = $True

                            if ($PSBoundParameters['TargetAddresses'])
                            {

                                "[{0}] Getting FC network to get associated SAN." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                # $_uri = "{0}/reachable-ports?query=expectedNetworkUri EQ '{1}'" -f $_VolumeToStorageSystem.uri, $profileConnection.networkUri
                                $_StoragePath.targetSelector = 'TargetPorts'

                                Try
                                {

                                    $_ServerProfileConnectionNetwork = Send-HPOVRequest -Uri $_ProfileConnection.networkUri -Hostname $_ServerProfile.ApplianceConnection

                                }

                                Catch
                                {

                                    $PSCmdlet.ThrowTerminatingError($_)

                                }

                                # Get the list of all ports reachable by the expected managed SAN/Network
                                $_StorageSystemExpectedMappedPorts = $_AssociatedStorageSystem.ports | Where-Object expectedSanUri -eq $_ServerProfileConnectionNetwork.managedSanUri

                                ForEach ($_PortID in $TargetAddresses)
                                {

                                    "[{0}] Looking for {1} host port from available storage system." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_PortID | Write-Verbose

                                    if ($WwnAddressPattern.Match($_PortID).Success)
                                    {

                                        $_PortType = 'name'

                                    }

                                    elseif ($StoreServeTargetPortIDPattern.Match($_PortID).Success)
                                    {

                                        $_PortType = 'address'

                                    }

                                    ForEach ($_HostPort in ($_StorageSystemExpectedMappedPorts | Where-Object $_PortType -match $_PortID))
                                    {

                                        "[{0}] Adding {1} ({2}) host port to targets." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_HostPort.address, $_HostPort.name | Write-Verbose

                                        $_Target = @{ name = $_HostPort.address}
                                        
                                        [void]$_StoragePath.targets.Add($_Target)

                                    }

                                }

                                        }                                        

                            [void]$_volume.storagePaths.Add($_StoragePath)

                        }

                    }

                    # We should NOT get here
                    if (-not ($found)) 
                    {

                        # Generate non-terminating error and continue
                        $ExceptionMessage = "Unable to find a Profile Connection that will map to '{0}'. Creating server profile resource without Volume Connection Mapping."  -f $_volumeName
                        $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException NoProfileConnectionsMapToVolume ObjectNotFound 'Volumes' -Message $ExceptionMessage
                        $PSCmdlet.WriteError($ErrorRecord)

                    }
 
                }

                "[{0}] Storage Volume Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), (ConvertTo-Json $_volume -depth 99) | Write-Verbose

                "[{0}] Attaching '{1}' Storage Volume to volumeAttachments collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_volumeName | Write-Verbose

                [void]$_ServerProfile.sanStorage.volumeAttachments.Add($_volume)

                $i++

            }

            # Workaround to remove a possible NULL entry in the volumeAttachments collection
            [void]$_ServerProfile.sanStorage.volumeAttachments.Remove($null)

            if (-not $PSBoundParameters['PassThru'])
            {

                "[{0}] Updating Server Profile with new Storage Volume Attachments: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ServerProfile.name | Write-Verbose 

                Try
                {

                    $_Task = Send-HPOVRequest -Uri $_ServerProfile.uri -Method PUT -Body $_ServerProfile -Hostname $_ServerProfile.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                Return $_Task

            }

            else
            {

                "[{0}] Returning Server Profile to caller with new Storage Volume Attachments: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ServerProfile.name | Write-Verbose 

                return $_ServerProfile

            }            

        }
        
        else
        {

            if ($PSBoundParameters['TargetAddresses'])
            {

                "[{0}] Adding TargetPortAssignmentType and TargetAddresses to volume attachment members." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                ForEach ($_VolAttachment in $_volumeAttachments)
                {

                    $_volumeAttachments | Add-Member -NotePropertyName TargetPortAssignmentType -NotePropertyValue $TargetPortAssignment
                    $_volumeAttachments | Add-Member -NotePropertyName TargetAddresses -NotePropertyValue $TargetAddresses

                }                

            }

            return $_volumeAttachments

        }

    }

}

# Helper function to return collection of available BIOS settings for a given SHT
function Get-HPOVAvailableServerBiosSettings
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdLetBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Server.BiosSetting[]])]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {



    }

    End
    {


    }

}

# Helper Cmdlet to get available iLO settings for SPT and SP
function Get-HPOVAvailableIloSettings
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdLetBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Server.IloSetting])]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {



    }

    End
    {

        
    }

}

#######################################################
# Cluster Profile:
#

function Get-HPOVClusterManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Cluster.HypervisorManager])]
    Param 
    (

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Version,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }                
                
            }

            if ($Version)
            {

                [Void]$_Query.Add(("version:'{0}'" -f $Version))

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.HypervisorManager

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose
                
                $ExceptionMessage = "The specified resource name '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ServerProfileResourceException ServerProfileResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)
                
            }

            else
            {

                foreach ($_member in $_ResourcesFromIndexCol)
                {

                    $_Preferences = New-Object HPOneView.Cluster.HypervisorManager+ConfigPreferences($_member.preferences.virtualSwitchType,
                                                                                                     $_member.preferences.distributedSwitchVersion,
                                                                                                     $_member.preferences.distributedSwitchUsage,
                                                                                                     $_member.preferences.multiNicVMotion,
                                                                                                     $_member.preferences.drsEnabled,
                                                                                                     $_member.preferences.haEnabled)

                    $_ResourcePath = New-Object 'System.Collections.Generic.List[HPOneView.Cluster.HypervisorManager+ResourcePath]'

                    ForEach ($_Path in $_member.resourcePaths)
                    {

                        $__resourcepath = New-Object HPOneView.Cluster.HypervisorManager+ResourcePath($_Path.userPath, $_Path.actualPath)
                        $_ResourcePath.Add($__resourcepath)

                    }

                    New-Object HPOneView.Cluster.HypervisorManager ($_member.name,
                                                                    $_member.displayName,
                                                                    $_member.uuid,
                                                                    $_member.port,
                                                                    $_member.version,
                                                                    $_member.state,
                                                                    $_member.stateReason,
                                                                    $_member.status,
                                                                    $_member.username,
                                                                    $_Preferences,
                                                                    $_ResourcePath,
                                                                    $_member.availableDvsVersions,
                                                                    $_member.uri,
                                                                    $_member.applianceConnection)
                    
                }

            }

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVClusterManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias('Name', 'ComputerName')]
        [String]$Hostname,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$DisplayName = "",

        [Parameter (ParameterSetName = 'Default', Mandatory)]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateRange(1, 65535)]
        [Int]$Port = 443,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Switch]$TrustLeafCertificate,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            if ($PSBoundParameters['TrustLeafCertificate'])
            {

                "[{0}] Caller provide the -TrustLeafCertificate switch. Adding SSL certificate to appliance trust store." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Getting SSL certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # This is not an async task operation
                Try
                {

                    $_uri = '{0}/{1}' -f $RetrieveHttpsCertRemoteUri, $Hostname

                    $_DeviceCertificate = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_DeviceCertificateToImport = NewObject -CertificateToImport
                $_DeviceCertificateToImport.certificateDetails[0].base64Data = $_DeviceCertificate.certificateDetails.base64Data
                $_DeviceCertificateToImport.certificateDetails[0].aliasName  = $_DeviceCertificate.certificateDetails.commonName

                Try
                {
                    
                    "[{0}] Adding SSL certificate to appliance trust store." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_uri = '{0}' -f $ApplianceTrustedSslHostStoreUri

                    $_TaskResults = Send-HPOVRequest -Uri $_uri -Method POST -Body $_DeviceCertificateToImport -Hostname $_appliance | Wait-HPOVTaskComplete

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($_TaskResults.taskErrors)
                {

                    "[{0}] Task errors adding SSL certificate." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($_TaskResults.taskErrors.errorCode -eq '409' -and $_TaskResults.taskErrors.message -match 'The certificate already exists for the alias')
                    {

                        "[{0}] Certificate already exists." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    }

                    else
                    {
                        
                        $ErrorRecord = New-ErrorRecord InvalidOperationException $_TaskResults.taskErrors.errorCode InvalidResult 'Hostname' -Message $_TaskResults.taskErrors.message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            $_Uri = $HypervisorManagersUri.Clone()

            $_NewClusterProfileManager = NewObject -ClusterProfileManager
            $_NewClusterProfileManager.name = $Hostname

            if ($PSBoundParameters['DisplayName'])
            {

                $_NewClusterProfileManager.displayName = $DisplayName

            }

            else
            {

                $_NewClusterProfileManager.displayName = $Hostname

            }
            
            $_NewClusterProfileManager.username    = $Credential.UserName
            $_NewClusterProfileManager.password    = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

            if ($PSBoundParameters['Scope'])
            {

                ForEach ($_Scope in $Scope)
                {

                    "[{0}] Adding to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                    [void]$_NewClusterProfileManager.initialScopeUris.Add($_Scope.Uri)

                }

            }

            Try
            {
            
                $_resp = Send-HPOVRequest -Uri $_Uri -Method POST -Body $_NewClusterProfileManager -Hostname $_appliance
            
            }
            
            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }

            # Wait for task to get into Starting stage
            Try
            {

                $_resp = Wait-HPOVTaskStart $_resp

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
                
            # Check to see if the task errored, which should be in the Task Validation stage
            if ($_resp.taskState -ne "Running" -and $_resp.taskState -eq "Error" -and $_resp.stateReason -eq "ValidationError") 
            {

                "[{0}] Task error found {1} {2} " -f $MyInvocation.InvocationName.ToString().ToUpper(), $resp.taskState, $resp.stateReason | Write-Verbose

                if ($_resp.taskErrors | Where-Object { $_.errorCode -eq "HYPERVISOR_MANAGER_SECURE_CONNECTION_FAILED" })
                {

                    $ExceptionMessage = 'The leaf certificate for {0} is untrusted by the appliance. Either provide the -TrustLeafCertificate parameter or manually add the certificate using the Add-HPOVApplianceTrustedCertificate Cmdlet.' -f $Hostname
                    $ErrorRecord = New-ErrorRecord InvalidOperationException UntrustedLeafCertificate InvalidResult 'Hostname' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                }

                elseif ($_resp.taskErrors)
                {

                    $_errorMessage = $_resp.taskErrors

                    $ErrorRecord = New-ErrorRecord InvalidOperationException $_errorMessage.errorCode InvalidResult 'Hostname' -Message ($_errorMessage.details + " " + $_errorMessage.message) 

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            if ($Async)
            {

                $_resp

            }

            else
            {
            
                $_resp | Wait-HPOVTaskComplete
            
            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVClusterManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Alias('Name')]
        [HPOneView.Cluster.HypervisorManager]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Hostname,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$DisplayName,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateRange (1, 65535)]
        [Int]$Port,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ('Distributed', 'Standard')]
        [String]$VirtualSwitchType,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ('AllNetworks', 'GeneralNetworks')]
        [String]$DistributedSwitchUsage,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ('4.0', '4.1.0', '5.0.0', '5.1.0', '5.5.0', '6.0', '6.7')]
        [String]$DistributedSwitchVersion,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Bool]$HAEnabled,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Bool]$DRSEnabled,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Bool]$MultiNicVMotionEnabled,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        $_UpdateHypervisorManagerDetails = [PSCustomObject]@{
            type        = 'HypervisorManagerV2';
            name        = $InputObject.Name
            username    = $InputObject.Username;
            password    = $InputObject.Password;
            displayName = $InputObject.DisplayName;
            preferences = [PSCustomObject]@{
                type = 'Vmware';
                virtualSwitchType        = $InputObject.Preferences.VirtualSwitchType
                distributedSwitchVersion = $InputObject.Preferences.DistributedSwitchVersion
                distributedSwitchUsage   = $InputObject.Preferences.DistributedSwitchUsage
                multiNicVMotion          = $InputObject.Preferences.MultiNicVMotion
                drsEnabled               = $InputObject.Preferences.DRSEnabled
                haEnabled                = $InputObject.Preferences.HAEnabled
            }
        }

        Switch ($PSBoundParameters.Keys)
        {

            'DisplayName'
            {

                "[{0}] Updating displayname to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DisplayName | Write-Verbose

                $_UpdateHypervisorManagerDetails.displayName = $DisplayName

            }

            'Hostname'
            {

                "[{0}] Updating name to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname | Write-Verbose

                $_UpdateHypervisorManagerDetails.name = $Hostname

            }

            'Credential'
            {

                "[{0}] Updating credential to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Credential.Username | Write-Verbose
                
                $_UpdateHypervisorManagerDetails.username = $Credential.Username
                $_UpdateHypervisorManagerDetails.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

            }

            'VirtualSwitchType'
            {

                # If Standard, check if $PSBoundParameters['DistributedSwitchUsage'] is provided, error if true
                if ($PSBoundParameters['VirtualSwitchType'] -eq 'Standard' -and $PSBoundParameters['DistributedSwitchUsage'])
                {

                    $ExceptionMessage = "Setting the hypervisor VirtualSwitchType to 'Standard' and also setting the DistributeSwitchUsage is not supported."
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException InvalidVirtualSwitchTypeParameters InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                if ($PSBoundParameters['VirtualSwitchType'] -eq 'Standard' -and $PSBoundParameters['DistributedSwitchVersion'])
                {

                    $ExceptionMessage = "Setting the hypervisor VirtualSwitchType to 'Standard' and also setting the DistributedSwitchVersion is not supported."
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException InvalidVirtualSwitchTypeParameters InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                if (-not $PSBoundParameters['DistributedSwitchUsage'])
                {

                    $ExceptionMessage = "Setting the hypervisor VirtualSwitchType to 'Distributed' requires the -DistributedSwitchUsage parameter."
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException InvalidVirtualSwitchTypeParameters InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                if (-not $PSBoundParameters['DistributedSwitchVersion'])
                {

                    $ExceptionMessage = "Setting the hypervisor VirtualSwitchType to 'Distributed' requires the -DistributedSwitchVersion parameter."
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException InvalidVirtualSwitchTypeParameters InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage

                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Updating VirtualSwitchType to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VirtualSwitchType | Write-Verbose

                $_UpdateHypervisorManagerDetails.preferences.virtualSwitchType = $VirtualSwitchType

            }

            'DistributedSwitchVersion'
            {

                # Error due to VirtualSwitchType not set to 'Distributed'
                if ($InputObject.Preferences.VirtualSwitchType -eq 'Standard' -and -not $PSBoundParameters['VirtualSwitchType'])
                {

                    $ExceptionMessage = "The Hypervisor Manager '{0}' is not currently configured to manage distributed virtual switch type. You must specify to use Distributed virtual switch type before setting the version." -f $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException InvalidVirtualSwitchType InvalidOperation 'DistributedSwitchVersion' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                # Check to make sure provided version is within $InputObject.AvailableDvsVersions.Contains($DistributedSwitchVersion)
                if (-not $InputObject.AvailableDvsVersions.Contains($DistributedSwitchVersion))
                {

                    $ExceptionMessage = "The Hypervisor Manager '{0}' does not support the requested DistributedSwitchVersion '{1}'. Please specify one of the valid supported versions: {2}" -f $InputObject.name, $DistributedSwitchVersion, [String]::Join(', ', $InputObject.AvailableDvsVersions)
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException UnsupportedVirtualSwitchVersion InvalidOperation 'DistributedSwitchVersion' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Updating DistributedSwitchVersion to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DistributedSwitchVersion | Write-Verbose
                
                $_UpdateHypervisorManagerDetails.preferences.distributedSwitchVersion = $DistributedSwitchVersion

            }

            'DistributedSwitchUsage'
            {

                # If supplied, and existing manager does not have virtualSwitchType set to Distributed or if $PSBoundParameters['VirtualSwitchType'] not supplied, error
                if ($InputObject.Preferences.VirtualSwitchType -eq 'Standard' -and -not $PSBoundParameters['VirtualSwitchType'])
                {

                    $ExceptionMessage = "The Hypervisor Manager '{0}' is not currently configured to manage distributed virtual switch type. You must specify to use Distributed virtual switch type before setting the version." -f $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException InvalidVirtualSwitchType InvalidOperation 'DistributedSwitchVersion' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Updating DistributedSwitchUsage to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DistributedSwitchUsage | Write-Verbose

                $_UpdateHypervisorManagerDetails.preferences.distributedSwitchUsage = $DistributedSwitchUsage

            }

            'HAEnabled'
            {

                $_UpdateHypervisorManagerDetails.preferences.haEnabled = $HAEnabled

            }

            'DRSEnabled'
            {

                "[{0}] Updating DRSEnabled to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DRSEnabled | Write-Verbose

                $_UpdateHypervisorManagerDetails.preferences.drsEnabled = $DRSEnabled

            }

            'MultiNicVMotionEnabled'
            {

                "[{0}] Updating MultiNicVMotionEnabled to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $MultiNicVMotionEnabled | Write-Verbose

                $_UpdateHypervisorManagerDetails.preferences.multiNicVMotion = $MultiNicVMotionEnabled

            }

        }

        Try
        {
        
            $_resp = Send-HPOVRequest -Uri $InputObject.Uri -Method PUT -Body $_UpdateHypervisorManagerDetails -AddHeader @{'If-Match' = "*"} -Hostname $InputObject.ApplianceConnection
        
        }
        
        Catch
        {
        
            $PSCmdlet.ThrowTerminatingError($_)
        
        }

        if (-not $Async)
        {

            $_resp = Wait-HPOVTaskComplete -InputObject $_resp

        }

        $_resp

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVClusterManager
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Cluster.HypervisorManager]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Switch]$Force,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ExceptionMessage = "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        $RemoveMessage = "remove '{0}' {1}" -f $InputObject.name, $ResourceCategoryEnum.HypervisorManager

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, $RemoveMessage))
        {

            "[{0}] Removing resource: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Out-String) | Write-Verbose
            "[{0}] URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose

            $_Uri = '{0}' -f $InputObject.uri

            if ($Force)
            {

                $_Uri += '?force=true'

            }

            try
            {

                Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['whatif']) 
        {

            "[{0}] -WhatIf was passed" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVClusterProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$NonCompliant,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ClustersCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }

            }

            # ($InputObject.complianceState -ne $ClusterProfileComplianceStateEnum.Consistent.State)
            if ($PSBoundParameters['NonCompliant'])
            {

                "[{0}] Filtering for non-compliant profiles." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Void]$_Query.Add(("NOT complianceState:'{0}'" -f $ClusterProfileComplianceStateEnum.Consistent.State))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.HypervisorCluster

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] Cluster Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified Cluster '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Cluster.ClusterResourceException ClusterResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage

                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.Cluster.ClusterProfile')

                    $_member

                }

            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVClusterNode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Name,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Label,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Object]$Scope = "AllResourcesInScope",

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ClusterNodeCol = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {


                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.ClusterNode

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] Cluster Node Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified Cluster Node '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.ClusterNodeResourceException ClusterNodeResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage

                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.Cluster.ClusterNode')

                    $_member

                }

            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# // TODO: DEV TEST DOCUMENT
# Use to get existing VMware hypervisor clusters from hypervisor manager
function Show-HPOVHypervisorCluster
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance Connection '{1}' (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance, $ApplianceConnection.count | Write-Verbose

            $_HypervisorManagerUris = [System.Collections.ArrayList]::new()

            # Get all hypervisor managers on the appliance
            try
            {

                $_HypervisorManagers = Send-HPOVRequest -Uri $HypervisorManagersUri -Hostname $_appliance

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_manager in $_HypervisorManagers.members)
            {

                $_uri = "hypervisorManagerUri='{0}'" -f $_manager.uri

                [void]$_HypervisorManagerUris.Add($_uri)

            }

            $_Filter = [System.Collections.ArrayList]::new()

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    [Void]$_Filter.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Filter.Add(("name:'{0}'" -f $Name))

                }

            }

            # Build the final URI
            $_uri = '{0}?filter="{1}{2}{3}"' -f $HypervisorClustersUri, [String]::Join(' OR ', $_HypervisorManagerUris.ToArray()), [String]::Join(' AND ', $_Filter.ToArray()), " AND state = 'Unmanaged'"

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # This is DIFFERENT than a Cluster Profile
            if ($_resp.Count -eq 0 -and $Name)
            {

                "[{0}] Hypervisor Cluster Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified Cluster '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Cluster.ClusterResourceException ClusterResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage

                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_resp.members)
                {

                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.Cluster.HypervisorCluster')

                    $_member

                }

            }

        }

    }
    
}

# // TODO: DEV TEST DOCUMENT
# Do members need to be shown? Maybe have the Add-HPOVClusterNode handle discovering new members that have yet to be added to cluster instead?
function Show-HPOVHypervisorClusterMember
{
    # .ExternalHelp HPOneView.500.psm1-help.xml
    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (
    )
}
function New-HPOVClusterProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory, ParameterSetName = 'UnmanageVSwitch')]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [String]$Description,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [String]$ClusterPrefix,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Cluster.HypervisorManager]$ClusterManager,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [String]$ClusterManagerLocation,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [Object]$ServerProfileTemplate,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [SecureString]$ClusterPassword,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Cluster.AddHostRequest[]]$Servers,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Switch]$OverrideManagementAddressAssignmet,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [IPAddress]$SubnetMask,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [IPAddress]$Gateway,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [IPAddress]$PrimaryDNS,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [IPAddress]$SecondaryDNS,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [IPAddress]$TertiaryDNS,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [String]$Domain,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Bool]$UseIPAddressAsHostName,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Bool]$LeaveHostsInMaintenanceMode,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [Object[]]$StorageVolume,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateSet ('VMFS', 'Unmanaged')]
        [String]$StorageVolumeFileSystem = "Unmanaged",

        [Parameter (Mandatory, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [Bool]$UnmanageVSwitch,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Switch]$OverrideNetworkingConfig,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [Bool]$ConfigurePortGroups,

        [Parameter (Mandatory = $False, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [HashTable]$VSwitchNameOverride,
        
        [Parameter (Mandatory = $False, ParameterSetName = 'OverrideSettings')]
        [ValidateNotNullOrEmpty()]
        [HashTable]$PortGroupNameOverride,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Switch]$OverrideClusterManagerConfig,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateSet ('Distributed', 'Standard')]
        [String]$VirtualSwitchType,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateSet ('AllNetworks', 'GeneralNetworks')]
        [String]$DistributedSwitchUsage,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [ValidateSet ('4.0', '4.1.0', '5.0.0', '5.1.0', '5.5.0', '6.0', '6.7')]
        [String]$DistributedSwitchVersion,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [Bool]$HAEnabled,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [Bool]$DRSEnabled,

        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [Bool]$MultiNicVMotionEnabled,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'OverrideSettings')]
        [Parameter (Mandatory = $false, ParameterSetName = 'UnmanageVSwitch')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Parameter validation
        if ($OverrideClusterManagerConfig.IsPresent -and -not $PSBoundParameters['VirtualSwitchType'])
        {

            $ExceptionMessage = "The option to override the cluster manager networking configuration was selected, but the 'VirtualSwitchType' parameter is missing."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException MissingParameter InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($OverrideClusterManagerConfig.IsPresent -and -not $PSBoundParameters['DistributedSwitchUsage'])
        {

            $ExceptionMessage = "The option to override the cluster manager networking configuration was selected, but the 'DistributedSwitchUsage' parameter is missing."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException MissingParameter InvalidOperation 'DistributedSwitchUsage' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($OverrideClusterManagerConfig.IsPresent -and -not $PSBoundParameters['DistributedSwitchVersion'])
        {

            $ExceptionMessage = "The option to override the cluster manager networking configuration was selected, but the 'DistributedSwitchVersion' parameter is missing."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException MissingParameter InvalidOperation 'DistributedSwitchVersion' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # If Standard, check if $PSBoundParameters['DistributedSwitchUsage'] is provided, error if true
        if ($PSBoundParameters['VirtualSwitchType'] -eq $ClusterProfileDistributedSwitchTypeEnum.Standard -and $PSBoundParameters['DistributedSwitchUsage'])
        {

            $ExceptionMessage = "Setting the hypervisor VirtualSwitchType to 'Standard' and also setting the DistributeSwitchUsage is not supported."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidVirtualSwitchTypeParameters InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage

            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($PSBoundParameters['VirtualSwitchType'] -eq $ClusterProfileDistributedSwitchTypeEnum.Standard -and $PSBoundParameters['DistributedSwitchVersion'])
        {

            $ExceptionMessage = "Setting the hypervisor VirtualSwitchType to 'Standard' and also setting the DistributedSwitchVersion is not supported."
            $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidVirtualSwitchTypeParameters InvalidOperation 'VirtualSwitchType' -Message $ExceptionMessage

            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    Process
    {

        # When processing connections in the SPT, look to see if a subnetUri is provided for the network with Management purpose,
        # and pull mask, gateway, and DNS from it. Or error the user hasn't provided that information.

        $_NewClusterProfile = NewObject -ClusterProfile

        switch ($PSBoundParameters.Keys)
        {

            'Name'
            {

                $_NewClusterProfile.name = $Name

                if (-not $PSBoundParameters['ClusterPrefix'])
                {

                    $_NewClusterProfile.hypervisorHostProfileTemplate.hostPrefix = $Name

                }

            }

            'Description'
            {

                $_NewClusterProfile.description = $Description

            }

            'ClusterPrefix'
            {

                $_NewClusterProfile.hypervisorHostProfileTemplate.hostPrefix = $ClusterPrefix

            }

            'ServerProfileTemplate'
            {

                $_ClusterNetworkingLayoutRequest = $null

                $_NewClusterProfile.hypervisorHostProfileTemplate.serverProfileTemplateUri = $ServerProfileTemplate.uri

                # Need to process vSwitch configuration based on connections property of SPT and if UnmanageVSwitch is $false
                if (-not $UnmanageVSwitch)
                {

                    "[{0}] Will manage cluster profile networking." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_ClusterNetworkingLayoutRequest = NewObject -ClusterNetworkingLayout

                    # Set the SPT URI
                    $_ClusterNetworkingLayoutRequest.serverProfileTemplateUri = $ServerProfileTemplate.uri
        
                    if ($OverrideClusterManagerConfig)
                    {

                        "[{0}] Overriding cluster networking configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] Overriding virtualSwitchType: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VirtualSwitchType | Write-Verbose

                        $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.virtualSwitchType = $VirtualSwitchType

                        "[{0}] Overriding distributedSwitchUsage: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DistributedSwitchUsage | Write-Verbose

                        $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.distributedSwitchUsage = $DistributedSwitchUsage

                        "[{0}] Overriding distributedSwitchVersion: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DistributedSwitchVersion | Write-Verbose

                        # Check to make sure provided version is within $InputObject.AvailableDvsVersions.Contains($DistributedSwitchVersion)
                        if (-not $ClusterManager.AvailableDvsVersions.Contains($DistributedSwitchVersion))
                        {

                            $ExceptionMessage = "The Hypervisor Manager '{0}' does not support the requested DistributedSwitchVersion '{1}'. Please specify one of the valid supported versions: {2}" -f $ClusterManager.name, $DistributedSwitchVersion, [String]::Join(', ', $ClusterManager.AvailableDvsVersions)
                            $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException UnsupportedVirtualSwitchVersion InvalidOperation 'DistributedSwitchVersion' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.distributedSwitchVersion = $DistributedSwitchVersion

                        if ($PSBoundParameters.Keys -contains 'MultiNicVMotionEnabled')
                        {

                            "[{0}] Overriding multiNicVMotion: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $MultiNicVMotionEnabled | Write-Verbose

                            $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.multiNicVMotion = $MultiNicVMotionEnabled

                        }

                    }

                    # Use the Hypervisor Manager settings
                    else
                    {

                        "[{0}] Will use default cluster manager network settings." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.virtualSwitchType        = $ClusterManager.Preferences.VirtualSwitchType

                        if ($ClusterManager.Preferences.VirtualSwitchType -ne $ClusterProfileDistributedSwitchTypeEnum.Standard)
                        {

                            $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.distributedSwitchUsage   = $ClusterManager.Preferences.DistributedSwitchUsage
                            $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.distributedSwitchVersion = $ClusterManager.Preferences.DistributedSwitchVersion

                        }
                        
                        $_ClusterNetworkingLayoutRequest.hypervisorClusterSettings.multiNicVMotion          = $ClusterManager.Preferences.MultiNicVMotion

                    }

                    if ($PSBoundParameters.Keys -contains 'ConfigurePortGroups')
                    {

                        "[{0}] Will not create port groups." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_ClusterNetworkingLayoutRequest.virtualSwitchConfigPolicy.configurePortGroups = $ConfigurePortGroups

                    }

                    # Generate a new vSwitch Layout
                    Try
                    {

                        $_ClusterNetworkingLayoutResults = Send-HPOVRequest -Uri $GenerateClusterProfileNetworkingLayoutUri -Method POST -Body $_ClusterNetworkingLayoutRequest -Hostname $ServerProfileTemplate.ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    # Or based on the override vswitch configuration

                    # [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
                    # [Parameter (Mandatory = $False, ParameterSetName = 'OverrideVswitchConfig')]
                    # [ValidateNotNullOrEmpty()]
                    # [HashTable]$VSwitchNameOverride, # @{ "NetworkName" = "OverrideName" }
                    
                    # [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
                    # [Parameter (Mandatory = $False, ParameterSetName = 'OverrideVswitchConfig')]
                    # [ValidateNotNullOrEmpty()]
                    # [HashTable]$PortGroupNameOverride, # @{ "NetworkName" = "OverrideName" }

                    ForEach ($_NetConf in $_ClusterNetworkingLayoutResults)
                    {

                        [void]$_NewClusterProfile.hypervisorHostProfileTemplate.virtualSwitches.Add($_NetConf)

                    }

                }

                else
                {

                    "[{0}] Will not manage cluster profile networking." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                if ($OverrideManagementAddressAssignmet)
                {

                    # Check if the SPT is set to auto or static IP Address management
                    if (($ServerProfileTemplate.osDeploymentSettings.osCustomAttributes | Where-Object name -match '.dhcp').value -ne $true -and -not ($ServerProfileTemplate.osDeploymentSettings.osCustomAttributes | Where-Object name -match '.ipaddress'))
                    {

                        $ExceptionMessage = "IP configuration in server profile template is set to Auto but static IP configuration is provided in cluster profile."
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidOverrideManagementAddressAssignmetParameter InvalidOperation 'OverrideManagementAddressAssignmet' -Message $ExceptionMessage

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    elseif (($ServerProfileTemplate.osDeploymentSettings.osCustomAttributes | Where-Object name -match '.dhcp').value -eq $true -and -not ($ServerProfileTemplate.osDeploymentSettings.osCustomAttributes | Where-Object name -match '.ipaddress'))
                    {

                        $ExceptionMessage = "IP configuration in server profile template is set to DHCP but static IP configuration is provided in cluster profile."
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidOverrideManagementAddressAssignmetParameter InvalidOperation 'OverrideManagementAddressAssignmet' -Message $ExceptionMessage

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    "[{0}] Overriding cluster management address assignment." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_NewClusterProfile | Add-Member -NotePropertyName mgmtIpSettingsOverride -NotePropertyValue (NewObject -ClusterProfileOverrideMgmtIPSettings)

                    $_NewClusterProfile.mgmtIpSettingsOverride.netMask = $SubnetMask
                    $_NewClusterProfile.mgmtIpSettingsOverride.gateway = $Gateway

                    if ($PSBoundParameters['PrimaryDNS'])
                    {

                        $_NewClusterProfile.mgmtIpSettingsOverride.primaryDns = $PrimaryDNS

                    }

                    if ($PSBoundParameters['SecondaryDNS'])
                    {

                        $_NewClusterProfile.mgmtIpSettingsOverride.secondaryDns = $SecondaryDNS

                    }

                    if ($PSBoundParameters['TertiaryDNS'])
                    {

                        $_NewClusterProfile.mgmtIpSettingsOverride.tertiaryDNS = $TertiaryDNS

                    }

                    if ($PSBoundParameters['Domain'])
                    {

                        $_NewClusterProfile.mgmtIpSettingsOverride.dnsDomain = $Domain

                    }

                }
                
            }

            'ClusterPassword'
            {

                $_NewClusterProfile.hypervisorHostProfileTemplate.deploymentPlan.serverPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ClusterPassword))
                
            }

            'Scope'
            {

                ForEach ($_Scope in $Scope)
                {

                    "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                    [void]$_NewClusterProfile.initialScopeUris.Add($_Scope.Uri)

                }

            }

            'VirtualSwitchType'
            {

                "[{0}] Setting VirtualSwitchType to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $VirtualSwitchType | Write-Verbose

                $_NewClusterProfile.hypervisorClusterSettings.virtualSwitchType = $VirtualSwitchType

            }

            'DistributedSwitchVersion'
            {

                # Check to make sure provided version is within $InputObject.AvailableDvsVersions.Contains($DistributedSwitchVersion)
                if (-not $ClusterManager.AvailableDvsVersions.Contains($DistributedSwitchVersion))
                {

                    $ExceptionMessage = "The Hypervisor Manager '{0}' does not support the requested DistributedSwitchVersion '{1}'. Please specify one of the valid supported versions: {2}" -f $InputObject.name, $DistributedSwitchVersion, [String]::Join(', ', $InputObject.AvailableDvsVersions)
                    $ErrorRecord = New-ErrorRecord HPOneView.HypervisorManagerException UnsupportedVirtualSwitchVersion InvalidOperation 'DistributedSwitchVersion' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Setting DistributedSwitchVersion to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DistributedSwitchVersion | Write-Verbose
                
                $_NewClusterProfile.hypervisorClusterSettings.distributedSwitchVersion = $DistributedSwitchVersion

            }

            'DistributedSwitchUsage'
            {

                "[{0}] Setting DistributedSwitchUsage to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DistributedSwitchUsage | Write-Verbose

                $_NewClusterProfile.hypervisorClusterSettings.distributedSwitchUsage = $DistributedSwitchUsage

            }

            'HAEnabled'
            {

                "[{0}] Updating HAEnabled to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $HAEnabled | Write-Verbose

                $_NewClusterProfile.hypervisorClusterSettings.haEnabled = $HAEnabled

            }

            'DRSEnabled'
            {

                "[{0}] Updating DRSEnabled to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DRSEnabled | Write-Verbose

                $_NewClusterProfile.hypervisorClusterSettings.drsEnabled = $DRSEnabled

            }

            'MultiNicVMotionEnabled'
            {

                "[{0}] Updating MultiNicVMotionEnabled to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $MultiNicVMotionEnabled | Write-Verbose

                $_NewClusterProfile.hypervisorClusterSettings.multiNicVMotion = $MultiNicVMotionEnabled

            }

            'ClusterManager'
            {

                if ($PSCmdlet.ParameterSetName -eq 'Default' -and -not $OverrideClusterManagerConfig.IsPresent)
                {

                    "[{0}] Using hypervisor managers default networking preferences" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($ClusterManager.Preferences.VirtualSwitchType -eq 'Distributed')
                    {

                        $_NewClusterProfile.hypervisorClusterSettings.distributedSwitchVersion = $ClusterManager.Preferences.DistributedSwitchVersion
                        $_NewClusterProfile.hypervisorClusterSettings.distributedSwitchUsage   = $ClusterManager.Preferences.DistributedSwitchUsage

                    }

                    $_NewClusterProfile.hypervisorClusterSettings.drsEnabled               = $ClusterManager.Preferences.DrsEnabled
                    $_NewClusterProfile.hypervisorClusterSettings.haEnabled                = $ClusterManager.Preferences.HaEnabled
                    $_NewClusterProfile.hypervisorClusterSettings.multiNicVMotion          = $ClusterManager.Preferences.MultiNicVMotion
                    $_NewClusterProfile.hypervisorClusterSettings.virtualSwitchType        = $ClusterManager.Preferences.VirtualSwitchType

                }

                $_NewClusterProfile.hypervisorManagerUri = $ClusterManager.Uri
                $_NewClusterProfile.path = $Path

            }

            'ClusterManagerLocation'
            {

                # Generate error that path is not valid
                $_FilterDelegate = [Func[object,bool]]{ param ($p) return $p.UserPath -eq $ClusterManagerLocation }

                if (-not [Linq.Enumerable]::ToArray([System.Linq.Enumerable]::Where($ClusterManager.Locations, $_FilterDelegate)))
                {

                    $ExceptionMessage = "The provided cluster manager location '{0}' is not found in '{1}' cluster manager." -f $ClusterManagerLocation, $ClusterManager.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidClusterManagerLocationParameter InvalidOperation 'ClusterManagerLocation' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                "[{0}] Setting hypervisor manager location: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ClusterManagerLocation | Write-Verbose

                $_NewClusterProfile.path = $ClusterManagerLocation

            }

            'UnmanageVSwitch'
            {

                $_NewClusterProfile.hypervisorHostProfileTemplate.virtualSwitchConfigPolicy.manageVirtualSwitches = -not $UnmanageVSwitch

                # If UnmanageVSwitch is True, then ConfigurePortGroups needs to be disabled
                if ($UnmanageVSwitch)
                {

                    $_NewClusterProfile.hypervisorHostProfileTemplate.virtualSwitchConfigPolicy.configurePortGroups   = -not $UnmanageVSwitch

                }
                
            }

            'ConfigurePortGroups'
            {

                $_NewClusterProfile.hypervisorHostProfileTemplate.virtualSwitchConfigPolicy.configurePortGroups   = $ConfigurePortGroups

            }

            # Add hypervisor nodes
            'Servers'
            {

                ForEach ($_Server in $Servers)
                {

                    # Generate error that overrride management address assignment was set, but the Add Hosts request contains an empty mgmtIp value
                    if ($OverrideManagementAddressAssignmet -and [String]::IsNullOrEmpty($_Server.mgmtIp) -and 
                        ($ServerProfileTemplate.osDeploymentSettings.osCustomAttributes | Where-Object name -match '.dhcp').value -eq $false -and 
                        ($ServerProfileTemplate.osDeploymentSettings.osCustomAttributes | Where-Object name -match '.ipaddress'))
                    {

                        $ExceptionMessage = "IP configuration in server profile template is set to DHCP but static IP configuration is provided in cluster profile."
                        $ErrorRecord = New-ErrorRecord HPOneView.Library.ParameterValidationException InvalidOverrideManagementAddressAssignmetParameter InvalidOperation 'OverrideManagementAddressAssignmet' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    [Void]$_NewClusterProfile.addHostRequests.Add($_Server)

                }

            }
            
            'StorageVolume'
            {

                ForEach ($_Volume in $StorageVolume)
                {

                    $_SharedVolumeToAdd = NewObject -ClusterProfileSharedStorageVolume

                    $_SharedVolumeToAdd.storageVolumeUri     = $_Volume.uri
                    $_SharedVolumeToAdd.volumeFileSystemType = $StorageVolumeFileSystem

                    [void]$_NewClusterProfile.sharedStorageVolumes.Add($_SharedVolumeToAdd)

                }

            }
            
            'LeaveHostsInMaintenanceMode'
            {

                $_NewClusterProfile.hypervisorHostProfileTemplate.hostConfigPolicy.leaveHostInMaintenance = $LeaveHostsInMaintenanceMode

            }

            'UseIPAddressAsHostName'
            {

                $_NewClusterProfile.hypervisorHostProfileTemplate.hostConfigPolicy.useHostnameToRegister = -not $UseIPAddressAsHostName

            }

        }

        Try
        {

            $_resp = Send-HPOVRequest -Uri $ClusterProfilesUri -Method POST -Body $_NewClusterProfile -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $Async.IsPresent)
        {

            $_resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_resp

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Namreposie, $_appliance.Name | Write-Verbose

    }

}

function New-HPOVClusterProfileMember
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Cluster.AddHostRequest])]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias('Server')]
        [Object]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)] # Not needed if management network is associated with an IP Address Pool
        [ValidateNotNullOrEmpty()]
        [IPAddress]$IPv4Address,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.ServerProfile.OSDeployment.OSDeploymentParameter[]]$OSDeploymentAttributes

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {

        if ($PSBoundParameters['OSDeploymentAttributes'] -and $PSBoundParameters['IPv4Address'])
        {

            New-Object HPOneView.Cluster.AddHostRequest($InputObject.uri, $IPv4Address, $OSDeploymentAttributes)

        }

        elseif ($PSBoundParameters['OSDeploymentAttributes'])
        {

            New-Object HPOneView.Cluster.AddHostRequest($InputObject.uri, $OSDeploymentAttributes)

        }

        elseif ($PSBoundParameters['IPv4Address'])
        {

            New-Object HPOneView.Cluster.AddHostRequest($InputObject.uri, $IPv4Address)

        }

        else
        {

            New-Object HPOneView.Cluster.AddHostRequest($InputObject.uri)

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

    }

}

# //TODO: DEV, Document, Test
function Import-HPOVClusterProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Alias('Name')]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Default')] # GET FROM SHOW-HPOVHypervisorCluster
        [Object]$Cluster,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateScript ({if (-not ($_.category -eq $ResourceCategoryEnum.ClusterProfile)) { 
            
            Throw "'$($_.category)' is not an allowed resource category. The resource object category must be '$($ResourceCategoryEnum.ClusterProfile)'. Please check the value and try again." 
        }
        else { $True }})]
        [Object[]]$ServerProfile,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            # Handle default cause of AllResourcesInScope
            if ($Scope -eq 'AllResourcesInScope')
            {

                "[{0}] Processing AllResourcesInScope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Scopes = $_appliance.ActivePermissions | Where-Object Active

                # If one scope contains 'AllResources' ScopeName "tag", then all resources should be returned regardless.
                if ($_Scopes | Where-Object ScopeName -eq 'AllResources')
                {

                    $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                    "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

                }

                # Process ApplianceConnection ActivePermissions collection
                else
                {

                    Try
                    {

                        $_ScopeQuery = Join-Scope $_Scopes

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

                }

            }

            elseif ($Scope | Where-Object ScopeName -eq 'AllResources')
            {

                $_ScopeNames = [String]::Join(', ', ($_Scopes | Where-Object ScopeName -eq 'AllResources').ScopeName)

                "[{0}] Scope(s) {1} is set to 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            elseif ($Scope -eq 'AllResources')
            {

                "[{0}] Requesting scope 'AllResources'. Will not add scope to URI query parameter." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeNames | Write-Verbose

            }

            else
            {

                Try
                {

                    $_ScopeQuery = Join-Scope $Scope

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [Void]$_Query.Add(("({0})" -f $_ScopeQuery))

            }

            if ($Name)
            {

                "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                if ($Name.Contains('*'))
                {

                    "[{0}] Filtering for Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

                    [Void]$_Query.Add(("name%3A{0}" -f $Name.Replace("*", "%2A").Replace(',','%2C').Replace(" ", "?")))

                }

                else
                {

                    [Void]$_Query.Add(("name:'{0}'" -f $Name))

                }

            }

            if ($Label)
            {

                [Void]$_Query.Add(("labels:'{0}'" -f $Label))

            }

            $_Category = 'category={0}' -f $ResourceCategoryEnum.ClusterProfiles

            # Build the final URI
            $_uri = '{0}?{1}&sort=name:asc&query={2}' -f $IndexUri,  [String]::Join('&', $_Category), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                [Array]$_ResourcesFromIndexCol = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if($_ResourcesFromIndexCol.Count -eq 0 -and $Name)
            {

                "[{0}] ClusterProfile Resource Name '{1}' was not found on appliance {2}. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

                $ExceptionMessage = "The specified ClusterProfile '{0}' was not found on '{1}' appliance connection. Please check the name again, and try again." -f $Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Cluster.ClusterProfileResourceException ClusterProfileResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage

                $PSCmdlet.WriteError($ErrorRecord)

            }

            else
            {

                ForEach ($_member in $_ResourcesFromIndexCol)
                {

                    $_member.PSObject.TypeNames.Insert(0,'HPOneView.Cluster.ClusterProfile')

                    $_member

                }

            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# //TODO: DEV, Document, Test
# Maybe this Cmdlet supports two cases:
# 1. Add a new member to an existing cluster, which would require Synergy and I3S
# 2. Import deployed cluster node outside of OV
function Add-HPOVClusterNode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Alias("Name")]
        [String]$ComputerName,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [PSCredential]$Credential,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,

        [Parameter (ParameterSetName = "Default", Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("Appliance")]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        if ($PSBoundParameters["Scope"])
        {

            $_InitialScopeUris = New-Object "System.Collections.Generic.List[String]"

            ForEach ($_Scope in $Scope)
            {

                "[{0}] Adding resource to Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Scope.Name | Write-Verbose

                $_InitialScopeUris.Add($_Scope.Uri)

            }

        }

        $_Import = NewObject -AddCategoryType

        

        Try
        {

            $_resp = Send-HPOVRequest -Uri Uri -Method POST -Body $_Import -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not $Async.IsPresent)
        {

            $_resp | Wait-HPOVTaskComplete

        }

        else
        {

            $_resp

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVClusterProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Cluster.CompliancePreview])]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Alias('Name')]
        [Object]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($PipelineInput) 
        {
        
            "[{0}] Processing Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        # Process server profile resource name
        if ($InputObject -is [String])
        {

            Try
            {

                $InputObject = Get-HPOVClusterProfile -Name $InputObject -ApplianceConnection $ApplianceConnect -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Not sure if I want to support this. Should 1 server hardware of a cluster be provided?
        # Validate the Input object is the allowed category
        elseif ($InputObject.category -ne $ResourceCategoryEnum.ClusterProfile)
        {

            $ExceptionMessage = "The provided InputObject object ({0}) category '{1}' is not an allowed value. Expected category value is '{2}'. Please correct your input value." -f $InputObject.name, $InputObject.category, $ResourceCategoryEnum.ClusterProfile
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidResourceObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not $InputObject.ApplianceConnection)
        {

            $ExceptionMessage = "The provided InputObject object ({0}) does not contain the required 'ApplianceConnection' object property. Please correct your input value." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException MissingApplianceConnectionProperty InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Processing Server Profile: '{1} [{2}]'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

        "{0}] Is Server Profile 'Compliant': {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.templateCompliance | Write-Verbose

        if ($InputObject.complianceState -ne $ClusterProfileComplianceStateEnum.Consistent.State)
        {

            try
            {

                $_cpUpdateOperations = Send-HPOVRequest -Uri ($InputObject.uri + '/compliance-preview') -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $ReviewObject = New-Object HPOneView.Cluster.CompliancePreview ($InputObject.hostProfileName, 
                                                                            $_cpUpdateOperations.isOnlineUpdate, 
                                                                            $_cpUpdateOperations.ApplianceConnection)

            $_cpUpdateOperations.serverProfileComplianceDetails.automaticUpdates | ForEach-Object { [void]$ReviewObject.AutomaticUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
            $_cpUpdateOperations.hypervisorProfileComplianceDetails.automaticUpdates | ForEach-Object { [void]$ReviewObject.AutomaticUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
            $_cpUpdateOperations.serverProfileComplianceDetails.manualUpdates | ForEach-Object { [void]$ReviewObject.ManualUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
            $_cpUpdateOperations.hypervisorProfileComplianceDetails.manualUpdates | ForEach-Object { [void]$ReviewObject.ManualUpdates.Add((ConvertFromEmbeddedJsonString $_)) }

            $_ShouldProcessMessage = "Update Cluster Profile configuration. WARNING: Depending on this action, there might be a brief outage."

            if ($PSCmdlet.ShouldProcess($InputObject.name, $ClusterProfileComplianceStateEnum.($InputObject.complianceState).Message))
            { 

                "[{0}] Sending request to {1} configuration" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSCmdlet.ParameterSetName | Write-Verbose

                Try
                {

                    $_task = Send-HPOVRequest -Uri $InputObject.uri -Method PATCH -Body $_Operation -Hostname $InputObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not($PSBoundParameters['Async']))
                {
                
                    $_task = $_task | Wait-HPOVTaskComplete
            
                }

                $_task
                
            }

            elseif ($PSBoundParameters['WhatIf'])
            {
            
                "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Need to return the HPOneView.Cluster.CompliancePreview object
                $ReviewObject
        
            }

            else 
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }  

        }

        else
        {

            Write-Warning ('Skipping {0} Cluster Profile, as it is Compliant.' -f $InputObject.name)

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

    }

}

# //TODO: DEV, Document, Test
function Update-HPOVClusterNode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Cluster.CompliancePreview])]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Alias('Name')]
        [Object]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($PipelineInput) 
        {
        
            "[{0}] Processing Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        # Process server profile resource name
        if ($InputObject -is [String])
        {

            Try
            {

                $InputObject = Get-HPOVClusterNode -Name $InputObject -ApplianceConnection $ApplianceConnect -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Not sure if I want to support this. Should 1 server hardware of a cluster be provided?
        # Validate the Input object is the allowed category
        elseif ($InputObject.category -ne $ResourceCategoryEnum.ClusterProfile)
        {

            $ExceptionMessage = "The provided InputObject object ({0}) category '{1}' is not an allowed value. Expected category value is '{2}'. Please correct your input value." -f $InputObject.name, $InputObject.category, $ResourceCategoryEnum.ClusterProfile
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException InvalidResourceObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if (-not $InputObject.ApplianceConnection)
        {

            $ExceptionMessage = "The provided InputObject object ({0}) does not contain the required 'ApplianceConnection' object property. Please correct your input value." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException MissingApplianceConnectionProperty InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        "[{0}] Processing Cluster Profile Host: '{1} [{2}]'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

        "{0}] Is Cluster Profile Host 'Compliant': {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.templateCompliance | Write-Verbose

        if ($InputObject.complianceState -ne $ClusterProfileComplianceStateEnum.Consistent.State)
        {

            try
            {

                $_cpUpdateOperations = Send-HPOVRequest -Uri ($InputObject.uri + '/compliance-preview') -Hostname $InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $ReviewObject = New-Object HPOneView.Cluster.CompliancePreview ($InputObject.hostProfileName, 
                                                                            $_cpUpdateOperations.isOnlineUpdate, 
                                                                            $_cpUpdateOperations.ApplianceConnection)

            $_cpUpdateOperations.serverProfileComplianceDetails.automaticUpdates | ForEach-Object { [void]$ReviewObject.AutomaticUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
            $_cpUpdateOperations.hypervisorProfileComplianceDetails.automaticUpdates | ForEach-Object { [void]$ReviewObject.AutomaticUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
            $_cpUpdateOperations.serverProfileComplianceDetails.manualUpdates | ForEach-Object { [void]$ReviewObject.ManualUpdates.Add((ConvertFromEmbeddedJsonString $_)) }
            $_cpUpdateOperations.hypervisorProfileComplianceDetails.manualUpdates | ForEach-Object { [void]$ReviewObject.ManualUpdates.Add((ConvertFromEmbeddedJsonString $_)) }

            $_ShouldProcessMessage = "Update Cluster Profile Host configuration. WARNING: Depending on this action, there might be a brief outage."

            if ($PSCmdlet.ShouldProcess($InputObject.name, $ClusterProfileComplianceStateEnum.($InputObject.complianceState).Message))
            { 

                "[{0}] Sending request to {1} configuration" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSCmdlet.ParameterSetName | Write-Verbose

                Try
                {

                    $_task = Send-HPOVRequest -Uri $InputObject.uri -Method PATCH -Body $_Operation -Hostname $InputObject.ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not($PSBoundParameters['Async']))
                {
                
                    $_task = $_task | Wait-HPOVTaskComplete
            
                }

                $_task
                
            }

            elseif ($PSBoundParameters['WhatIf'])
            {
            
                "[{0}] User included -WhatIf." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Need to return the HPOneView.Cluster.CompliancePreview object
                $ReviewObject
        
            }

            else 
            {

                "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }  

        }

        else
        {

            Write-Warning ('Skipping {0} Cluster Profile, as it is Compliant.' -f $InputObject.name)

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

    }

}

function Remove-HPOVClusterProfile
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Switch]$Force,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ExceptionMessage = "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        Write-Warning -Message "**** WARNING **** - Removing a Cluster Profile from OneView also destroys the cluster within the cluster manager. Do not remove the cluster profile unless you intend to also destroy the cluster within the cluster manager."
        
        $RemoveMessage = "remove '{0}' {1}" -f $InputObject.name, $ResourceCategoryEnum.ClusterProfile

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection, $RemoveMessage))
        {

            "[{0}] Removing resource: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Out-String) | Write-Verbose
            "[{0}] URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose

            $_Uri = '{0}' -f $InputObject.uri

            if ($Force)
            {

                $_Uri += '?force=true'

            }

            try
            {

                Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag } -Hostname $InputObject.ApplianceConnection

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['whatif']) 
        {

            "[{0}] -WhatIf was passed" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enter-HPOVClusterNodeMaintenanceMode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Alias('Name')]
        [Object]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($InputObject.type -notmatch $ClusterProfileHostType)
        {

            "[{0}] Invalid InputObject provided. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ExceptionMessage = "The provided InputObject parameter value is not a valid ClusterProfileHost resource."
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.powerState -ne $ClusterProfileHostPowerStateEnum.On)
        {

            "[{0}] ClusterProfileHost not in PoweredOn state, '{1}'. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ClusterProfileHostPowerStateEnum[$InputObject.powerState].Value | Write-Verbose

            $ExceptionMessage = "The provided InputObject parameter value is not a valid ClusterProfileHost resource."
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            $_InputObject = $InputObject.PSObject.Copy()

            $_InputObject.powerState = $ClusterProfileHostPowerStateEnum.EnterMaintenanceMode

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_InputObject.uri -Method PUT -Body $_InputObject -Hostname $_InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if ($Async)
        {

            $_resp = Wait-HPOVTaskComplete -InputObject $_resp

        }

        $_resp

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

    }

}

function Exit-HPOVClusterNodeMaintenanceMode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Alias('Name')]
        [Object]$InputObject,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($InputObject.type -notmatch $ClusterProfileHostType)
        {

            "[{0}] Invalid InputObject provided. Generate Error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ExceptionMessage = "The provided InputObject parameter value is not a valid ClusterProfileHost resource."
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($InputObject.powerState -ne $ClusterProfileHostPowerStateEnum.InMaintenanceMode)
        {

            "[{0}] ClusterProfileHost not in the InMaintenance state, '{1}'. Generating error." -f $MyInvocation.InvocationName.ToString().ToUpper(), $ClusterProfileHostPowerStateEnum[$InputObject.powerState].Value | Write-Verbose

            $ExceptionMessage = "ClusterProfileHost not in the InMaintenance state, '{0}'." -f $InputObject.powerState
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            $_InputObject = $InputObject.PSObject.Copy()

            $_InputObject.powerState = $ClusterProfileHostPowerStateEnum.ExitMaintenanceMode

            Try
            {

                $_resp = Send-HPOVRequest -Uri $_InputObject.uri -Method PUT -Body $_InputObject -Hostname $_InputObject.ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if ($Async)
        {

            $_resp = Wait-HPOVTaskComplete -InputObject $_resp

        }

        $_resp

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_appliance.Name | Write-Verbose

    }
    
}

#######################################################
# Index:
#

function Search-HPOVIndex  
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Search,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$Category,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$Count = 50,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$Start = 0,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Initialize collection to hold multiple volume attachments objects
        $_IndexSearchResults = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Processing Appliance Connection '{0}' (of {1})" -f $_appliance.Name, $ApplianceConnection.count | Write-Verbose

            $uri = $indexuri + '?start=' + $start.ToString() + '&count=' + $count.ToString()
        
            if ($search) 
            { 
                
                $uri = $uri + "&userQuery=" + $search 
            
            }
            
            if ($category) 
            { 
                
                $uri = $uri + "&category=" + $category 
            
            }
            
            $uri = $uri.Replace(" ", "%20")

            Try
            {

                $r = Send-HPOVRequest $uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }        
            
            if ($r.count -eq 0 -and $PSBoundParameters['Search']) 
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException NoIndexResults ObjectNotFound 'Search' -Message ("No Index results found for '{0}' on '{1}." -f $Search, $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)
            }

            else 
            {
                
                $r.members | ForEach-Object {

                    $_.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.IndexResource')

                    [void]$_IndexSearchResults.Add($_)

                }

            }

        }

    }

    End
    {

        "Done. {0} index resource(s) found." -f $_IndexSearchResults.count | Write-Verbose

        Return $_IndexSearchResults

    }

}

function Search-HPOVAssociations 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [String]$AssociationName,

        [Parameter (Mandatory = $false, ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [object]$Parent,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [object]$Child,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$Count = 50,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Int]$Start = 0,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )    

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSBoundParameters['Parent'])
        {

            if (-not($Parent -is [PSCustomObject]))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Parent' -Message "The provided -Parent Parameter value is not an Object. Please correct the value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            $ApplianceConnection = $Parent.ApplianceConnection

        }

        elseif ($PSBoundParameters['Child'])
        {

            if (-not($Child -is [PSCustomObject]))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Chuld' -Message "The provided -Child Parameter value is not an Object. Please correct the value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            $ApplianceConnection = $Child.ApplianceConnection

        }

        if ($PSBoundParameters['ApplianceConnection'])
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        # Initialize collection to hold multiple volume attachments objects
        $_IndexSearchResults = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $uri = $associationsUri + '?start=' + $start.ToString() + '&count=' + $count.ToString()

        if ($PSBoundParameters['AssociationName']) 
        { 

            $uri = $uri + "&name=" + $associationName 
        
        }
        
        if ($Parent) 
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Parent resource: {0}" -f ($Parent | Out-String) | Write-Verbose 

            if (-not($Parent -is [PSCustomObject]))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Parent' -Message "The provided -Parent Parameter value is not an Object. Please correct the value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
                    
            $uri = $uri + "&parentUri=" + $Parent.uri
        
        }
        
        if ($PSBoundParameters['Child']) 
        {

            "[$($MyInvocation.InvocationName.ToString().ToUpper())] Child resource: {0}" -f ($Child | Out-String) | Write-Verbose 

            if (-not($Child -is [PSCustomObject]))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Child' -Message "The provided -Child Parameter value is not an Object. Please correct the value."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            $uri = $uri + "&childUri=" + $Child.uri
        
        }
        
        $uri = $uri.Replace(" ", "%20")

        Try
        {

            $r = Send-HPOVRequest $uri -Hostname $ApplianceConnection.Name

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        $r.members | ForEach-Object {

            [void]$_IndexSearchResults.Add($_)

        }

    }
    
    End
    {

        Return $_IndexSearchResults

    }

}

#######################################################
# Tasks:
#

function Get-HPOVTask 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ResourceCategory")]
        [ValidateNotNullorEmpty()]
        [Alias ("TaskName")]
        [String]$Name,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = "Default")]
        [Alias('Resource')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "ResourceCategory")]
        [ValidateNotNullorEmpty()]
        [Alias ("Category")]
        [String]$ResourceCategory,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ResourceCategory")]
        [ValidateNotNullorEmpty()]
        [ValidateSet ("Unknown","New","Running","Pending","Stopping","Suspended","Terminated","Killed","Completed","Error","Warning")]
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ResourceCategory")]
        [ValidateScript({ if ([Int]$_ -gt -1) {$true} else {Throw "The Count Parameter value '$_' is invalid."}})]
        [Int]$Count = 0,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "ResourceCategory")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $uri = $TasksUri + '?sort=modified:desc'

            if ($PSBoundParameters['Name']) 
            { 
        
                "[{0}] Name Parameter value: $($Name)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $Uri += "&filter=name='$Name'" 
        
            }

            if ($PSBoundParameters['State']) 
            { 
        
                "[{0}] State Parameter value: $($State)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $Uri += "&filter=taskState='$State'" 
                            
            }

            if ($PSBoundParameters['Count']) 
            {

                "[{0}] Count Parameter value: $($Count)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                    
                $Uri += "&count=$Count&sort=created:descEnding" 

            }


            "[{0}] Parameter Set Name resolved to: $($PSCmdlet.ParameterSetName)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            switch ($PSCmdlet.ParameterSetName) 
            {

                "Default" 
                {
                    
                    if ($PSBoundParameters['InputObject']) 
                    {

                        # If the Resource value is a Name
                        if (($InputObject -is [String]) -and (-not($InputObject.StartsWith("/rest/"))))
                        {

                            "[{0}] Resource Parameter Name: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $Uri += "&filter=associatedResource.resourceName='$InputObject'" 
                            
                        }

                        # Checking if the input is System.String and IS a URI
                        elseif (($InputObject -is [String]) -and ($InputObject.StartsWith("/rest/"))) 
                        {
                
                            "[{0}] Resource Parameter URI: $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                            $Uri += "&filter=associatedResource.resourceUri='$InputObject'" 
                            
            
                        }

                        # Checking if the input is PSCustomObject, and the category type is not null, which would be passed via pipeline input
                        elseif (($InputObject -is [PSCustomObject]) -and ($InputObject.category)) 
                        {

                            "[{0}] Resource is an object: '$($InputObject.name)' of type '$($InputObject.Category)'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            "[{0}] Using URI value ($($InputObject.Uri)) from input object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            $Uri += "&filter=associatedResource.resourceUri='$($InputObject.Uri)'" 
                            
                        }

                        else 
                        {
                             
                            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -Message "The Resource input Parameter was not recognized as a valid type or format."
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                            
                        }
                        
                    }

                } # End Default
                
                "ResourceCategory" 
                { 
                
                    "[{0}] Resource Category was specified: $($ResourceCategory)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $Uri += "&filter=associatedResource.resourceCategory='$($ResourceCategory)'" 

                } # End ResourceCategory

            } # End switch

            "[{0}] URI: $($Uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($Count -gt 0 ) 
            { 
            
                "[{0}] Getting $($Count) task objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
        
            }

            else 
            { 
            
                "[{0}] ($($Count)) Returning all available task objects." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
        
            }

            try 
            {
        
                $_tasks = Send-HPOVRequest $Uri -Hostname $_appliance

                if ($_tasks.count -eq 0) 
                { 
                
                    "[{0}] No tasks found on Appliance '$($_appliance.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if ($Name)
                    {

                        $ExceptionMessage = "Task '{0}' name was not found on '{1}' appliance connection." -f $Name, $_appliance.Name
                        $ErrorRecord = New-ErrorRecord InvalidOperationException ResourceNotFound ObjectNotFound 'Name' -Message $ExceptionMessage
                        $PSCmdlet.WriteError($ErrorRecord)

                    }
                    
                }

                else 
                { 
                
                    $_tasks.members | ForEach-Object { 
                            
                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.TaskResource") 
                        
                        [void]$_TaskCollection.Add($_)
                        
                    }
 
                }

            }

            catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)
            
            }

        }

    }    

    End
    {

        "[$($MyInvocation.InvocationName.ToString().ToUpper())] Done. {0} task resource(s) found." -f $_TaskCollection.count | Write-Verbose

        Return $_TaskCollection

    }

}

function Wait-HPOVTaskStart 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [Alias ('taskuri', 'task')]
        [object]$InputObject,

        [Parameter (Mandatory = $false)]
        [String]$resourceName,

        [Parameter (Mandatory = $false)]
        [timespan]$Timeout = $DefaultTimeout,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    ) 

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject']) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            if ($InputObject -is [String] -and $ApplianceConnection.Count -gt 1)
            {
            
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'Task' -Message "The -Task Parameter requires an Appliance to be specified. Please provide the Appliance Connection object or name by using the -ApplianceConnection Parameter."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            else
            {


                "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
                {


                    For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                    {

                        Try 
                        {
                
                            $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                        }

                        Catch [HPOneview.Appliance.AuthSessionException] 
                        {

                            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                        }

                        Catch 
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }


                    }

                }

                else
                {

                    Try 
                    {
                
                        $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

        }

    }

    Process 
    {

        if ($PipelineInput) 
        { 
            
            "[{0}] Task resource passed via pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        }

        # Validate the task object
        if (($InputObject -is [String]) -and ($InputObject.StartsWith($TasksUri))) 
        {
            
            "[{0}] Task is System.String $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_uri = $InputObject
        
        }

        elseif (($InputObject -is [PSCustomObject] -or $InputObject -is [HPOneView.Appliance.TaskResource]) -and ($InputObject.category -ieq 'tasks')) 
        {
        
            "[{0}] Task is $($InputObject.GetType()). Task URI: $($taInputObjectsk.uri)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $ApplianceConnection = $InputObject.ApplianceConnection

            $_uri = $InputObject.uri
        
        }

        else 
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument 'InputObject' -Message "Invalid task. Please verify the task object you are passing and try again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $sw = [diagnostics.stopwatch]::StartNew()

        Try
        {

            $taskObj = Send-HPOVRequest -uri $_uri -HostName $ApplianceConnection.name

        }
        
        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }
        
        $i = 0

        if ($resourceName) 
        { 
            
            $taskname = "Waiting for '{0} {1}' task to start" -f $taskObj.name, $resourceName
        
        }

        else 
        { 
            
            $taskName = "Waiting for '{0}' task to start" -f $taskObj.name
        
        }

        "[{0}] $taskName" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
        { 
            
            "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        while ($taskObj.taskState -ieq "Adding" -or
               $taskObj.taskState -ieq "New" -or
               $taskObj.taskState -ieq "Starting") 
        {

            Try
            {

                $taskObj = Send-HPOVRequest -Uri $taskObj.uri -Hostname $taskObj.ApplianceConnection.Name

            }

            Catch
            {
            
                $PSCmdlet.ThrowTerminatingError($_)
            
            }
            
            if ($sw.Elapsed -gt $timeout) 
            {
                
                $ErrorRecord = New-ErrorRecord InvalidOperationException TaskWaitExceededTimeout OperationTimeout  'Wait-HPOVTaskStart' -Message "The time-out period expired before waiting for task '$taskName' to start." #-verbos
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            # Display Progress Bar

            # Display the task status
            if ($taskObject.taskStatus)
            {

                $progressStatus = $taskObject.taskStatus

            }
                        
            elseif ($taskObject.taskState)
            {

                $progressStatus = $taskObject.taskState

            }

            else
            {

                $progressStatus = "Waiting $($taskObject.Name)"

            }

            if ($taskObj.expectedDuration) 
            {

                $percentComplete = ($i / $taskObj.expectedDuration * 100)

            }

            else
            {

                $percentComplete = $taskObj.percentComplete 

            }
            
            # Handle the call from -Verbose so Write-Progress does not get borked on display.
            if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
            { 
                
                "[{0}] Task Status: '$taskName' $progressStatus $($percentComplete)% Complete" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }
             
            else 
            {

                Write-Progress -activity $taskName -status $progressStatus -percentComplete $percentComplete
                
            }

            Start-Sleep 1

            $i++

        }

        Write-Progress -activity $taskName -Completed

        $taskObj

    }

    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Wait-HPOVTaskComplete 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (ValueFromPipeline, Mandatory)]
        [Alias ('TaskUri','Task')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false)]
        [timespan]$Timeout = $DefaultTimeout,

        [Parameter (Mandatory = $false)]
        [Switch]$ApplianceWillReboot,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {
        
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['InputObject']) 
        { 
            
            $PipelineInput = $True 
        
        }
        
        # Task isn't provided by pipeline, but check for ApplianceConnection property
        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $TaskCollection          = [System.Collections.ArrayList]::new()
        $FinishedTasksCollection = [System.Collections.ArrayList]::new()
        $_TaskIds                = [System.Collections.ArrayList]::new()

        $i = 1

    }

    Process 
    {

        if ($PipelineInput) 
        { 
            
            "[{0}] Task resource passed via pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
        }

        # Validate the task object
        ForEach ($_task in $InputObject)
        {

            "[{0}] Processing task resources." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (($_task -is [String]) -and ($_task.StartsWith($TasksUri))) 
            {

                "[{0}] Task is URI $($_task)"-f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Use to track -ID in Write-Progress
                $_task = [PSCustomObject]@{
                    id                  = $i; 
                    uri                 = $_task; 
                    taskState           = $Null; 
                    ApplianceConnection = $ApplianceConnection 
                }

            }

            elseif ($_task -is [PSCustomObject] -and $_task.category -ieq 'tasks')
            {

                "[{0}] Task is $($_task.GetType()). Task URI: $($_task.uri)"-f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                # Use to track -ID in Write-Progress
                $_task | Add-Member -NotePropertyName id -NotePropertyValue $i -force
                
            }

            else 
            {

                $ExceptionMessage = "Invalid task object provided. Please verify the task object you are passing and try again."
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument $_task -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            [void]$TaskCollection.Add($_task)
            [void]$_TaskIds.Add($i)

            $i++
            
        }

    }

    End
    {

        $_taskCollection = $TaskCollection.Clone()        

        # Start Stopwatch
        $sw = [diagnostics.stopwatch]::StartNew()

        while ($_taskCollection.Count -gt 0 -and $sw.Elapsed -lt $timeout)
        {

            "[{0}] Processing taskcollection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($sw.Elapsed -gt $timeout) 
            {

                # Tear down Write-Progress
                $_taskCollection | ForEach-Object { Write-Progress -id $_.id -Activity $_.Activity -Completed }

                # Return 'finished' collection to caller then display error
                if ($_taskCollection.Count -gt 0)
                {

                    $_taskCollection

                }
                
                if ($FinishedTasksCollection.Count -gt 0)
                {

                    $FinishedTasksCollection

                }

                # UPDATE ERROR MESSAGE to state timeout waiting for tasks to complete
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.TaskResourceException TaskWaitExceededTimeout OperationTimeout  'Wait-HPOVTaskComplete' -Message "The time-out period expired before waiting for task '$taskName' to start." #-verbos
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            $_t = 1

            ForEach ($_task in $_taskCollection)
            {

                # Get task object from API
                Try
                {

                    "[{0}] Getting task object from API." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_taskObj = Send-HPOVRequest $_task.uri -Hostname $_task.ApplianceConnection.Name

                }

                Catch
                {

                    if ($ApplianceWillReboot.IsPresent -and $_taskObj.progressUpdates.statusUpdate -match 'Rebooting')
                    {

                        Write-Host "`r`n"
                        Write-Warning "Appliance is rebooting..."

                        # Sleep for 30 seconds so the web service isn't available, and should trigger Wait-HPOVApplianceStart
                        Start-Sleep -Seconds 30 

                    }

                    else
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

                $Activity = '{0} {1}' -f $_taskObj.name, $_taskObj.associatedResource.resourceName
            
                # Task is in a finished state
                if ($TaskFinishedStatesEnum -contains $_taskObj.taskState)
                {

                    "[{0}] Task is finished, removing from collection." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                      
                    "[{0}] Task Collection size: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $TaskCollection.count | Write-Verbose

                    # Remove task object from base arraylist
                    [void]$TaskCollection.Remove($_task)

                    "[{0}] Updated Task Collection size: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $TaskCollection.count | Write-Verbose

                    # Add Task Object from API to return back to caller
                    [void]$FinishedTasksCollection.Add($_taskObj)

                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    {
                        
                        "[{0}] {1} [{2}{3}] Task finished. " -f $MyInvocation.InvocationName.ToString().ToUpper(), $_taskObj.name, $_taskObj.ApplianceConnection.Name, $_taskObj.uri | Write-Verbose
                    
                    }

                    else 
                    {
                    
                        Write-Progress -id $_task.id -activity $Activity -Completed
                    
                    }

                }

                # Display Progress Bar
                else
                {

                    # Check for running associated tasks for -CurrentOperation status messages
                    Try
                    {

                        $AssociatedChildTasksInexUri = "{0}?sort=created:desc&start=0&category=tasks&query=parentTaskUri:'{1}' AND state:'Running'" -f $IndexUri, $_taskObj.uri

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    $CurrentOperation = $null

                    # Handle the call from -Verbose so Write-Progress does not get borked on display.
                    if ($PSBoundParameters['Verbose'] -or $VerbosePreference -eq 'Continue') 
                    { 
                        
                        "[{0}] Skipping Write-Progress display." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                        "[{0}] CMDLET Task Track ID: {1}`nTask Object Name: {2}`nAssociated Resource Name: {3}`nPrecent Complete: {4}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_task.id, $_taskObj.name,$_taskObj.associatedResource.resourceName,$_taskObj.percentComplete | Write-Verbose
                    
                        If ($_taskObj.progressUpdates[-1].statusUpdate)
                        {

                            "[{0}] Child tasks - Child task: {1} ParentId: {2} {3} ({4})" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_task.id + 100), $_task.id, $_taskObj.progressUpdates[-1].statusUpdate, $_taskObj.taskStatus | Write-Verbose

                        }

                        if ($CurrentOperation)
                        {

                            "[{0}] Current operation: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $CurrentOperation | Write-Verbose

                        }

                    }
                    
                    else 
                    {

                        # Display the task status, and associated child tasks
                        if ($_taskObj.progressUpdates.count -gt 0) 
                        { 

                            # StatusUpdate contains an embedded JSON object as a string.
                            if ($_taskObj.progressUpdates[-1].statusUpdate -match '{')
                            {

                                $ChildTaskMessage = $_taskObj.progressUpdates[-1].statusUpdate.Substring($_taskObj.progressUpdates[-1].statusUpdate.IndexOf('{'), ($_taskObj.progressUpdates[-1].statusUpdate.IndexOf('}') - $_taskObj.progressUpdates[-1].statusUpdate.IndexOf('{') + 1)) | ConvertFrom-Json
                                $StatusMessage  = '{0}{1}' -f $_taskObj.progressUpdates[-1].statusUpdate.Substring(0, $_taskObj.progressUpdates[-1].statusUpdate.IndexOf('{')), $ChildTaskMessage.name

                            }

                            else
                            {

                                $StatusMessage  = '{0}' -f $_taskObj.progressUpdates[-1].statusUpdate

                            }    

                            if ($null -eq $StatusMessage -or [System.String]::IsNullOrWhiteSpace($StatusMessage))
                            {

                                $StatusMessage = $_taskObj.taskState

                            }    

                            # Child task is executing, display reported status
                            # Need to add child task object to trask tracker so to remove them when finished from Write-Progress nested view
                            If ($_taskObj.progressUpdates[-1].statusUpdate) 
                            {

                                if ($_TaskIds -notcontains ($_task.id + 100))
                                {

                                    [void]$_TaskIds.Add($_task.id + 100)

                                }

                                $ChildTaskStatus = '{0} {1}' -f $_taskObj.name, $_taskObj.associatedResource.resourceName

                                Write-Progress -id ($_task.id + 100) -ParentId $_task.id -activity $ChildTaskStatus -status $StatusMessage -CurrentOperation $CurrentOperation -percentComplete $_taskObj.computedPercentComplete
                            
                            }

                            # There is a child task, but it's statusUpdate value is NULL, so just display the parent task status
                            else 
                            {
                            
                                if ($_taskObj.taskStatus)
                                {

                                    $progressStatus = $_taskObj.taskStatus

                                }
                                
                                else
                                {

                                    $progressStatus = $_taskObj.taskState

                                }

                                Write-Progress -Activity $Activity -Status $StatusMessage -CurrentOperation $CurrentOperation -percentComplete $_taskObj.percentComplete
                            
                            }

                        }

                        #Just display the task status, as it has no child tasks
                        elseif ($_taskObj.taskStatus) 
                        {
                            
                            Write-Progress -activity $Activity -status $_taskObj.taskStatus -CurrentOperation $CurrentOperation -percentComplete $_taskObj.percentComplete 
                        
                        }
                        
                        else 
                        {
                            
                            Write-Progress -activity $Activity -status $_taskObj.taskState -CurrentOperation $CurrentOperation -percentComplete $_taskObj.percentComplete 
                        
                        }

                    }
                    
                }
                
                if ($_t -ge $_taskCollection.count)
                {

                    Start-Sleep -seconds 2
                    $_t = 1 # Reset counter

                }

                else
                {

                    $_t++

                }

            }

            # Reclone $_taskCollection object to update array with current task ArrayList
            $_taskCollection = $TaskCollection.Clone()

        }

        # Tear down any remaining Write-Progress displays before returning back to the user
        $_TaskIds | ForEach-Object { Write-Progress -id $_ -Activity "Completed" -Completed }

        Return $FinishedTasksCollection

    }

}

#######################################################
# Securty and LDAP functions
#

function Get-HPOVUser 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [Alias ('Username')]
        [ValidateNotNullorEmpty()]
        [String]$Name,
        
        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )
    
    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }    
        
        $_UserCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_Query = [System.Collections.ArrayList]::new()

            $_Category = "category=users&"

            if ($Name)
            {

                if ($Name.Contains('*'))
                {

                    [Void]$_Query.Add(("user_name%3A{0}" -f $Name.Replace(" ","?").Replace("*", "%2A")))

                }

                else
                {

                    [Void]$_Query.Add(("user_name:'{0}'" -f $Name))

                }                
                
            }

            # Build the final URI
            $_uri = '{0}?{1}sort=name:asc&query={2}' -f $IndexUri, $_Category.ToString(), [String]::Join(' AND ', $_Query.ToArray())

            Try
            {

                $_users = Get-AllIndexResources -Uri $_uri -ApplianceConnection $_appliance

                if ($_users.count -eq 0 -and $Name) 
                {
                
                    $_Message    = "Username '{0}' was not found on {1} Appliance Connection. Please check the spelling, or create the user and try again." -f $Name, $_appliance.Name 
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.UserResourceException UserNotFound ObjectNotFound "Name" -Message $_Message
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }

            # User isn't authorized, so let's display their user account
            Catch [HPOneView.Appliance.AuthPrivilegeException]
            {

                Try
                {

                    $_user = Send-HPOVRequest ($ApplianceUserAccountsUri + '/' + $_appliance.Username) -Hostname $_appliance.Name 

                    $_user.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.User')

                    [void]$_UserCollection.Add($_user)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] Found {1} user resources on '{2}' appliance." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_users.count, $_appliance.Name | Write-Verbose

            if ($_users)
            {

                ForEach ($u in $_users) 
                {

                    $u.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.User')

                    [void]$_UserCollection.Add($u)

                }

            }
            
        }

    }

    End 
    {

        "Done. {0} user(s) found." -f $_UserCollection.count | Write-Verbose 
        
        Return $_UserCollection    

    }

}

function New-HPOVUser 
{
     
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$UserName, 

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Password, 

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$FullName, 

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Array]$Roles = @(),
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Array]$ScopePermissions,    

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [validatescript({$_ -as [Net.Mail.MailAddress]})]
        [String]$EmailAddress,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')] 
        [ValidateNotNullOrEmpty()]
        [String]$OfficePhone,
     
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$MobilePhone,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Enabled,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {


        if ($PSBoundParameters['Enabled'])
        {

            Write-Warning 'The -Enabled Parameter is now deprecated. By default, all new user accounts will be enabled. In order to disable a user account, use the Set-HPOVUser Cmdlet.'

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
        $_UserStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            "[{0}] Validating requested role values" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $_unsupportedRoles = [System.Collections.ArrayList]::new()
            $_NewUserRoles     = [System.Collections.ArrayList]::new()

            $_user = NewObject -UserAccount

            $_user.userName     = $userName
            $_user.fullName     = $fullName
            $_user.password     = $password
            $_user.emailAddress = $emailAddress
            $_user.officePhone  = $officePhone 
            $_user.mobilePhone  = $mobilePhone
            $_user.enabled      = $true

            # Validate roles provided are allowed.
            if ($PSBoundParameters['Roles'])
            {
                foreach ($_role in $Roles) 
                {
    
                    "[{0}] Processing role: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_role | Write-Verbose
    
                    if (-not ((${Global:ConnectedSessions} | Where-Object Name -EQ $_appliance.Name).ApplianceSecurityRoles -contains $_role)) 
                    { 
                    
                        "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                        [void]$_unsupportedRoles.Add($_role)
                
                    }

                    else
                    {

                        "[{0}] Supported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_TempName = $_role.split(' ')

                        $_NewPermission = NewObject -DirectoryGroupPermissions

                        $_UpdatedName = New-Object System.Text.StringBuilder

                        for ($s = 0; $s -lt $_TempName.count; $s++) 
                        {

                            if ($s -eq 0) 
                            { 
                                
                                [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                            
                            }

                            else 
                            {

                                [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                            
                            }

                        }

                        $_NewPermission.roleName = $_UpdatedName.ToString()

                        [void]$_user.permissions.Add($_NewPermission)

                    }
    
                }
    
                if ($_unsupportedRoles.count -ge 1) 
                { 
            
                    $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedRolesFound InvalidArgument $($MyInvocation.InvocationName.ToString().ToUpper()) -Message "The '$($_unsupportedRoles -join ", ")' role(s) is/are not supported or the correct names. Please validate the -roles Parameter contains one or more valid roles. Allowed roles are: $((${Global:ConnectedSessions} | ? Name -EQ $_appliance.Name).ApplianceSecurityRoles -join ", ")"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)            
                
                }

            }

            # Process scopes with permissions
            if ($PSBoundParameters['ScopePermissions'])
            {

                ForEach ($_ScopeToPermission in $ScopePermissions)
                {

                    "[{0}] Processing role: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Role | Write-Verbose
                    
                    if ((${Global:ConnectedSessions} | Where-Object Name -EQ $ApplianceConnection.Name).ApplianceSecurityRoles -notcontains $_ScopeToPermission.Role)
                    { 
                    
                        "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_unsupportedRoles.Add($_ScopeToPermission.Role)

                    }

                    else
                    {

                        "[{0}] Supported role." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ([System.String]::IsNullOrWhiteSpace($_ScopeToPermission.Scope))
                        {

                            Throw "Scope property within ScopePermissions must contain at least 1 entry."

                        }

                        $_TempName = $_ScopeToPermission.Role.split(' ')

                        "[{0}] Process scope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] Scope object type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Scope.GetType().Fullname | Write-Verbose
                        "[{0}] Scope object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Scope | Write-Verbose

                        if ($_ScopeToPermission.Scope -IsNot [HPOneView.Appliance.ScopeCollection] -and $_ScopeToPermission.Scope -ne 'All')
                        {

                            Throw ("Invalid scope resource {0}" -f $_ScopeToPermission.Name)

                        }

                        elseif ($_ScopeToPermission.Scope -eq 'All')
                        {

                            "[{0}] Scope is not an HPOneView.Appliance.ScopeCollection resource, but String 'All'. Will set uri to null." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $_Scope = [PSCustomObject]@{uri = $null}

                        }

                        else
                        {

                            $_Scope = $_ScopeToPermission.Scope

                        }
                        
                        $_NewPermission = NewObject -DirectoryGroupPermissions

                        $_UpdatedName = New-Object System.Text.StringBuilder

                        for ($s = 0; $s -lt $_tempname.count; $s++) 
                        {

                            if ($s -eq 0) 
                            { 
                                
                                [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                            
                            }

                            else 
                            {

                                [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                            
                            }

                        }
                        
                        "[{0}] Adding Role '{1}' -> '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_UpdatedName.ToString(), $_Scope.uri | Write-Verbose

                        $_NewPermission.roleName = $_UpdatedName.ToString()
                        $_NewPermission.scopeUri = $_Scope.uri

                        [void]$_user.permissions.Add($_NewPermission)                    

                    }

                }                

            }            

            "[{0}] Sending request to create user: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_user.userName | Write-Verbose
        
            Try
            {

                $_resp = Send-HPOVRequest -Uri $ApplianceUserAccountsUri -Method POST -Body $_user -Hostname $_appliance

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.User')

            $_resp

        }

    }

    End
    {
        
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVUser 
{
     
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'default')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [Object]$UserObject,

        [Parameter (Mandatory, ParameterSetName = 'default')]
        [ValidateNotNullorEmpty()]
        [String]$UserName, 

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [String]$Password, 

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [String]$FullName, 

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [Array]$Roles, 

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [Array]$ScopePermissions,

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [validatescript({$_ -as [Net.Mail.MailAddress]})]
        [String]$EmailAddress,

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')] 
        [ValidateNotNullorEmpty()]
        [String]$OfficePhone,
     
        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [ValidateNotNullorEmpty()]
        [String]$MobilePhone,
     
        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [Alias ('enable')]
        [ValidateNotNullorEmpty()]
        [Switch]$Enabled,

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Pipeline')]
        [Alias ('disable')]
        [ValidateNotNullorEmpty()]
        [Switch]$Disabled,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Pipeline')]
        [Alias ('Appliance')]
        [ValidateNotNullorEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # No need to validate ApplianceConnection, as object is passed via pipeline.
        if ($PSCmdlet.ParameterSetName -eq 'Pipeline')
        {

            "[{0}] Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {


                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
                        
        }

        $_UsersToUpdate = [System.Collections.ArrayList]::new()
        $_UserStatus    = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput)
        {

            # Validate pipeline input is user object
            if (-not($UserObject -is [PSCustomObject]) -and -not($UserObject.category -eq 'users'))
            {

                "[{0}] Invalid UserObject provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.UserResourceException InvalidUserObject InvalidArgument "UserObject" -TargetType 'PSObject' -Message "The UserObject Parameter value is not a valid User object resource. Object category provided '$($UserObject.category)', allowed object category value 'users'. Please verify the input object and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Adding UserObject to Process collection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $UserObject.Username | Write-Verbose

            [void]$_UsersToUpdate.Add($UserObject)

        }

        else
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                try 
                { 
                    
                    $_UserObject = Get-HPOVUser -Name $userName -ApplianceConnection $_appliance
                
                }
        
                # If not found, throw error
                catch [HPOneView.Appliance.UserResourceException]
                {
                
                    # Generate terminating error
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.UserResourceException UserNotFound ObjectNotFound 'UserName' -Message "Username `'$userName`' was not found. Please check the spelling, or create the user and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                [void]$_UsersToUpdate.Add($_UserObject)

            }

        }

    }

    End
    {

        ForEach ($_User in $_UsersToUpdate)
        {

            "[{0}] Processing User: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_User.userName | Write-Verbose

            if ($PSBoundParameters['Roles'] -or $PSBoundParameters['ScopePermissions'])
            {

                $_user.permissions = [System.Collections.ArrayList]::new()

            }

            switch ($PSBoundParameters.keys) 
            {

                "Password" 
                { 

                    if ($_User.userName -eq (${Global:ConnectedSessions} | Where-Object Name -eq $_User.ApplianceConnection.Name).UserName) 
                    {

                        write-warning "This CMDLET will not modify the password for your account. Please use the Set-HPOVUserPassword CMDLET to update your user account password. Password update will not be Processed."

                    }  
                                  
                    else 
                    { 
                        
                        $_User | Add-Member -NotePropertyName password -NotePropertyValue $Password -force
                        
                    } 
                
                }

                "fullName" 
                { 
                    
                    $_User.fullName = $FullName
                
                }

                "roles" 
                {

                    if ($_User.userName -eq (${Global:ConnectedSessions} | Where-Object Name -eq $_User.ApplianceConnection.Name).UserName) 
                    {

                        write-warning "Unable to modify roles for your account, as you must be authenticated to the appliance with a different administrator account. Roles will not be Processed."

                    }

                    else 
                    {
                    
                        $_User | add-member -NotePropertyName replaceRoles -NotePropertyValue $True -force

                        # Validate roles provided are allowed.
                        $_unsupportedRoles = [System.Collections.ArrayList]::new()
                        $_NewUserRoles     = [System.Collections.ArrayList]::new()

                        # Validate roles provided are allowed.
                        foreach ($_role in $Roles) 
                        {
            
                            "[{0}] Processing role: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_role | Write-Verbose
            
                            if (-not ((${Global:ConnectedSessions} | Where-Object Name -EQ $_User.ApplianceConnection.Name).ApplianceSecurityRoles -contains $_role)) 
                            { 
                            
                                "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
                                [void]$_unsupportedRoles.Add($_role)
                        
                            }

                            else
                            {

                                "[{0}] Supported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                                $_TempName = $_role.split(' ')

                                $_NewPermission = NewObject -DirectoryGroupPermissions

                                $_UpdatedName = New-Object System.Text.StringBuilder

                                for ($s = 0; $s -lt $_TempName.count; $s++) 
                                {

                                    if ($s -eq 0) 
                                    { 
                                        
                                        [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                                    
                                    }

                                    else 
                                    {

                                        [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                                    
                                    }

                                }

                                $_NewPermission.roleName = $_UpdatedName.ToString()

                                [void]$_user.permissions.Add($_NewPermission)

                            }
            
                        }
            
                        if ($_unsupportedRoles.count -ge 1) 
                        { 
                    
                            $ExceptionMessage = "The '{0}' role(s) is/are not supported or the correct names. Please validate the -roles Parameter contains one or more valid roles. Allowed roles are: {1}" -f [String]::Join(', ', $_unsupportedRoles.ToArray()), [String]::Join(', ', (${Global:ConnectedSessions} | Where-Object Name -EQ $_User.ApplianceConnection.Name).ApplianceSecurityRoles.ToArray())
                            $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedRolesFound InvalidArgument 'Roles' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)            
                        
                        }

                    }

                }            

                # Process scopes with permissions
                'ScopePermissions'
                {

                    $_User | add-member -NotePropertyName replaceRoles -NotePropertyValue $True -force

                    ForEach ($_ScopeToPermission in $ScopePermissions)
                    {

                        "[{0}] Processing role: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Role | Write-Verbose
                        
                        if ((${Global:ConnectedSessions} | Where-Object Name -EQ $_user.ApplianceConnection.Name).ApplianceSecurityRoles -notcontains $_ScopeToPermission.Role)
                        { 
                        
                            "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            [void]$_unsupportedRoles.Add($_ScopeToPermission.Role)

                        }

                        else
                        {

                            "[{0}] Supported role." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            if ([System.String]::IsNullOrWhiteSpace($_ScopeToPermission.Scope))
                            {

                                Throw "Scope property within ScopePermissions must contain at least 1 entry."

                            }

                            $_TempName = $_ScopeToPermission.Role.split(' ')

                            "[{0}] Process scope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                            "[{0}] Scope object type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Scope.GetType().Fullname | Write-Verbose
                            "[{0}] Scope object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Scope | Write-Verbose

                            if ($_ScopeToPermission.Scope -IsNot [HPOneView.Appliance.ScopeCollection] -and $_ScopeToPermission.Scope -ne 'All')
                            {

                                Throw ("Invalid scope resource {0}" -f $_ScopeToPermission.Name)

                            }

                            elseif ($_ScopeToPermission.Scope -eq 'All')
                            {

                                "[{0}] Scope is not an HPOneView.Appliance.ScopeCollection resource, but String 'All'. Will set uri to null." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                                $_Scope = [PSCustomObject]@{uri = $null}

                            }

                            else
                            {

                                $_Scope = $_ScopeToPermission.Scope

                            }
                            
                            $_NewPermission = NewObject -DirectoryGroupPermissions

                            $_UpdatedName = New-Object System.Text.StringBuilder

                            for ($s = 0; $s -lt $_tempname.count; $s++) 
                            {

                                if ($s -eq 0) 
                                { 
                                    
                                    [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                                
                                }

                                else 
                                {

                                    [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                                
                                }

                            }
                            
                            "[{0}] Adding Role '{1}' -> '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_UpdatedName.ToString(), $_Scope.uri | Write-Verbose

                            $_NewPermission.roleName = $_UpdatedName.ToString()
                            $_NewPermission.scopeUri = $_Scope.uri

                            [void]$_user.permissions.Add($_NewPermission)                    

                        }

                    }                

                }    

                "emailAddress" 
                { 
                    
                    $_User.emailAddress = $EmailAddress
                
                }

                "officePhone" 
                { 
                    
                    $_User.officePhone = $OfficePhone
                
                }

                "mobilePhone" 
                { 
                    
                    $_User.mobilePhone = $MobilePhone
                
                }

                "enabled" 
                { 
                
                    if ($_User.userName -eq (${Global:ConnectedSessions} | Where-Object Name -eq $_User.ApplianceConnection.Name).UserName) 
                    {

                        write-warning "This CMDLET will not modify the state for your account. Please authenticate to the appliance with a different administrator account. Account state will not be Processed."

                    }

                    else 
                    { 
                        
                        $_User.enabled = $true
                    
                    }

                }

                "disabled" 
                { 

                    if ($_User.userName -eq (${Global:ConnectedSessions} | Where-Object Name -eq $_User.ApplianceConnection.Name).UserName) 
                    {

                        write-warning "This CMDLET will not modify the state for your account. Please authenticate to the appliance with a different administrator account. Account state will not be Processed."

                    }

                    else 
                    { 
                        
                        $_User.enabled = $false

                    }

                }

            }

            "[{0}] Sending request to update `'$($_User.userName)`' user at '$ApplianceUserAccountsUri'" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest $ApplianceUserAccountsUri PUT $_User -Hostname $_User.ApplianceConnection.Name

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.User')

            [void]$_UserStatus.Add($_resp)

        }
        
        Return $_UserStatus

    }

}

function Set-HPOVUserPassword 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('CurrentPassword')]
        [String]$Current,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Alias ('NewPassword')]
        [String]$New,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Prompt user for current password if not provided
        if (-not($PSBoundParameters['Current'])) 
        { 
        
            $Current                  = Read-Host -AsSecureString "Current"
            $_decryptCurrentPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Current))

        }

        else 
        { 
            
            $_decryptCurrentPassword = $Current 
        
        }

        # Prompt user for new password if not provided
        if (-not($PSBoundParameters['New'])) 
        { 
        
            Do 
            {

                $New                 = Read-Host -AsSecureString "New"
                $_CompareNewPassword = Read-Host -AsSecureString "Re-type New"
                
                # Compare provided password matches
                $_decryptNewPassword        = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($New))
                $_decryptcompareNewPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($_CompareNewPassword))

                if (-not ($_decryptNewPassword -eq $_decryptcompareNewPassword))
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.PasswordMismatchException NewPasswordsDoNotMatch InvalidResult 'New' -Message "The new password values do not match. Please check the value and try again."
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                if (-not ($_decryptNewPassword.length -ge 8) -or -not ($_decryptcompareNewPassword -ge 8)) 
                {
                
                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.PasswordMismatchException NewPasswordLengthTooShort InvalidResult 'New' -Message "The new password value do not meet the minimum character length of 8 characters. Please try again."
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            } Until ($_decryptNewPassword -eq $_decryptcompareNewPassword -and $_decryptNewPassword.length -ge 8)

        }

        else 
        {

            $_decryptNewPassword = $New

        }

        $_UserStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($_appliance.AuthLoginDomain -ne 'LOCAL')
            {

                $_message     = "The user account Auth Provider, {0}, is not the local appliance. HPE OneView does not support updating an LDAP User Account password." -f $_appliance.AuthLoginDomain
                $_errorrecord = New-ErrorRecord HPOneView.Appliance.UserResourceException UserNotFound ObjectNotFound 'UserName' -Message $_message
                $PSCmdlet.WriteError($_errorrecord)

            }

            else
            {

                $_UpdatePassword                 = NewObject -UpdateUserPassword
                $_UpdatePassword.currentPassword = $_decryptCurrentPassword
                $_UpdatePassword.password        = $_decryptNewPassword
                $_UpdatePassword.userName        = $_appliance.UserName

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $ApplianceUserAccountsUri -Method PUT -Body $_UpdatePassword -Hostname $_appliance

                    if ($_resp.category -eq 'users')
                    {

                        $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.User')

                    }

                    [void]$_UserStatus.Add($_resp)

                }
                
                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }     

    }

    End 
    {

        Return $_UserStatus

    }

}

function Remove-HPOVUser 
{
     
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("u","user",'UserName', 'Name')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Name'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
        $_UserCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] User Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Format-List * | Out-String) | Write-Verbose

            If ('users' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "User:$($InputObject.Name)" -TargetType PSObject -Message "The User object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_UserCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "User:$($InputObject.Name)" -TargetType PSObject -Message "The User object resource is not an expected category type [$($InputObject.category)]. The allowed resource category type is 'users'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                "[{0}] Processing User Name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject| Write-Verbose

                Try
                {

                    $_User = Get-HPOVUser $InputObject -ApplianceConnection $_appliance

                    $_User | ForEach-Object {

                        [void]$_UserCollection.Add($_)

                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

    }

    End
    {

        "[{0}] Processing {1} User object resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_UserCollection.count | Write-Verbose

        # Process User Resources
        ForEach ($_user in $_UserCollection)
        {

            if ($PSCmdlet.ShouldProcess($_user.ApplianceConnection, ("Remove User '{0}' from appliance") -f $_user.userName)) 
            {

                "[{0}] Removing User '{1}' from appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_user.userName, $_user.ApplianceConnection | Write-Verbose

                $_ETag = '*'

                if ($null -ne $_user.eTag)
                {

                    $_ETag = $_user.eTag

                }

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $_user.Uri -Method DELETE -AddHeader @{'If-Match' = $_ETag} -Hostname $_user.ApplianceConnection.Name

                    $_resp | Add-Member -NotePropertyName userName -NotePropertyValue $_user.userName

                    $_resp

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

}

function Show-HPOVUserSession 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param ()

    Begin 
    {
    
        Write-Warning "This CMDLET has been deprecated. Please use the $ConnectedSessions Global variable for appliance session information."
    
    }

    Process { }

    End { }

}

function Get-HPOVRole 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param()
    
    Begin 
    {

        Write-Warning "This CMDLET is now deprecated. Please use the Get-HPOVUser CMDLET to retrieve the user account and associated Roles."

    }

}

function Set-HPOVUserRole 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias ("user",'userName')]
        [Object]$Name,

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Alias ('roleName')]
        [Array]$Roles,

        [Parameter (ValueFromPipelineByPropertyName, Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        Write-Warning "This CMDLET is now deprecated. Please use the Set-HPOVUser CMDLET to modify user accounts and associated roles/permissions."

    }

}

function Set-HPOVInitialPassword  
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$OldPassword,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$NewPassword,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$Appliance

    )

    Begin 
    { 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # Check to see if a connection to the appliance exists
        if ($Appliance -is [String])
        {

            if (-not(${Global:ConnectedSessions}.Name -contains $Appliance) -and (-not(${Global:ConnectedSessions} | Where-Object Name -eq $Appliance).SessionID))
            {

                "[{0}] Appliance Session not found. Running FTS sequence?" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Creating temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [HPOneView.Appliance.Connection]$Appliance = New-Object HPOneView.Appliance.Connection(99, $Appliance)

                $Appliance.SessionID    = 'TemporaryConnection'

                [void]${Global:ConnectedSessions}.Add($_Appliance)
            
            }

            elseif (${Global:ConnectedSessions}.Name -contains $Appliance)
            {

                "[{0}] Appliance is a string value, lookup connection in global tracker." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [HPOneView.Appliance.Connection]$Appliance = ${Global:ConnectedSessions} | Where-Object Name -eq $Appliance

                "[{0}] Found connection in global tracker: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

            }

        }        

        elseif ($Appliance -is [HPOneView.Appliance.Connection])
        {

            "[{0}] Appliance is a Connection: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($Appliance | Out-String) | Write-Verbose

        }

        else
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException UnknownCondition InvalidOperation "Appliance" -Message "An unknown condition has ocurred."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        if ($OldPassword -is [SecureString])
        {

            $OldPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($OldPassword))

        }

        if ($NewPassword -is [SecureString])
        {

            $NewPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($NewPassword))

        }
    
    }

    Process 
    {
        
        $body = [PSCustomObject]@{
            
            userName    = 'Administrator'; 
            oldPassword = $OldPassword; 
            newPassword = $NewPassword
        
        }

        $uri  = $ApplianceUserAccountsUri + "/changePassword"

        Try
        {

            $resp = Send-HPOVRequest -Uri $uri -Method POST -BOdy $body -Hostname $Appliance

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        finally
        {

            # Remove Temporary appliance connection
            if ((${Global:ConnectedSessions} | Where-Object Name -eq $Appliance.Name).SessionID -eq 'TemporaryConnection')
            {

                "[{0}] Removing temporary Session object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ConnectedSessions.RemoveConnection($Appliance)

            }

        }

    }

    End 
    {

        return $resp

    }

}

function Get-HPOVApplianceTrustedCertificate
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Resource')]
        [Object]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Alias ("CASOnly")]
        [Switch]$CertificateAuthoritiesOnly,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Resource')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_CertCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        $_uri = '{0}?category=certificates&count=10000&query=({1})'

        $_Query = New-Object 'System.Collections.Generic.List[String]'

        $_Query.Add("(NOT cert_type:STANDARD_ROOT)")

        $_Name = $null

        if ($PSBoundParameters['Name'])
        {

            $_Query.Add('((cert_aliasName:/.*{0}.*/) OR (cert_altNames:/.*{0}.*/))' -f $Name)

            $_Name = $Name

        }

        if ($CertificateAuthoritiesOnly.IsPresent)
        {

            $_Query.Add('(cert_type:INTERMEDIATE OR cert_type:CUSTOM_ROOT)')

        }

        if ($InputObject)
        {

            switch ($InputObject.category)
            {

                'server-hardware'
                {

                    $_Query.Add(('((cert_aliasName:/.*{0}.*/) OR (cert_altNames:/.*{0}.*/) OR (cert_altNames:/.*{1}.*/))' -f $InputObject.uuid, $InputObject.name))

                }

                'enclosures'
                {

                    $_Query.Add(('((cert_aliasName:/.*{0}.*/) OR (cert_altNames:/.*{0}.*/) OR (cert_altNames:/.*{1}.*/))' -f $InputObject.serialNumber, $InputObject.name))

                }

                default
                {

                    $ExceptionMessage = 'The provided resource "{0} ({1})" is unsupported with this Cmdlet. Please provide a Server or Enclosure resource.' -f $InputObject.name, $InputObject.category
                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidInputObjectParameterValue InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            $_Name = $InputObject.name

        }

        $_uri = $_uri -f $IndexUri, [String]::Join(' AND ', $_Query.ToArray())

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_CollectionResults = Send-HPOVRequest -Uri $_uri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_CollectionResults.members)
            {

                Try
                {

                    ForEach ($_certMember in ($_CollectionResults.members | Sort-Object Type))
                    {
                        
                        $_Cert = Send-HPOVRequest -Uri $_certMember.uri -Hostname $_appliance.Name

                        "[{0}] Processing '{1}' ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Cert.certificateDetails.aliasName, $_Cert.uri | Write-Verbose

                        Switch ($_Cert.type)
                        {

                            'CertificateAuthorityInfo'
                            {

                                if ($null -eq $_Cert.certRevocationConfInfo.crlExpiry -and
                                    $null -eq $_Cert.certRevocationConfInfo.crlSize)
                                {

                                    $CertificateRevocationListInfo = New-Object HPOneView.Appliance.TrustedCertificateAuthority+CertificateRevocationListInfo("1/1/1970", 
                                                                                                                                                              "CrlNotFound", 
                                                                                                                                                              $_Cert.certRevocationConfInfo.crlSize)
                                }

                                else
                                {

                                    $CertificateRevocationListInfo = New-Object HPOneView.Appliance.TrustedCertificateAuthority+CertificateRevocationListInfo($_Cert.certRevocationConfInfo.crlExpiry, 
                                                                                                                                                          $_Cert.certRevocationConfInfo.crlConf.crlDpList, 
                                                                                                                                                          $_Cert.certRevocationConfInfo.crlSize)

                                }

                                

                                $_Certificate = New-Object HPOneView.Appliance.TrustedCertificateAuthority($_Cert.certificateDetails.base64Data,
                                                                                                           $_Cert.certificateDetails.aliasName,
                                                                                                           $_Cert.certificateDetails.state,
                                                                                                           $_Cert.created, 
                                                                                                           $_Cert.modified, 
                                                                                                           $_Cert.eTag, 
                                                                                                           $CertificateRevocationListInfo, 
                                                                                                           $_Cert.uri, 
                                                                                                           $_Cert.ApplianceConnection)

                            }

                            'CertificateInfoV2'
                            {

                                $_CertStatus = New-Object HPOneView.Appliance.CertificateStatus($_Cert.certificateStatus.chainStatus, 
                                                                                                $_Cert.certificateStatus.selfsigned, 
                                                                                                $_Cert.certificateStatus.trusted)

                                $_Certificate = New-Object HPOneView.Appliance.TrustedCertificate($_Cert.certificateDetails.base64Data,
                                                                                                  $_Cert.certificateDetails.aliasName,
                                                                                                  $_Cert.certificateDetails.commonName,
                                                                                                  $_Cert.created, 
                                                                                                  $_Cert.modified,
                                                                                                  $_CertStatus,
                                                                                                  $_Cert.eTag, 
                                                                                                  $_Cert.uri, 
                                                                                                  $_Cert.ApplianceConnection)

                            }

                        }
    
                        [void]$_CertCollection.Add($_Certificate)
    
                    }

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

            elseif ($PSBoundParameters['Name'])
            {

                $ExceptionMessage = "The specified '{0}' trusted SSL certificate resource not found on Appliance '{1}'. Please check the name and try again." -f $_Name, $_appliance.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.TrustedCertificateResourceException TrustedCertificateResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

        }

    }

    End
    {

        $_CertCollection | Sort-Object type

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVApplianceTrustedCertificate
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [System.IO.FileInfo]$Path,

        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$CertObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$ComputerName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Int]$Port,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$AliasName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Force,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Async,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }
    
    Process 
    {

        if (-not $Path -and $ComputerName)
        {

            "[{0}] Attempting to retreive SSL certificate from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $ComputerName | Write-Verbose

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                # Attempt to get the server cert using GET /rest/certificates/https/remote/$ComputerName
                Try
                {

                    $_Uri = '{0}{1}' -f $RetrieveHttpsCertRemoteUri, $ComputerName

                    if ($PSBoundParameters['Port'])
                    {

                        $_Uri += ':{0}' -f $Port
                    }

                    $_RemoteHttpsServerCert = Send-HPOVRequest -Uri $_Uri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Add the SSL certificate to the appliance
                $_CertObject = NewObject -ApplianceTrustedSslCertificate
                $_CertObject.aliasName  = $PSBoundParameters['AliasName']
                $_CertObject.base64Data = $_RemoteHttpsServerCert.certificateDetails.base64Data

                $_CertToImportCollection = [PSCustomObject]@{

                    type = 'CertificateInfoV2';
                    certificateDetails = [System.Collections.ArrayList]::new()
                    
                }

                [void]$_CertToImportCollection.certificateDetails.Add($_CertObject)

                $Params = @{
                    Uri      = $ApplianceTrustedSslHostStoreUri;
                    Method   = 'POST';
                    Body     = $_CertToImportCollection;
                    Hostname = $_appliance.Name
                }

                if ($PSBoundParameters['Force'])
                {

                    $Params.Add('AddHeader', @{Forcesaveleaf = $true})

                }

                Try
                {

                    $_Resp = Send-HPOVRequest @Params
                    

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $PSBoundParameters['Async'])
                {

                    $_Resp | Wait-HPOVTaskComplete

                }

                else
                {

                    $_Resp

                }

            }

        }

        elseif ($Path -or $CertObject)
        {

            if ($Path)
            {

                "[{0}] Processing path: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Path.Name | Write-Verbose

                # Validate cert is valid X509 object
                Try
                {

                    $_x509CertObject = New-Object Security.Cryptography.X509Certificates.X509Certificate2($Path)
                    $sb = New-Object System.Text.StringBuilder
                    [void]$sb.Append("-----BEGIN CERTIFICATE-----`n")
                    [void]$sb.Append([System.Convert]::ToBase64String($_x509CertObject.RawData, "InsertLineBreaks"))
                    [void]$sb.Append("`n-----END CERTIFICATE-----`n")
                    
                    $_CertObject = $sb.ToString().Clone()

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($CertObject -is [System.Security.Cryptography.X509Certificates.X509Certificate2])
            {
    
                "[{0}] Processing certificate object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $CertObject.ToString() | Write-Verbose

                # Validate cert is valid X509 object
                Try
                {

                    $_x509CertObject = $CertObject

                    $sb = New-Object System.Text.StringBuilder
                    [void]$sb.Append("-----BEGIN CERTIFICATE-----`n")
                    [void]$sb.Append([System.Convert]::ToBase64String($CertObject.RawData, "InsertLineBreaks"))
                    [void]$sb.Append("`n-----END CERTIFICATE-----`n")
                    
                    $_CertObject = $sb.ToString().Clone()

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            else
            {

                "[{0}] Base64 Cert object provided" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $base64string = $CertObject.Replace("-----BEGIN CERTIFICATE-----`n",$null).Replace("`n-----END CERTIFICATE-----",$null)
                $_CertObject  = $CertObject.Clone()
                $_x509CertObject = New-Object Security.Cryptography.X509Certificates.X509Certificate2(([System.Convert]::FromBase64String($base64string)), $null)

            }            

            # Look at .Extensions | ? { $_.KeyUsages -match 'KeyCertSign' } or EnhancedKeyUsage
            # This is a CA or Issuing Cert Authority
            if ($_x509CertObject.Extensions | Where-Object { $_.KeyUsages -match 'KeyCertSign' })
            {

                "[{0}] Cert is Issuing authority" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_Cert = NewObject -ApplianceTrustedCertAuthority

                if (-not $PSBoundParameters['AliasName'])
                {

                    $AliasName = $_x509CertObject.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::SimpleName,$false)

                }

                $_Cert.certificateDetails.aliasName  = $AliasName
                $_Cert.certificateDetails.base64Data = $_CertObject #-join "`n"

                $_CertToImportCollection = [PSCustomObject]@{

                    type    = 'CertificateAuthorityInfoCollection';
                    members = [System.Collections.ArrayList]::new()
                    
                }

                [void]$_CertToImportCollection.members.Add($_Cert)

                $_Uri = $ApplianceCertificateAuthorityUri.Clone()

            }

            else
            {

                "[{0}] Cert is Server Authentication host" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # Add the SSL certificate to the appliance
                $_Cert = NewObject -ApplianceTrustedSslCertificate
                $_Cert.aliasName  = $PSBoundParameters['AliasName']
                $_Cert.base64Data = $_CertObject -join "`n"

                $_CertToImportCollection = [PSCustomObject]@{

                    type = 'CertificateInfoV2';
                    certificateDetails = [System.Collections.ArrayList]::new()
                    
                }

                [void]$_CertToImportCollection.certificateDetails.Add($_Cert)

                # Throw error that cert does not have the right EnchancedKeyUsage bit set
                if (-not($_x509CertObject.EnhancedKeyUsageList | Where-Object FriendlyName -notmatch "Server Authentication"))
                {
                    
                    # THrow exception

                }

                $_Uri = $ApplianceTrustedSslHostStoreUri.Clone()

            }

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

                $Params = @{
                    Uri      = $_Uri;
                    Method   = 'POST';
                    Body     = $_CertToImportCollection;
                    Hostname = $_appliance.Name
                }

                if ($PSBoundParameters['Force'])
                {

                    $Params.Add('AddHeader', @{Forcesaveleaf = $true})

                }

                Try
                {

                    $_Resp = Send-HPOVRequest @Params
                    
                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $PSBoundParameters['Async'])
                {

                    $_Resp | Wait-HPOVTaskComplete

                }

                else
                {

                    $_Resp

                }

            }

        }
        
    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Update-HPOVApplianceTrustedAuthorityCrl
{
    
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    # [OutputType([System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol]], ParameterSetName = "Default")]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'FilePath')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.TrustedCertificateAuthority[]]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'FilePath')]
        [System.IO.FileInfo]$Path,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'FilePath')]
        [Switch]$Async,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'FilePath')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_GlobalAuthDirectorySettings = [System.Collections.ArrayList]::new()
        
    }

    Process
    {

        if (-not $PSBoundParameters['Path'])
        {

            try 
            { 

                "[{0}] Testing for Proxy settings" -f  $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [Uri]$_ProxyUri = $null

                $_Options = @{Uri = $InputObject.CRLInfo.EndPointList[0]}

                $_filename = Split-Path $InputObject.CRLInfo.EndPointList[0] -Leaf

                $_Proxy = [System.Net.WebRequest]::GetSystemWebProxy()

                $_Proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials

                $_ProxyUri = $_Proxy.GetProxy($_Options.Uri)

                if ($_ProxyUri.OriginalString -ne $_Options.Uri)
                {

                    "[{0}] Using proxy settings" -f  $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Options.Add('Proxy',$_proxyUri)
                    $_Options.Add('ProxyUseDefaultCredentials', $true)
                    
                }

                "[{0}] Invoke-WebRequest Options: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Options | Out-String) | Write-Verbose
                
                Invoke-WebRequest @_Options -OutFile "$env:TEMP\$_filename"    
                
                [System.IO.FileInfo]$Path = "$env:TEMP\$_filename"    

            }

            catch 
            {

                $errorMessage = "$($_[0].exception.message). $($_[0].exception.InnerException.message)"
                $ErrorRecord = New-ErrorRecord HPOneView.Library.UpdateConnectionError InvalidResult ConnectionError 'CheckOnline' -TargetType 'Switch' -Message "$($_[0].exception.message)." -InnerException $_.exception.InnerException
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        Try
        {

            $_Uri = '{0}/crl' -f $InputObject.Uri

            Upload-File -Uri $_Uri -Method PUT -File $Path | Wait-HPOVTaskComplete

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }
    
}

function Remove-HPOVApplianceTrustedCertificate
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false)]
        [Switch]$Async,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process 
    {

        "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        "[{0}] Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject | Write-Verbose

        If ($InputObject -isnot [HPOneView.Appliance.TrustedCertificate] -and $InputObject -isnot [HPOneView.Appliance.TrustedCertificateAuthority])
        {

            $ExceptionMessage = 'The InputObject is not a valid appliance trusted certificate.'
            $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType $InputObject.GetType().Name -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_RemoveMessage = "remove appliance trusted certificate '{0}'" -f $InputObject.Name

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection.Name, $_RemoveMessage)) 
        {

            "[{0}] Removing appliance trusted certificate: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Name, $InputObject.Uri | Write-Verbose

            Try
            {
                
                $_Resp = Send-HPOVRequest -Uri $InputObject.Uri -Method DELETE -AddHeader @{'If-Match' = $InputObject.eTag }  -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $PSBoundParameters['Async'])
            {

                $_Resp | Wait-HPOVTaskComplete

            }

            else
            {

                $_Resp

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {
            
            "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }
        
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVLdap 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='Default')]
    Param 
    (

        [Parameter (Mandatory, ParameterSetName = 'Export')]
        [Alias ('x')]
        [Switch]$Export,

        [Parameter (Mandatory, ParameterSetName = 'Export')]
        [Alias ('location')]
        [ValidateScript ({split-path $_ | Test-Path})]
        [String]$Save,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Export')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_GlobalAuthDirectorySettings = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_AuthDirectoryGlobalSettings = Send-HPOVRequest $authnSettingsUri -Hostname $_appliance.Name
                
                $_AuthDirectoryGlobalSettings | ForEach-Object { $_.psobject.typenames.Insert(0,"HPOneView.Appliance.AuthGlobalDirectoryConfiguration") }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            [void]$_GlobalAuthDirectorySettings.Add($_AuthDirectoryGlobalSettings)

        }
        
    }

    End 
    {

        if ($PSBoundParameters['export'])
        {

            "[{0}] Exporting Global Directory configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($_Directory in $_GlobalAuthDirectorySettings)
            {

                "[{0}] Saving to: $($save)\$($_Directory.ApplianceConnection.Name)_globalSettings.json" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                ConvertTo-Json $_Directory > $save\$($_Directory.ApplianceConnection.Name)_globalSettings.json

            }        

        }

        else
        {
             
            Return $_GlobalAuthDirectorySettings 

        }

    }

}

function Get-HPOVLdapDirectory 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName='Default')]
        [Alias ('directory','domain')]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Export')]
        [Alias ('x')]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$Export,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Export')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_AuthDirectorySettings = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            $Found = [System.Collections.ArrayList]::new()

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_AuthDirectories = Send-HPOVRequest -uri $AuthnProvidersUri -Hostname $_appliance.Name

                If ($PSBoundParameters['Name']) 
                {

                    $_AuthDirectories.members = $_AuthDirectories.members | Where-Object name -like $Name

                }
            
                if ($_AuthDirectories.members)
                {

                    $_AuthDirectories.members | ForEach-Object {

                        $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectory") 
                    
                        [void]$Found.Add($_)

                    }

                }                

                if ($Found.Count -eq 0 -and $PSBoundParameters['Name'])
                {
                    
                    $ExceptionMessage = "The specified '{0}' Authentication Directory resource not found on Appliance '{1}'. Please check the name and try again." -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException AuthDirectoryResourceNotFound ObjectNotFound "Name" -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                $Found | ForEach-Object {

                    $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectory") 
                
                    [void]$_AuthDirectorySettings.Add($_)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {    
    
        # Export directory settings (raw JSON) to file
        if ($PSboundParameters['export'])
        {

            # Loop through each directory and get all configured settings
            ForEach ($_directory in $_AuthDirectorySettings)
            {

                "[{0}] Exporting Directory $($_directory.name) configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_SaveLocation = $Export + "\" + $_directory.ApplianceConnection.Name + "_" + $_directory.name + ".json"

                "[{0}] Saving to: $_SaveLocation" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $_directory                 | Select-Object * -ExcludeProperty credential,created,modified,eTag             
                $_directory.directoryServers | Select-Object * -ExcludeProperty directoryServerCertificateStatus,serverStatus,created,modified,eTag
                $_directory                 | convertto-json > $_SaveLocation
            
            }
        
        }
        
        else
        {
            
            Return $_AuthDirectorySettings

        }

    }

}

function New-HPOVLdapDirectory 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName='AD')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "AD")]
        [Parameter (Mandatory, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = "AD")]
        [Switch]$AD,

        [Parameter (Mandatory, ParameterSetName = "LDAP")]
        [Alias ('LDAP')]
        [Switch]$OpenLDAP,

        [Parameter (Mandatory, ParameterSetName = "AD")]
        [Parameter (Mandatory, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [Alias ('root','rootdn')]
        [String]$BaseDN,

        [Parameter (Mandatory = $false, ParameterSetName = "LDAP")]
        [ValidateSet('CN', 'UID', IgnoreCase = $False)]
        [String]$UserNamingAttribute = 'CN',

        [Parameter (Mandatory, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [Array]$OrganizationalUnits,

        [Parameter (Mandatory, ParameterSetName = "AD")]
        [Parameter (Mandatory, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [Array]$Servers,

        [Parameter (Mandatory = $false, ParameterSetName = "AD")]
        [Parameter (Mandatory = $false, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [Alias ('u','user')]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = "AD")]
        [Parameter (Mandatory = $false, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [Alias ('p','pass')]
        [Object]$Password,

        [Parameter (ValueFromPipeline, Mandatory = $false, ParameterSetName = "AD")]
        [Parameter (ValueFromPipeline, Mandatory = $false, ParameterSetName = "LDAP")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = "AD")]
        [Parameter (Mandatory = $false, ParameterSetName = "LDAP")]
        [Switch]$ServiceAccount,

        [Parameter (Mandatory = $false, ParameterSetName = 'AD')]
        [Parameter (Mandatory = $false, ParameterSetName = 'LDAP')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)
            
        }

        elseif ($Password -is [SecureString])
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSBoundParameters['Password'])
        {

            $_DecryptPassword = $Password

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        else
        {

            $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters.'
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        $_AuthDirectorySettings = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_NewAuthDirectoryObj = NewObject -AuthDirectory
        
            $_NewAuthDirectoryObj.name                = $Name
            $_NewAuthDirectoryObj.baseDN              = $BaseDN
            $_NewAuthDirectoryObj.credential.userName = $Username
            $_NewAuthDirectoryObj.credential.password = $_DecryptPassword

            if ($ServiceAccount)
            {

                "[{0}] Setting provided user credential as Service Account." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_NewAuthDirectoryObj.directoryBindingType = $LdapDirectoryAccountBindTypeEnum['SERVICEACCOUNT']

            }
        
            "[{0}] Validating Server object values" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            ForEach ($_Server in $Servers)
            {

                if ($_Server -is [PSCustomObject] -and $_Server.type -eq 'LoginDomainDirectoryServerInfoDto')
                {

                    $__Server = $_Server.PSObject.Copy()

                    # Process the certificate if included, which means TrustLeafCertificate was used with New-HPOVLdapServer
                    if (-not [System.String]::IsNullOrWhiteSpace($_DirectoryServer.directoryServerCertificateBase64Data))
                    {

                        "[{0}] Adding directory server certificate to appliance trust store" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        # Add the SSL certificate to the appliance
                        $_CertObject = NewObject -ApplianceTrustedSslCertificate
                        $_CertObject.aliasName  = '{0}_{1}' -f $Name, $__Server.directoryServerIpAddress
                        $_CertObject.base64Data = $__Server.directoryServerCertificateBase64Data

                        $_CertToImportCollection = [PSCustomObject]@{

                            type = 'CertificateInfoV2';
                            certificateDetails = [System.Collections.ArrayList]::new()

                        }

                        [void]$_CertToImportCollection.certificateDetails.Add($_CertObject)

                        Try
                        {

                            $Null = Send-HPOVRequest -Uri $ApplianceTrustedSslHostStoreUri -Method POST -Body $_CertToImportCollection -AddHeader @{Forcesaveleaf = $true} -Hostname $_appliance | Wait-HPOVTaskComplete

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingErro($_)

                        }

                        $__Server.directoryServerCertificateBase64Data = $null

                    }

                    [void]$_NewAuthDirectoryObj.directoryServers.Add($__Server)

                }

                else
                {

                    $ExceptionMessage = "The Servers Parameter contains an invalid Server object: {0}. Please correct this value and try again." -f $_Server.name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException InvalidDirectoryServer InvalidArgument 'Servers' -TargetType ($_Server.GetType().Name) -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            if ($PSBoundParameters['OpenLDAP'])
            {

                $_NewAuthDirectoryObj.authProtocol        = 'LDAP'
                $_NewAuthDirectoryObj.userNamingAttribute = $UserNamingAttribute

                ForEach ($_ou in $OrganizationalUnits)
                {

                    if ($_ou.type -match $OrganizationalUnitPattern)
                    {

                        [void]$_NewAuthDirectoryObj.orgUnits.Add($_ou)

                    }

                    else
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException InvalidDirectoryServer InvalidArgument 'OrganizationalUnits' -Message "The OrganizationalUnits Parameter contains an invalid OU value: '$_ou'. Please correct this value and try again."
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            Try
            {

                # API is broken
                # "[{0}] Validating authentication directory setting is valid" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                # $_validateresp = Send-HPOVRequest -Uri $authnProviderValidatorUri -Method POST -Body $_NewAuthDirectoryObj -Hostname $_appliance

                "[{0}] Submitting request to create new authentication directory" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_resp = Send-HPOVRequest -Uri $authnProvidersUri -Method POST -Body $_NewAuthDirectoryObj -Hostname $_appliance

                $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectory")

                [void]$_AuthDirectorySettings.Add($_resp)

            }

            Catch
            {

                foreach ($NestedError in (${Global:ResponseErrorObject} | Where-Object Name -eq $_appliance.Name).ErrorResponse.nestedErrors) 
                {

                    if ($NestedError.errorCode -eq "AUTHN_LOGINDOMAIN_SERVER_AUTHENTICATION_ERROR" ) 
                    { 
                        
                        $ErrorCategory = 'AuthenticationError' 

                    }

                    elseif ($NestedError.errorCode -eq "AUTHN_LOGINDOMAIN_DUPLICATE_NAME" ) 
                    { 
                        
                        $ErrorCategory = 'ResourceExists' 

                    }

                    else 
                    { 
                        
                        $ErrorCategory = 'InvalidOperation' 
                    
                    }

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException $NestedError.errorCode $ErrorCategory "New-HPOVLdapDirectory" -Message "$($NestedError.message) $($NestedError.details)"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException InvalidResult InvalidOperation 'New-HPOVLdapDirectory' -Message "$((${Global:ResponseErrorObject} | ? Name -eq $_appliance.Name).ErrorResponse.message) $((${Global:ResponseErrorObject} | ? Name -eq $_appliance.Name).ErrorResponse.details)"
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }

    End 
    {

        Return $_AuthDirectorySettings
       
    }

}

function Remove-HPOVLdapDirectory 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ("d",'Directory')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default),

        [Parameter (Mandatory = $False, ParameterSetName = "default")]
        [Switch]$Force

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection    = [System.Collections.ArrayList]::new()
        $_DirectoryCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        { 

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # "[{0}] Directory Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

            If ($InputObject.category -eq 'users')
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Directory:$($InputObject.Name)" -TargetType PSObject -Message "The Directory resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_DirectoryCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Directory:$($InputObject.Name)" -TargetType PSObject -Message "The Directory resource is not an expected category type [$($InputObject.category)]. Allowed resource category type is 'users'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
        
        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing Directory Name $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_directory = Get-HPOVLdapDirectory $InputObject -ApplianceConnection $_appliance

                    $_directory | ForEach-Object {

                        [void]$_DirectoryCollection.Add($_)

                    }

                }

                Catch
                {

                    if ($_.FullyQualifiedErrorId -match 'AuthDirectoryResourceNotFound')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException AuthDirectoryResourceNotFound ObjectNotFound 'InputObject' -Message "The Directory '$InputObject' was not found on Appliance '$($_appliance.Name)'."
                        $PSCmdlet.WriteError($ErrorRecord)

                    }

                    else
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }                

            }

        }
        
    }

    End
    {

        "[{0}] Processing $($_DirectoryCollection.count) Authentication Directory resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Directory Resources
        ForEach ($_Directory in $_DirectoryCollection)
        {

            if ($PSCmdlet.ShouldProcess($_Directory.ApplianceConnection.Name,"remove directory '$($_Directory.name)'")) 
            {

                "[{0}] Removing Directory '$($_Directory.name)' from appliance '$($_Directory.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    $_resp = Send-HPOVRequest -Uri $_Directory.Uri -Method DELETE -Hostname $_Directory.ApplianceConnection.Name -AddHeader @{'If-Match' = $InputObject.eTag } 

                    $_resp | Add-Member -NotePropertyName name -NotePropertyValue $_Directory.name

                    $_resp

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVLdapDefaultDirectory 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [Alias('Directory')]
        [Object]$InputObject,

        [Switch]$DisableLocalLogin,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
    
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_TaskCollection      = [System.Collections.ArrayList]::new()
        $_DirectoryCollection = [System.Collections.ArrayList]::new()
    
    }

    #Build collection of objects to Process
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            # Create default Directory configuration object
            $_DefaultDirectoryConfig = [PSCustomObject]@{
            
                allowLocalLogin     = (-not($DisableLocalLogin.IsPresent));
                defaultLoginDomain  = $Null;
                ApplianceConnection = $_appliance

            }

            switch ($InputObject.Gettype().Name) 
            {

                "String" 
                {

                    if ($InputObject -ne "Local") 
                    {

                        "[{0}] Authentication Directory Name provided: $InputObject" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        Try
                        {

                            $InputObject = Get-HPOVLdapDirectory -Name $InputObject -Hostname $_appliance.Name -ErrorAction Stop

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    elseif ($InputObject -eq "Local") 
                    {

                        $InputObject = [PSCustomObject] @{

                            type                = 'LoginDomainConfigInfoDto';
                            name                = "LOCAL";
                            uri                 = "";
                            loginDomain         = "0";

                        }

                    }

                }

                "PSCustomObject" 
                {

                    if ($InputObject.type -match 'LoginDomainConfig') 
                    {

                        "[{0}] Authentication Directory Object provided: {1} ({2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name, $InputObject.uri | Write-Verbose

                        $InputObject.type = 'LoginDomainConfigInfoDto'

                    }

                    else 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryException InvalidAuthDirectoryObject InvalidArgument "InputObject" -TargetType "PSObject" -Message "The authentication directory object type '$($InputObject.type)' provided is not correct. The type must be 'LoginDomainConfigVersion200'. Please correct the value and try again."

                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                }

            }

            $_DefaultDirectoryConfig.defaultLoginDomain = ($InputObject | Select-Object type,loginDomain,name,eTag,uri)

            [void]$_DirectoryCollection.Add($_DefaultDirectoryConfig)

        }

    }

    # Process objects here
    End 
    {

        ForEach ($_DirectoryToProcess in $_DirectoryCollection)
        {

            if ($PSCmdlet.ShouldProcess($_DirectoryToProcess.ApplianceConnection.Name,"Set appliance authentication directory $($_DirectoryToProcess.defaultLoginDomain.name) as default domain")) 
            {
        
                "[{0}] Setting default Authentication Directory to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DirectoryToProcess.defaultLoginDomain.name | Write-Verbose

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $authnSettingsUri -Method POST -Body $_DirectoryToProcess -Hostname $_DirectoryToProcess.ApplianceConnection.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($IsWindows)
                {

                    "[{0}] Setting PowerShell library AuthProvider registry (HKCU:\Software\Hewlett-Packard\HPOneView) value to 'AuthProvider#{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DirectoryToProcess.defaultLoginDomain.name | Write-Verbose

                    Set-ItemProperty -Path HKCU:\Software\Hewlett-Packard\HPOneView -Name ("AuthProvider#{0}" -f $_DirectoryToProcess.ApplianceConnection.Name) -Value $_DirectoryToProcess.defaultLoginDomain.name -Type STRING | Write-Verbose

                }
                
            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_resp = $null

            }

            else
            {

                "[{0}] User likely selected 'No' to prompt." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_resp = $null

            }

            $_resp

        }

    }

}

function Enable-HPOVLdapLocalLogin 
{
        
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
    
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {
                
                # Get current auth directory configuration
                $_currentDirectoryConfig = Send-HPOVRequest $authnSettingsUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            "[{0}] Current global authentication settings: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_currentDirectoryConfig | ConvertTo-Json) | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_appliance.Name,"enable local logins")) 
            {

                $_request = 'true'

                Try
                {

                    # Update Configuration
                    $_resp = Send-HPOVRequest $AuthnAllowLocalLoginUri POST $_request -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                [void]$_TaskCollection.Add($_resp)

            }

            elseif ($PSBoundParameters['Whatif'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }
        
    }

    End 
    {

        Return $_TaskCollection

    }

}

function Disable-HPOVLdapLocalLogin 
{
        
    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_TaskCollection = [System.Collections.ArrayList]::new()
    
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($_appliance.AuthLoginDomain -eq 'LOCAL')
            {

                $ExceptionMessage = 'To disable local login you must log in using another authentication service.'
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthSessionException InvalidLoginDomain InvalidOperation 'AuthLoginDomain' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Try
            {
                
                # Get current auth directory configuration
                $_currentDirectoryConfig = Send-HPOVRequest $authnSettingsUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_currentDirectoryConfig.defaultLoginDomain.name -eq 'LOCAL')
            {

                $ExceptionMessage = 'The Default Login Domain must not be set to "LOCAL" before disabling Local Logins.'
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapConfigurationException InvalidDefaultLoginDomain InvalidOperation 'DefaultLoginDomain' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }
            
            "[{0}] Current global authentication settings: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_currentDirectoryConfig | ConvertTo-Json) | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_appliance.Name,"disable local logins")) 
            {

                $_request = 'false'

                Try
                {

                    # Update Configuration
                    $_resp = Send-HPOVRequest $AuthnAllowLocalLoginUri POST $_request -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                [void]$_TaskCollection.Add($_resp)

            }

            elseif ($PSBoundParameters['Whatif'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }
        
    }

    End 
    {

        Return $_TaskCollection

    }

}

function New-HPOVLdapServer 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Name')]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Alias ('port')]
        [ValidateRange (1,65535)]
        [Int32]$SSLPort = 636,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Alias ('cert')]
        [Object]$Certificate,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Switch]$TrustLeafCertificate

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
        $_AuthDirectoryServer = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        Try
        {

            $Parameters = @{

                Hostname = $Hostname;

            }

            if ($SSLPort)
            {

                $Parameters.Add("SSLPort", $SSLPort)
                
            }
            
            if ($Certificate)
            {

                $Parameters.Add("Certificate", $Certificate)

            }
            
            if ($TrustLeafCertificate)
            {

                $Parameters.Add("TrustLeafCertificate", $TrustLeafCertificate.IsPresent)

            }

            $_LdapServer = BuildLdapServer @Parameters

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }


        # Add the directory server to the provided Auth Directory
        if ($InputObject)
        {

            "[{0}] Processing Auth Directory value" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if ($InputObject.category -ne 'users')
            {

                $ExceptionMessage = "The Directory resource is not an expected category type [{0}]. Allowed resource category type is 'users'. Please check the object provided and try again." -f $InputObject.category
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument $InputObject.Name -TargetType PSObject -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if (-not($PSBoundParameters['Password']))
            {

                do 
                {
                    
                    $securepass   = Read-Host 'Password' -AsSecureString
                    $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                    $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                    $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                    if ($_DecryptPassword -ne $_DecryptPassword2)
                    {

                        Write-Host "Passwords do not match!" -BackgroundColor Red

                    }

                } until ($_DecryptPassword -eq $_DecryptPassword2)
                
            }

            elseif ($Password -is [SecureString])
            {

                $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

            }

            else 
            {

                $_DecryptPassword = $Password

            }

            # Add credentials to object
            $InputObject.credential = @{ userName = $Username; password = $_DecryptPassword }

            Try
            {

                $_resp = Send-HPOVRequest -Uri $InputObject.Uri -Method PUT -Body $InputObject -Hostname $InputObject.ApplianceConnection.Name

                $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectory")

                $_resp

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }            

        }

        else
        {

            "[{0}] Return directory server object" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_ldapServer

        }        

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVLdapServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (
        
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'PSCredential')]
        [ValidateNotNullorEmpty()]
        [PSCustomObject]$InputObject,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [Parameter (Mandatory, ParameterSetName = "PSCredential")]
        [ValidateNotNullorEmpty()]
        [Alias ("Name")]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "PSCredential")]
        [Alias ('port')]
        [ValidateRange (1,65535)]
        [Int32]$SSLPort = 636,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "PSCredential")]
        [Alias ('cert')]
        [Object]$Certificate,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('u','user')]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('p','pass')]
        [Object]$Password,
        
        [Parameter (Mandatory, ParameterSetName = "PSCredential")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Parameter (Mandatory = $false, ParameterSetName = "PSCredential")]
        [Switch]$TrustLeafCertificate,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'PSCredential')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection

    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $InputObject) 
        {

            $PipelineINput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)
            
        }

        elseif ($Password -is [SecureString])
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSBoundParameters['Password'])
        {

            $_DecryptPassword = $Password

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        else
        {

            $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters.'
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    Process 
    {

        Try
        {

            $Parameters = @{

                Hostname = $Hostname;

            }

            if ($SSLPort)
            {

                $Parameters.Add("SSLPort", $SSLPort)
                
            }
            
            if ($Certificate)
            {

                $Parameters.Add("Certificate", $Certificate)

            }
            
            if ($TrustLeafCertificate)
            {

                $Parameters.Add("TrustLeafCertificate", $TrustLeafCertificate.IsPresent)

            }

            $_LdapServer = BuildLdapServer @Parameters

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # "[{0}] New Auth Directory Server Object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $($_ldapServer | Format-List * ) | Write-Verbose

        "[{0}] Processing Auth Directory value" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if ($InputObject.category -ne 'users')
        {

            $ExceptionMessage = "The Directory resource is not an expected category type [{0}]. Allowed resource category type is 'users'. Please check the object provided and try again." -f $InputObject.category
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument $InputObject.Name -TargetType PSObject -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Add credentials to object
        if ($InputObject.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['USERACCOUNT'])
        {

            $InputObject.credential = @{ userName = $Username; password = $_DecryptPassword }

        }

        else
        {

            $InputObject.credential.userName = $Username
            $InputObject.credential.password = $_DecryptPassword

        }        

        # Rebuild directoryServers property
        $_DirectoryServers = $InputObject.directoryServers.Clone()

        $InputObject.directoryServers = [System.Collections.ArrayList]::new()

        [Void]$InputObject.directoryServers.Add($_ldapServer)

        ForEach ($_Server in $_DirectoryServers)
        {

            [Void]$InputObject.directoryServers.Add($_Server)

        }

        Try
        {

            $_resp = Send-HPOVRequest -Uri $InputObject.Uri -Method PUT -Body $InputObject -Hostname $InputObject.ApplianceConnection.Name

            $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectory")

            $_resp

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }    

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function BuildLdapServer
{

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (
        
        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ("Name")]
        [String]$Hostname,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Alias ('port')]
        [ValidateRange (1,65535)]
        [Int32]$SSLPort = 636,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Alias ('cert')]
        [Object]$Certificate,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [Bool]$TrustLeafCertificate

    )

    Process
    {

        $Base64Certificate = ""

        if ($Certificate)
        {

            if (Test-Path $Certificate) 
            { 

                "[{0}] Certificate file found." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $readfile = [System.IO.File]::OpenText($Certificate)
                    $certificate = $readfile.ReadToEnd()
                    $readfile.Close()
                    $Base64Certificate = ($Certificate | Out-String) -join "`n"

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

            else 
            {

                $ErrorRecord = New-ErrorRecord System.IO.FileNotFoundException CertificateNotFound ObjectNotFound 'Certificate' -TargetType 'PSObject' -Message "Autehntication Directory Server SSL certiciate not found. Please check the path of the public key, and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        elseif ($TrustLeafCertificate)
        {

            "[{0}] Attempting to get SSL certificate from '{1}' on '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Hostname, $Sslport | Write-Verbose

            try 
            {
                
                $Certificate = [HPOneView.Utilities.Net]::DownloadSslCertificate($Hostname, $SslPort)
            
            }
    
            catch
            {

                '[{0}] Caught exception' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $sb = New-Object System.Text.StringBuilder

            [void]$sb.Append("-----BEGIN CERTIFICATE-----`n")
            [void]$sb.Append([System.Convert]::ToBase64String($Certificate.RawData, "InsertLineBreaks"))
            [void]$sb.Append("`n-----END CERTIFICATE-----`n")

            $Base64Certificate = $sb.ToString()

        }
        
        $_LdapServer = NewObject -AuthDirectoryServer

        $_LdapServer.directoryServerIpAddress             = $Hostname
        $_LdapServer.directoryServerCertificateBase64Data = $Base64Certificate

        if ($PSBoundParameters['Sslport'])
        {

            $_LdapServer.directoryServerSSLPortNumber = $Sslport.ToString()

        }
        
        $_LdapServer.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AuthDirectoryServer')

        return $_LdapServer

    }

}

function Remove-HPOVLdapServer
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'PSCredential')]
        [Alias ('Directory')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'PSCredential')]
        [ValidateNotNullorEmpty()]
        [Alias ('Name')]
        [String]$DirectoryServerName,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('u','user')]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('p','pass')]
        [Object]$Password,

        [Parameter (Mandatory, ParameterSetName = "PSCredential")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'PSCredential')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection

    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $InputObject) 
        {

            $PipelineINput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)
            
        }

        elseif ($Password -is [SecureString])
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSBoundParameters['Password'])
        {

            $_DecryptPassword = $Password

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        else
        {

            $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters.'
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }
        
    }

    Process 
    {

        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        "[{0}] LdapDirectory Object provided: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Format-List *) | Write-Verbose

        If ('users' -contains $InputObject.category)
        {

            If (-not($InputObject.ApplianceConnection))
            {

                $ExceptionMessage = "The InputObject parameter value resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else
        {

            $ExceptionMessage = "The Group object resource is not an expected category type [{0}]. The allowed resource category type is 'users'. Please check the object provided and try again." -f $InputObject.category
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message $ExceptionMessage
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        # Add credentials to object
        if ($InputObject.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['USERACCOUNT'])
        {

            $InputObject.credential = @{ userName = $Username; password = $_DecryptPassword }

        }

        else
        {

            $InputObject.credential.userName = $Username
            $InputObject.credential.password = $_DecryptPassword

        }    

        $PromptMessage = "remove directory server '{0}'" -f $DirectoryServerName

        if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection.Name,$PromptMessage)) 
        {

            "[{0}] Removing Directory Server '{1}' from LDAP Directory '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(),$DirectoryServerName, $InputObject.name | Write-Verbose

            Try
            {

                [Array]$InputObject.directoryServers = $InputObject.directoryServers | Where-Object directoryServerIpAddress -ne $DirectoryServerName
                
                $_resp = Send-HPOVRequest -Uri $InputObject.Uri -Method PUT -Body $InputObject -Hostname $InputObject.ApplianceConnection.Name

                $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectory")

                $_resp

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        elseif ($PSBoundParameters['WhatIf'])
        {

            "[{0}] -WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Show-HPOVLdapGroups 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'PSCredential')]
        [ValidateNotNullOrEmpty()]
        [Alias ("d","domain","AuthProvider")]
        [Object]$Directory,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ("u")]
        [String]$UserName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Alias ("p")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$Password,
        
        [Parameter (Mandatory = $false, ParameterSetName = "PSCredential")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ParameterSetName = 'PSCredential')]
        [ValidateNotNullOrEmpty()]
        [String]$GroupName,
            
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'PSCredential')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $Directory) 
        {

            $PipelineINput = $true

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)

            $Password = $securepass
            
        }

        elseif (-not $PSBoundParameters['Password'] -and -not $PSBoundParameters['Username'] -and -not $PSBoundParameters['Credential'])
        {

            "[{0}] Credentials were not provided. Will validate directory object for 'directoryBindingType' in Process block." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        $_DirectoryGroupsCollection = [System.Collections.ArrayList]::new()
        
    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSBoundParameters['Directory'])
            {

                "[{0}] Validating directory parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                switch ($Directory.GetType().Name)
                {

                    'String'
                    {

                        "[{0}] Looking for directory by name." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                        Try
                        {
                        
                            $Directory = Get-HPOVLdapDirectory -Name $Directory -ApplianceConnection $_appliance

                        }

                        Catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                    }

                    'PSCustomObject'
                    {

                        "[{0}] Directory object provided." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ($Directory.type -notmatch 'LoginDomainConfig')
                        {

                            $ExceptionMessage = 'The provided -Directory Parameter value is not a support object type, {0}. Please verify the object.' -f $Directory.name
                            $ErrorRecord      = New-ErrorRecord ArgumentException InvalidGroupCommonName InvalidArgument 'Group' -Message $ExceptionMessage
                            $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                        }

                    }

                }

                $_Search = $Directory.baseDN

            }
            
            if ($PSBoundParameters['GroupName'])
            {

                $_Search = $GroupName

            }

            Try
            { 

                $_Params = @{

                    Search              = $_Search;
                    Directory           = $Directory.name;
                    Username            = $null;
                    Password            = $null;
                    ApplianceConnection = $_appliance

                }

                if ($Directory.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['SERVICEACCOUNT'])
                {

                    "[{0}] Directory uses Service Account to bind." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Params.Username = $Directory.credential.userName

                }

                elseif ($Directory.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['USERACCOUNT'])
                {

                    if ($PSBoundParameters['Credential'])
                    {
    
                        "[{0}] Using PSCredential object to provide directory auth credentials." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                        $_Params.Username = $Credential.Username
                        $_Params.Password = $Credential.Password
    
                    }
    
                    elseif ($PSBoundParameters['Username'])
                    {
    
                        "[{0}] Providing user crednetials for directory auth." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                        $_Params.Username = $Username
                        $_Params.Password = $Password
    
                    }

                    # User did not provide required authentication for directory. Throw error.
                    else
                    {
            
                        $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters. The directory {0} is configured to require user authentication in order to bind to the authentication directory.' -f $Directory.name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
    
                    }

                }                
                
                $_Groups = BuildGroupList @_Params
                
            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }    
 
    }

    End 
    {
    
        return $_Groups

    }

}

function BuildGroupList
{

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Position = 0, Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Search,

        [Parameter (Position = 1, Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Username,

        [Parameter (Position = 2, Mandatory = $false, ParameterSetName = 'Default')]
        [SecureString]$Password,

        [Parameter (Position = 3, Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Directory,

        [Parameter (Position = 4, Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection

    )

    Begin
    {

        "[{0}] Processing Search: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Search | Write-Verbose

        $_Collection = [System.Collections.ArrayList]::new()

        $_body = @{
            
            type             = 'Group2RoleSearchContext';
            directoryName    = $Directory;
            userName         = $Username;
            password         = $Password;
            searchContext    = $Search

        }

        if ($PSBoundParameters['Password'])
        {

            $_body.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            
        }

    }

    Process
    {

        $_uri = $AuthnDirectorySearchContextUri

        if ($Search.ToLower().StartsWith('ou=') -or $Search.ToLower().StartsWith('cn=') -or $Search.ToLower().StartsWith('dc='))
        {

            "[{0}] Navigating tree" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_body | Add-Member -NotePropertyName start -NotePropertyValue 0 -force

        }

        else
        {

            "[{0}] Searching for group name" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_GroupSearch = $True

            $_uri += '/search'        

        }

        Try
        {

            $_Resp = Send-HPOVRequest -uri $_uri -Method POST -body $_body -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if (-not($_GroupSearch))
        {

            ForEach ($_ChildOU in ($_Resp | Where-Object hasChildren))
            {

                "[{0}] Processing Child OU {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ChildOU.distinguishedName | Write-Verbose

                $_Groups = BuildGroupList $_ChildOU.distinguishedName $Username $Password $Directory $ApplianceConnection

                ForEach ($_group in $_Groups)
                {
            
                    [void]$_Collection.Add($_group)
            
                }

            }

        }
        
        ForEach ($_DirGroup in ($_Resp | Where-Object groupType))
        {

            "[{0}] Processing Group {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_DirGroup.displayName.Replace('CN=',$null) | Write-Verbose

            $_entry = New-Object HPOneView.Appliance.LdapDirectoryGroup($_DirGroup.displayName.Replace('CN=',$null),
                                                                        $_DirGroup.distinguishedName, 
                                                                        $_DirGroup.distinguishedName.Replace($_DirGroup.displayName + ',',$null), 
                                                                        $Directory)

            [void]$_Collection.Add($_entry)

        }

    }

    End
    {

        Return $_Collection
    
    }
    
}

function Get-HPOVLdapGroup 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [Alias ("group","GroupName")]
        [String]$Name,

        [Parameter (Mandatory, ParameterSetName = 'Export')]
        [Alias ('x')]
        [ValidateScript({split-path $_ | Test-Path})]
        [String]$Export,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Export')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_DirectoryGroupsCollection = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {
        
            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            { 
                
                $_Groups = Send-HPOVRequest $AuthnEgroupRoleMappingUri -Hostname $_appliance.Name

                ForEach ($_Group in $_Groups.members)
                {

                    $_Group.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.AuthDirectoryGroupRoleMapping") 
                
                    [void]$_DirectoryGroupsCollection.Add($_Group)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }      

    }

    End 
    {

        if ($PSBoundParameters['Name']) 
        { 
            
            $_DirectoryGroupsCollection = $_DirectoryGroupsCollection | Where-Object egroup -eq $Name

            if ($_DirectoryGroupsCollection.Count -eq 0)
            {
                
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryGroupException AuthDirectoryGroupResourceNotFound ObjectNotFound "Name" -Message "The specified '$name' Authentication Directory Group resource not found. Please check the name and try again."
                
                $PSCmdlet.WriteError($ErrorRecord)

            }
        
        }

        if ($PSBoundParameters['Export'])
        { 
            
            $_DirectoryGroupsCollection | convertto-json > $Export 
        
        }
 
        else 
        {

            Return $_DirectoryGroupsCollection

        }

    }

}

function New-HPOVLdapGroup 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Scope')]
        [ValidateNotNullOrEmpty()]
        [Alias ("d","domain","authProvider")]
        [Object]$Directory,

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Scope')]
        [ValidateNotNullOrEmpty()]
        [Alias ("g","GroupName","name")]
        [Object]$Group,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ("r","role")]
        [Array]$Roles,

        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [ValidateNotNullOrEmpty()]
        [Array]$ScopePermissions,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [ValidateNotNullOrEmpty()]
        [Alias ("u")]
        [String]$Username,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [Alias ("p")]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = "Scope")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,
            
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Directory'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
                
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }


                }

            }

            else
            {

                Try 
                {
                
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_DirectroyGroupStatus = [System.Collections.ArrayList]::new()

        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)
            
        }

        elseif ($Password -is [SecureString])
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSBoundParameters['Password'])
        {

            $_DecryptPassword = $Password

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        else
        {

            "[{0}] Credentials were not provided. Will validate directory object for 'directoryBindingType' in Process block." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    Process
    {
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_unsupportedRoles = [System.Collections.ArrayList]::new()
            $_PremissionsCol   = [System.Collections.ArrayList]::new()

            if ($PSBoundParameters['Roles'])
            {

                "[{0}] Validating requested role values" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                # Validate roles provided are allowed.
                foreach ($_role in $Roles) 
                {

                    "[{0}] Processing role: $_role" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if (-not ((${Global:ConnectedSessions} | Where-Object Name -EQ $_appliance.Name).ApplianceSecurityRoles -contains $_role)) 
                    { 
                    
                        "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_unsupportedRoles.Add($_role)

                    }

                    else
                    {

                        "[{0}] Supported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_TempName = $_role.split(' ')

                        $_NewPermission = NewObject -DirectoryGroupPermissions

                        $_UpdatedName = New-Object System.Text.StringBuilder

                        for ($s = 0; $s -lt $_TempName.count; $s++) 
                        {

                            if ($s -eq 0) 
                            { 
                                
                                [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                            
                            }

                            else 
                            {

                                [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                            
                            }

                        }

                        $_NewPermission.roleName = $_UpdatedName.ToString()

                        [void]$_PremissionsCol.Add($_NewPermission)

                    }

                }

                if ($_unsupportedRoles.count -ge 1) 
                { 

                    $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedRolesFound InvalidArgument $($MyInvocation.InvocationName.ToString().ToUpper()) -Message "The '$($_unsupportedRoles -join ", ")' role(s) is/are not supported or the correct names. Please validate the -roles Parameter contains one or more valid roles. Allowed roles are: $((${Global:ConnectedSessions} | ? Name -EQ $_appliance.Name).ApplianceSecurityRoles -join ", ")"
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)            

                }

            }
            
            # Process scopes with permissions
            if ($PSBoundParameters['ScopePermissions'])
            {

                # Rebuild the

                ForEach ($_ScopeToPermission in $ScopePermissions)
                {

                    "[{0}] Processing role: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Role | Write-Verbose
                    
                    if (-not ((${Global:ConnectedSessions} | Where-Object Name -EQ $_appliance.Name).ApplianceSecurityRoles -contains $_ScopeToPermission.Role)) 
                    { 
                    
                        "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_unsupportedRoles.Add($_ScopeToPermission.Role)

                    }

                    else
                    {

                        "[{0}] Supported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ([System.String]::IsNullOrWhiteSpace($_ScopeToPermission.Scope))
                        {

                            Throw "Scope property within ScopePermissions must contain at least 1 entry."

                        }

                        $_TempName = $_ScopeToPermission.Role.split(' ')

                        ForEach ($_Scope in $_ScopeToPermission.Scope)
                        {

                            if ($_Scope -IsNot [HPOneView.Appliance.ScopeCollection])
                            {
    
                                Throw ("Invalid scope resource {0}" -f $_Scope.name)
    
                            }
                            
                            $_NewPermission = NewObject -DirectoryGroupPermissions

                            $_UpdatedName = New-Object System.Text.StringBuilder

                            for ($s = 0; $s -lt $_tempname.count; $s++) 
                            {

                                if ($s -eq 0) 
                                { 
                                    
                                    [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                                
                                }

                                else 
                                {

                                    [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                                
                                }

                            }
    
                            $_NewPermission.roleName = $_UpdatedName.ToString()
                            $_NewPermission.scopeUri = $_Scope.uri
    
                            [void]$_PremissionsCol.Add($_NewPermission)

                        }                        

                    }

                }                

            }

            switch ($Group.GetType().Name)
            {

                'String'
                {

                    if (-not [HPOneView.Utilities.Security.X500DistinguishedName]::TryParse($Group))
                    {

                        $Message     = 'The provided -Group Parameter value {0} is not a valid Distinguished Name (DN) value. Please verify the Group DN follows this format: CN=GroupName,OU=OrganizationalUnit,DC=Domain,DC=com' -f $Group
                        $ErrorRecord = New-ErrorRecord ArgumentException InvalidGroupCommonName InvalidArgument 'Group' -Message $Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                    $Group = [PSCustomObject]@{ DN = $Group }

                }

                'PSCustomObject'
                {

                    if (-not [HPOneView.Utilities.Security.X500DistinguishedName]::TryParse($Group.DN))
                    {

                        $Message     = 'The provided -Group Parameter value {0} does not contain a valid Distinguished Name (DN) value. Please verify the Group DN follows this format: CN=GroupName,OU=OrganizationalUnit,DC=Domain,DC=com' -f $Group.Name
                        $ErrorRecord = New-ErrorRecord ArgumentException InvalidGroupCommonName InvalidArgument 'Group' -TargetType 'PSObject' -Message $Message
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)  

                    }

                }

            }
        
            # Get new Directory Group object
            $_NewGroup = NewObject -DirectoryGroup

            $_NewGroup.group2PermissionPerGroup.loginDomain = $Directory.name
            $_NewGroup.group2PermissionPerGroup.egroup      = $Group.DN
            $_NewGroup.group2PermissionPerGroup.permissions = $_PremissionsCol

            if ($Directory.directoryBindingType -ne $LdapDirectoryAccountBindTypeEnum['SERVICEACCOUNT'] -and (-not $PSBoundParameters['Username'] -and -not $PSBoundParameters['Credential']))
            {
    
                $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters.'
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
            }

            elseif ($Directory.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['SERVICEACCOUNT'])
            {

                $_NewGroup.credentials.userName = $Directory.credential.userName

            }
    
            elseif ($Directory.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['USERACCOUNT'])
            {
    
                # Add credentials to object
                $_NewGroup.credentials.userName = $Username
                $_NewGroup.credentials.password = $_decryptPassword
    
            }            
        
            # "[{0}] Directory Group requested to create: $($_NewGroup | out-string )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Sending request to create $($_NewGroup.egroup) Directory Group" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            Try
            {

                $_resp = Send-HPOVRequest -Uri $AuthnEgroupRoleMappingUri -Method POST -Body $_NewGroup -Hostname $_appliance

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AuthDirectoryGroupRoleMapping')

            [void]$_DirectroyGroupStatus.Add($_resp)
           
        }

    }

    End
    {
        
        Return $_DirectroyGroupStatus

    }

}

function Set-HPOVLdapGroupRole 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = 'Role')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Role')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Scope')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'RoleAndScope')]
        [ValidateNotNullOrEmpty()]
        [Alias ("g","name",'GroupName', 'Group')]
        [Object]$InputObject,

        [Parameter (Mandatory, ParameterSetName = 'Role')]
        [Parameter (Mandatory, ParameterSetName = 'RoleAndScope')]
        [ValidateNotNullOrEmpty()]
        [Alias ("r","role")]
        [Array]$Roles,
        
        [Parameter (Mandatory, ParameterSetName = 'Scope')]
        [Parameter (Mandatory, ParameterSetName = 'RoleAndScope')]
        [ValidateNotNullOrEmpty()]
        [Array]$ScopePermissions,        

        [Parameter (Mandatory = $false, ParameterSetName = 'Role')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RoleAndScope')]
        [ValidateNotNullOrEmpty()]
        [Alias ("u")]
        [String]$UserName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Role')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RoleAndScope')]
        [Alias ("p")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$Password,

        [Parameter (Mandatory = $false, ParameterSetName = 'Role')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Scope')]
        [Parameter (Mandatory = $false, ParameterSetName = 'RoleAndScope')]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Role')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Scope')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'RoleAndScope')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        if ($PSBoundParameters['Username'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."
            
        }

        if ($PSBoundParameters['Password'])
        {

            Write-Warning "The -Username parameter will be deprecated in a future release. Please transition to using the -Credental Parameter."

        }

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        # No need to validate ApplianceConnection, as object is passed via pipeline.
        if (-not $PSboundParameters['InputObject'])
        {

            "[{0}] Pipeline input." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            $PipelineInput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ExceptionMessage = "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }
                        
        }

        $_DirectoryGroupsToUpdate = [System.Collections.ArrayList]::new()
        $_DirectoryGroupStatus    = [System.Collections.ArrayList]::new()

        # Decrypt the password
        if (-not($PSBoundParameters['Password']) -and $PSBoundParameters['Username'])
        {

            do 
            {
                
                $securepass   = Read-Host 'Password' -AsSecureString
                $securepass2  = Read-Host 'Confirm Password' -AsSecureString
                $_DecryptPassword  = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass))
                $_DecryptPassword2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepass2))

                if ($_DecryptPassword -ne $_DecryptPassword2)
                {

                    Write-Host "Passwords do not match!" -BackgroundColor Red

                }

            } until ($_DecryptPassword -eq $_DecryptPassword2)
            
        }

        elseif ($Password -is [SecureString])
        {

            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

        }

        elseif ($PSBoundParameters['Password'])
        {

            $_DecryptPassword = $Password

        }

        elseif ($PSBoundParameters['Credential'])
        {

            $Username = $Credential.Username
            $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))

        }

        else
        {

            "[{0}] Credentials were not provided. Will validate directory object for 'directoryBindingType' in Process block." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

    }

    Process 
    {

        ForEach ($_Group in $InputObject)
        {

            # Validate pipeline input is user object
            if (-not $_Group.category -eq 'users')
            {

                "[{0}] Invalid Group provided: $($_Group )" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryGroupException InvalidDirectoryGroupObject InvalidArgument "Group" -TargetType 'PSObject' -Message "The Group Parameter value is not a valid Directory Group object resource. Object category provided '$($Group.category)', allowed object category value 'users'. Please verify the input object and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            "[{0}] Processing Group: $($_Group.egroup)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $_UpdateDirectroyGroup = NewObject -DirectoryGroup
            $_UpdateDirectroyGroup.group2PermissionPerGroup.egroup  = $_Group.egroup
            $_UpdateDirectroyGroup.group2PermissionPerGroup.loginDomain  = $_Group.loginDomain

            "[{0}] Original Group object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($_Group | ConvertTo-Json -Depth 99 | Out-String) | Write-Verbose

            # Get the auth directory associated with the group
            Try
            {

                $_Directory = Get-HPOVLdapDirectory -Name $_Group.loginDomain -ApplianceConnection $_Group.ApplianceConnection -ErrorAction Stop

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_unsupportedRoles = [System.Collections.ArrayList]::new()
            $_PremissionsCol   = [System.Collections.ArrayList]::new()

            if ($PSBoundParameters['Roles'])
            {

                "[{0}] Validating requested role values" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                # Validate roles provided are allowed.
                foreach ($_role in $Roles) 
                {

                    "[{0}] Processing role: $_role" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    if (-not ((${Global:ConnectedSessions} | Where-Object Name -EQ $ApplianceConnection.Name).ApplianceSecurityRoles -contains $_role)) 
                    { 
                    
                        "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_unsupportedRoles.Add($_role)

                    }

                    else
                    {

                        "[{0}] Supported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_TempName = $_role.split(' ')

                        $_NewPermission = NewObject -DirectoryGroupPermissions

                        $_UpdatedName = New-Object System.Text.StringBuilder

                        for ($s = 0; $s -lt $_TempName.count; $s++) 
                        {

                            if ($s -eq 0) 
                            { 
                                
                                [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                            
                            }

                            else 
                            {

                                [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                            
                            }

                        }

                        $_NewPermission.roleName = $_UpdatedName.ToString()

                        [void]$_UpdateDirectroyGroup.group2PermissionPerGroup.permissions.Add($_NewPermission)

                    }

                }

                if ($_unsupportedRoles.count -ge 1) 
                { 

                    $ExceptionMessage = "The '{0}' role(s) is/are not supported or the correct names. Please validate the -roles Parameter contains one or more valid roles. Allowed roles are: {1}." -f [String]::Join(', ', $_unsupportedRoles.ToArray()), [String]::Join(', ', (${Global:ConnectedSessions} | Where-Object Name -EQ $ApplianceConnection.Name).ApplianceSecurityRoles)
                    $ErrorRecord = New-ErrorRecord ArgumentException UnsupportedRolesFound InvalidArgument $($MyInvocation.InvocationName.ToString().ToUpper()) -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)            

                }

            }
            
            # Process scopes with permissions
            if ($PSBoundParameters['ScopePermissions'])
            {

                ForEach ($_ScopeToPermission in $ScopePermissions)
                {

                    "[{0}] Processing role: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Role | Write-Verbose
                    
                    if ((${Global:ConnectedSessions} | Where-Object Name -EQ $ApplianceConnection.Name).ApplianceSecurityRoles -notcontains $_ScopeToPermission.Role)
                    { 
                    
                        "[{0}] Invalid or unsupported" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        [void]$_unsupportedRoles.Add($_ScopeToPermission.Role)

                    }

                    else
                    {

                        "[{0}] Supported role." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        if ([System.String]::IsNullOrWhiteSpace($_ScopeToPermission.Scope))
                        {

                            Throw "Scope property within ScopePermissions must contain at least 1 entry."

                        }

                        $_TempName = $_ScopeToPermission.Role.split(' ')

                        "[{0}] Process scope." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        "[{0}] Scope object type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Scope.GetType().Fullname | Write-Verbose
                        "[{0}] Scope object: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ScopeToPermission.Scope | Write-Verbose

                        if ($_ScopeToPermission.Scope -IsNot [HPOneView.Appliance.ScopeCollection] -and $_ScopeToPermission.Scope -ne 'All')
                        {

                            Throw ("Invalid scope resource {0}" -f $_ScopeToPermission.Name)

                        }

                        elseif ($_ScopeToPermission.Scope -eq 'All')
                        {

                            "[{0}] Scope is not an HPOneView.Appliance.ScopeCollection resource, but String 'All'. Will set uri to null." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            $_Scope = [PSCustomObject]@{uri = $null}

                        }

                        else
                        {

                            $_Scope = $_ScopeToPermission.Scope

                        }
                        
                        $_NewPermission = NewObject -DirectoryGroupPermissions

                        $_UpdatedName = New-Object System.Text.StringBuilder

                        for ($s = 0; $s -lt $_tempname.count; $s++) 
                        {

                            if ($s -eq 0) 
                            { 
                                
                                [void]$_UpdatedName.Append($_TempName[$s].Substring(0, 1).ToUpper() + $_TempName[$s].SubString(1, ($_TempName[$s].length - 1)).ToLower()) 
                            
                            }

                            else 
                            {

                                [void]$_UpdatedName.Append(" " + $_TempName[$s].ToLower()) 
                            
                            }

                        }
                        
                        "[{0}] Adding Role '{1}' -> '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_UpdatedName.ToString(), $_Scope.uri | Write-Verbose

                        $_NewPermission.roleName = $_UpdatedName.ToString()
                        $_NewPermission.scopeUri = $_Scope.uri

                        [void]$_UpdateDirectroyGroup.group2PermissionPerGroup.permissions.Add($_NewPermission)                    

                    }

                }                

            }            

            "[{0}] Directory binding type: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $LdapDirectoryAccountBindTypeEnum[$_Directory.directoryBindingType] | Write-Verbose

            if ($_Directory.directoryBindingType -ne $LdapDirectoryAccountBindTypeEnum['SERVICEACCOUNT'] -and (-not $PSBoundParameters['Username'] -and -not $PSBoundParameters['Credential']))
            {
    
                $ExceptionMessage = 'Please provide valid credentials using either -Username/-Password or -Credential parameters.'
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LdapAuthenticationException NoValidCredentialParameters AuthenticationError "ApplianceConnection" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
                
            }

            elseif ($_Directory.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['SERVICEACCOUNT'])
            {

                "[{0}] Adding username to object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_UpdateDirectroyGroup.credentials.userName = $Directory.credential.userName

            }
    
            elseif ($_Directory.directoryBindingType -eq $LdapDirectoryAccountBindTypeEnum['USERACCOUNT'])
            {

                "[{0}] Adding username and password to object." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
                # Add credentials to object
                $_UpdateDirectroyGroup.credentials.userName = $Username
                $_UpdateDirectroyGroup.credentials.password = $_decryptPassword
    
            }
            
            "[{0}] Sending request to update '$($_Group.egroup)' group." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $AuthnEgroupRoleMappingUri -Method PUT -Body $_UpdateDirectroyGroup -Hostname $_Group.ApplianceConnection

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_resp.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AuthDirectoryGroupRoleMapping')

            $_resp

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVLdapGroup 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param 
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('g','Group','Name')]
        [Object]$InputObject,
    
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_TaskCollection  = [System.Collections.ArrayList]::new()
        $_GroupCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {
 
        if ($PipelineInput -or $InputObject -is [PSCustomObject]) 
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            "[{0}] Group Object provided: {2}\{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.egroup, $InputObject.logindomain | Write-Verbose

            If ('users' -contains $InputObject.category)
            {

                If (-not($InputObject.ApplianceConnection))
                {

                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "Group:$($InputObject.Name)" -TargetType PSObject -Message "The Group object resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                [void]$_GroupCollection.Add($InputObject)

            }

            else
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message "The Group object resource is not an expected category type [$($Name.category)]. The allowed resource category type is 'users'. Please check the object provided and try again."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        else 
        {

            ForEach ($_appliance in $ApplianceConnection)
            {

                "[{0}] Processing Appliance $($_appliance.Name) (of $($ApplianceConnection.Count))" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] Processing Group Name $($InputObject)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_Group = Get-HPOVLdapGroup -Name $InputObject -ApplianceConnection $_appliance

                    $_Group | ForEach-Object {

                        [void]$_GroupCollection.Add($_)

                    }

                }

                Catch
                {

                    if ($_.FullyQualifiedErrorId -match 'AuthDirectoryGroupResourceNotFound')
                    {

                        $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LdapDirectoryGroupException AuthDirectoryGroupResourceNotFound ObjectNotFound 'InputObject' -Message "The Directory Group '$InputObject' was not found on Appliance '$($_appliance.Name)'."
                        $PSCmdlet.WriteError($ErrorRecord)

                    }

                    else
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }                

            }

        }

    }

    End
    {

        "[{0}] Processing $($_GroupCollection.count) Directory Group resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Network Resources
        ForEach ($_Group in $_GroupCollection)
        {

            if ($PSCmdlet.ShouldProcess($_Group.ApplianceConnection.Name,"remove directory group '$($_Group.egroup)'")) 
            {

                "[{0}] Removing Directory Group '$($_Group.egroup)' from appliance '$($_Group.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                    
                    $_resp = Send-HPOVRequest -Uri $_Group.Uri -Method DELETE -AddHeader @{'If-Match' = $_Group.eTag } -Hostname $_Group.ApplianceConnection

                    $_resp | Add-Member -NotePropertyName name -NotePropertyValue $_Group.egroup

                    [void]$_TaskCollection.Add($_resp)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

        Return $_TaskCollection

    }

}

function Get-HPOVAuditLog 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Int]$Count = 0,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [TimeSpan]$TimeSpan,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$Start,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$End = [DateTime]::Now,

        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_AllAuditLogs = [System.Collections.ArrayList]::new()
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $uri = $applAuditLogsUri + "?sort:asc"

            if ($PSBoundParameters['Count'])
            {

                $uri = "{0}&count={1}" -f $uri, $Count

            }

            $Filter = [System.Collections.ArrayList]::new()

            if ($TimeSpan)
            {

                [Void]$Filter.Add(("DATE<='{0}/P{1}D'" -f [DateTime]::Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),$TimeSpan.Days))
                
            }

            elseif ($Start)
            {

                [Void]$Filter.Add(("DATE>='{0}' and DATE<='{1}'" -f $Start.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"), $End.ToUniversalTime().ToString("yyyy-MM-ddT23:59:59Z")))

            }

            if ($Filter.count -gt 0)
            {

                $uri = '{0}&filter="{1}"' -f $uri, [String]::Join(' and ',$Filter.ToArray())

            }

            Try
            {
                
                # Send the request
                $_AuditLogs = Send-HPOVRequest -Uri $uri -Hostname $_appliance

                $_AuditLogs.members | ForEach-Object {

                    $_.PSObject.TypeNames.Insert(0,'HPOneView.Appliance.AuditLogEntry')

                    [void]$_AllAuditLogs.Add($_)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End
    {

        Return $_AllAuditLogs

    }

}

Function Get-HPOVAuditLogArchive
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param 
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ("save")]
        [String]$Location = (get-location).Path,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'default')]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        # Validate the path exists. If not, create it.
        if (-not(Test-Path $Location))
        {
             
            "[{0}] Directory does not exist. Creating directory..." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            New-Item $Location -itemtype directory

        }
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                # Now that the Support Dump has been requested, download the file
                "[{0}] Downloading audit log to $($Location)" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Download-File $applAuditLogDownloadUri $_appliance $Location

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

}

function Get-HPOVApplianceServiceConsoleAccess
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Appliance.ServiceConsoleAccess])]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceServiceAccessUri

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_serviceConsoleStatus = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

                New-Object HPOneView.Appliance.ServiceConsoleAccess($_serviceConsoleStatus, (New-Object HPOneView.Library.ApplianceConnection($_appliance.Name, $_appliance.ConnectionID)))

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVApplianceServiceConsoleAccess
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceEnableServiceAccessUri.Clone()

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                Send-HPOVRequest -Uri $_uri -Method PUT -Body 'true' -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVApplianceServiceConsoleAccess
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceEnableServiceAccessUri.Clone()

        Write-Warning "Disabling support access means that an authorized support representative cannot diagnose your system in the event of a system failure."

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_appliance.Name, "disable appliance console access")) 
            {

                "[{0}] Disabling appliance console access on appliance '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                Try
                {
                    
                    Send-HPOVRequest -Uri $_uri -Method PUT -Body 'false' -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVApplianceComplexPasswords
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $AuthnSettingsUri.Clone()

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Get global settings from appliance
            Try
            {

                $_CurrentApplianceLoginDomainGlobalSettings = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_CurrentApplianceLoginDomainGlobalSettings.enforceComplexPasswordEnabled = $true

            Try
            {

                Send-HPOVRequest -Uri $_uri -Method PUT -Body $_CurrentApplianceLoginDomainGlobalSettings -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVApplianceComplexPasswords
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $AuthnSettingsUri.Clone()

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Get global settings from appliance
            Try
            {

                $_CurrentApplianceLoginDomainGlobalSettings = Send-HPOVRequest -Uri $_uri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            $_CurrentApplianceLoginDomainGlobalSettings.enforceComplexPasswordEnabled = $false

            Try
            {

                Send-HPOVRequest -Uri $_uri -Method PUT -Body $_CurrentApplianceLoginDomainGlobalSettings -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceSshAccess
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Appliance.SshAccess])]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceSshAccessUri.Clone()

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_sshAccessStatus = Send-HPOVRequest -Uri $_uri -Hostname $_appliance
                
                New-Object HPOneView.Appliance.SshAccess($_sshAccessStatus.allowSshAccess, $_sshAccessStatus.ApplianceConnection)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVApplianceSshAccess
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default")]
    [OutputType([HPOneView.Appliance.TaskResource])]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceSshAccessUri.Clone()

        $_body = @{
            type           = "SshAccess";
            allowSshAccess = $True
        }

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_Resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_body -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            if (-not $PSBoundParameters['Async'])
            {

                $_Resp | Wait-HPOVTaskComplete

            }

            else
            {

                $_Resp
                
            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVApplianceSshAccess
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([HPOneView.Appliance.TaskResource])]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceSshAccessUri.Clone()

        $_body = @{
            type           = "SshAccess";
            allowSshAccess = $False
        }

        Write-Warning "Disabling SSH access prevents remote access to the maintenance console. The maintenance console is still accessible from the virtual machine system console."
        
        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_appliance.Name, "disable appliance ssh access")) 
            {

                "[{0}] Disabling appliance SSH access on appliance '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

                Try
                {
                    
                    $_Resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_body -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            if (-not $PSBoundParameters['Async'])
            {

                $_Resp | Wait-HPOVTaskComplete

            }

            else
            {

                $_Resp

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVCertificateValidation
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$CheckForSelfSignedExpiry,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceCertificateValidatorUri.Clone()

        $_Action = 'enable certificate validation'

        if ($PSBoundParameters['CheckForSelfSignedExpiry'])
        {

            Write-Warning 'If you enable expiry checking, while establishing a connection to external devices or servers associated with self-signed certificates, certificate expiry check will be performed and communication with any device that has an expired self-signed certificate will fail.'

            $_Action += ' and check for expiration of self-signed certificates'
        
        }

        Write-Warning "Enabling certificate validation will require a reboot of the appliance. Please ensure that other users are not in the middle of operations before continuing."

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_appliance.Name, $_Action)) 
            {

                "[{0}] {1} on appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Action, $_appliance.Name | Write-Verbose

                # Get current configuration from appliance
                Try
                {

                    $_CurrentCertValidationConfig = Send-HPOVRequest -Uri $_uri -Hostname $_appliance.name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_CurrentCertValidationConfig.certValidationConfig.'global.validateCertificate' = $true
                $_CurrentCertValidationConfig.okToReboot = $true

                if ($PSBoundParameters['CheckForSelfSignedExpiry'])
                {
        
                    $_CurrentCertValidationConfig.certValidationConfig.'global.enableExpiryCheckForSelfSignedLeafAtConnect' = $true
                    
                }

                Try
                {
                    
                    $_Resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_CurrentCertValidationConfig -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Write-Warning ('Appliance {0} is now rebooting.' -f $_appliance.Name)

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVCertificateValidation
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceCertificateValidatorUri.Clone()
        
        $_Action = 'disable certificate validation'

        Write-Warning 'Communication to devices and servers whose certificates are not validated is insecure and is subject to man-in-the-middle (MITM) attacks. Disabling certificate validation is discouraged.'

        Write-Warning "Diabling certificate validation will require a reboot of the appliance. Please ensure that other users are not in the middle of operations before continuing."

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Need to validate if two-factor authentication is enabled, as certificate validation cannot be disabled
            Try
            {

                "[{0}] Getting current appliance global authentication configuration to check for two-factor auth setting." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $_ApplianceTwoFactorConfiguration = Send-HPOVRequest -Uri $AuthnSettingsUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ApplianceTwoFactorConfiguration.twoFactorAuthenticationEnabled)
            {

                "[{0}] Two-factor auth is configured. Building ErrorRecord." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = 'Certificate validation or revocation cannot be disabled as two-factor authentication is enabled. Turn off two-factor authentication to disable certificate validation or revocation.'
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthGlobalSettingException InvalidCertValidationSetting InvalidOperation 'DisableCertVerification' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            elseif ($PSCmdlet.ShouldProcess($_appliance.Name, $_Action)) 
            {

                "[{0}] Two-factor auth is not configured." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] {1} on appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Action, $_appliance.Name | Write-Verbose

                # Get current configuration from appliance
                Try
                {

                    $_CurrentCertValidationConfig = Send-HPOVRequest -Uri $_uri -Hostname $_appliance.name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_CurrentCertValidationConfig.certValidationConfig.'global.validateCertificate' = $false
                $_CurrentCertValidationConfig.okToReboot = $true

                Try
                {
                    
                    $_Resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_CurrentCertValidationConfig -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Write-Warning ('Appliance {0} is now rebooting.' -f $_appliance.Name)

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Enable-HPOVCertificateRevocationChecking
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$SkipRevocationCheck,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$AllowExpiredCRLs,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$NotifyExpiredMissingCRLs,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceCertificateValidatorUri.Clone()

        $_Action = 'enable certificate revocation checking'

        if ($PSBoundParameters['SkipRevocationCheck'])
        {

            Write-Warning 'SkipRevocationCheck: If you have existing CA certificates associated with expired certificate revocation lists (CRL), any communication with devices or remote servers that have certificates authorized by those CAs will fail until new CRLs are uploaded for all of those CA certificates.'
            $_SkipAction = if ($SkipRevocationCheck) { 'enable' } else { 'disable' }
            $_Action += ', {0} skip CRL revocation check' -f $_SkipAction
        
        }

        if ($PSBoundParameters['AllowExpiredCRLs'])
        {

            Write-Warning 'AllowExpiredCRLs: If you have existing CA certificates associated with expired certificate revocation lists (CRL), any communication with devices or remote servers that have certificates authorized by those CAs will fail until new CRLs are uploaded for all of those CA certificates.'

            $_AllowExpiredCRLsAction = if ($AllowExpiredCRLs) { 'enable' } else { 'disable' }
            $_Action += ', {0} skip CRL revocation check' -f $_AllowExpiredCRLsAction

        }

        if ($PSBoundParameters['NotifyExpiredMissingCRLs'])
        {

            Write-Warning 'NotifyExpiredMissingCRLs: Changing notify missing or expired CRLs security setting require rebooting the appliance.'

            $_AllowNotifyExpiredCRLsAction = if ($NotifyExpiredMissingCRLs) { 'enable' } else { 'disable' }
            $_Action += ', {0} notify missing or expired CRLs' -f $_AllowNotifyExpiredCRLsAction

        }

        Write-Warning "Enabling certificate revocation checking will require a reboot of the appliance. Please ensure that other users are not in the middle of operations before continuing."

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            if ($PSCmdlet.ShouldProcess($_appliance.Name, $_Action)) 
            {

                "[{0}] {1} on appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Action, $_appliance.Name | Write-Verbose

                # Get current configuration from appliance
                Try
                {

                    $_CurrentCertValidationConfig = Send-HPOVRequest -Uri $_uri -Hostname $_appliance.name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_CurrentCertValidationConfig.certValidationConfig.'global.checkCertificateRevocation' = $true

                if ($PSBoundParameters['SkipRevocationCheck'])
                {
        
                    $_CurrentCertValidationConfig.certValidationConfig.'global.checkCertificateRevocation' = $SkipRevocationCheck
                    
                }

                if ($PSBoundParameters['AllowExpiredCRLs'])
                {
        
                    $_CurrentCertValidationConfig.certValidationConfig.'global.allow.noCRL' = $AllowExpiredCRLs
                    
                }

                if ($PSBoundParameters['NotifyExpiredMissingCRLs'])
                {
        
                    $_CurrentCertValidationConfig.certValidationConfig.'global.allow.invalidCRL' = $NotifyExpiredMissingCRLs
                    
                }

                $_CurrentCertValidationConfig.okToReboot = $true

                Try
                {
                    
                    $_Resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_CurrentCertValidationConfig -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Write-Warning ('Appliance {0} is now rebooting.' -f $_appliance.Name)

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVCertificateValidation
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
        
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
        
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {
        
        $_uri = $ApplianceCertificateValidatorUri.Clone()
        
        $_Action = 'disable certificate revocation checking'

        Write-Warning 'Communication to devices and servers whose certificates are not checked for revocation is insecure and is subject to man-in-the-middle (MITM) attack. It is strongly recommended that certificate revocation check is not turned off as it poses a serious security risk to the environment.'

        Write-Warning "Diabling certificate revocation checking will require a reboot of the appliance. Please ensure that other users are not in the middle of operations before continuing."

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Need to validate if two-factor authentication is enabled, as certificate validation cannot be disabled
            Try
            {

                "[{0}] Getting current appliance global authentication configuration to check for two-factor auth setting." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                $_ApplianceTwoFactorConfiguration = Send-HPOVRequest -Uri $AuthnSettingsUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ApplianceTwoFactorConfiguration.twoFactorAuthenticationEnabled)
            {

                "[{0}] Two-factor auth is configured. Building ErrorRecord." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = 'Certificate validation or revocation cannot be disabled as two-factor authentication is enabled. Turn off two-factor authentication to disable certificate validation or revocation.'
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.AuthGlobalSettingException InvalidCertValidationSetting InvalidOperation 'DisableCertVerification' -Message $ExceptionMessage
                $PSCmdlet.WriteError($ErrorRecord)

            }

            elseif ($PSCmdlet.ShouldProcess($_appliance.Name, $_Action)) 
            {

                "[{0}] Two-factor auth is not configured." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                "[{0}] {1} on appliance '{2}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Action, $_appliance.Name | Write-Verbose

                # Get current configuration from appliance
                Try
                {

                    $_CurrentCertValidationConfig = Send-HPOVRequest -Uri $_uri -Hostname $_appliance.name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                $_CurrentCertValidationConfig.certValidationConfig.'global.validateCertificate' = $false
                $_CurrentCertValidationConfig.okToReboot = $true

                Try
                {
                    
                    $_Resp = Send-HPOVRequest -Uri $_uri -Method PUT -Body $_CurrentCertValidationConfig -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                Write-Warning ('Appliance {0} is now rebooting.' -f $_appliance.Name)

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceTwoFactorAuthentication
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_Current2FAConfig = Send-HPOVRequest -Uri $AuthnSettingsUri -Hostname $_appliance.Name
                
                if (-not $_Current2FAConfig.emergencyLocalLoginEnabled)
                {

                    New-Object HPOneView.Appliance.Security.TwoFactorAuthConfiguration ($_Current2FAConfig.twoFactorAuthenticationEnabled,
                                                                                        $_Current2FAConfig.strictTwoFactorAuthentication,
                                                                                        $_Current2FAConfig.allowLocalLogin,
                                                                                        $_Current2FAConfig.emergencyLocalLoginEnabled,
                                                                                        'EmergencyLocalLoginDisabled',
                                                                                        $_Current2FAConfig.ApplianceConnection
                                                                                        )

                }

                else
                {

                    New-Object HPOneView.Appliance.Security.TwoFactorAuthConfiguration ($_Current2FAConfig.twoFactorAuthenticationEnabled,
                                                                                        $_Current2FAConfig.strictTwoFactorAuthentication,
                                                                                        $_Current2FAConfig.allowLocalLogin,
                                                                                        $_Current2FAConfig.emergencyLocalLoginEnabled,
                                                                                        $TwoFactorLocalLoginTypeEnum[$_Current2FAConfig.emergencyLocalLoginType],
                                                                                        $_Current2FAConfig.ApplianceConnection
                                                                                        )

                }
                
                
            
            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Disable-HPOVApplianceTwoFactorAuthentication
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                "[{0}] Getting Global Auth settings from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_CurrentAuthn2FAConfig = Send-HPOVRequest -Uri $AuthnSettingsUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSCmdlet.ShouldProcess($_appliance.Name, 'disable two factor authentication')) 
            {

                "[{0}] Will disable 2FA on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                
                $_CurrentAuthn2FAConfig.twoFactorAuthenticationEnabled = $false

                Try
                {

                    Send-HPOVRequest -Uri $AuthnSettingsUri -Method PUT -Body $_CurrentAuthn2FAConfig -Hostname $_appliance.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceTwoFactorAuthentication
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
        
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$SmartCardLoginOnly,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Bool]$EnableEmergencyLocalLogin,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('ApplianceConsoleOnly', 'NetworkAndApplianceConsole')]
        [String]$EmergencyLoginAllowType,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Array]$SubjectAlternativeNamePatterns,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$SubjectPatterns,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Array]$ValidationOids = @(@{"1.3.6.1.4.1.311.20.2.2" = "Smart Card Logon"; "1.3.6.1.5.5.7.3.2" = "Client Authentication"}),

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('Subject', 'SubjectAlternativeName', 'Issuer', 'Manual')]
        [String]$DirectoryDomainType = 'Subject',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$DirectoryDomain = 'DC=(.*)',

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }


            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }
        
    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                "[{0}] Getting Global Auth settings from appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_CurrentAuthn2FAConfig = Send-HPOVRequest -Uri $AuthnSettingsUri -Hostname $_appliance.Name

                $_Current2FALoginCertConfig = Send-HPOVRequest -Uri $Authn2FALoginCertificateConfigUri -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            "[{0}] 2FA is enabled on the appliance: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_CurrentAuthn2FAConfig.twoFactorAuthenticationEnabled.ToString() | Write-Verbose

            if (-not $_CurrentAuthn2FAConfig.twoFactorAuthenticationEnabled)
            {

                "[{0}] Will enable 2FA on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_CurrentAuthn2FAConfig.twoFactorAuthenticationEnabled = $true

            }

            switch ($PSBoundParameters.Keys)
            {

                'SmartCardLoginOnly'
                {

                    if ($SmartCardLoginOnly)
                    {

                        if ($PSCmdlet.ShouldProcess($_appliance.Name, 'enforce two factor authentication only')) 
                        {
        
                            "[{0}] Will enable 2FA on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            $_CurrentAuthn2FAConfig.twoFactorAuthenticationEnabled = $true
                            $_CurrentAuthn2FAConfig.allowLocalLogin                = $false
        
                        }

                    }

                    else
                    {

                        "[{0}] Disabling strict 2FA on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                        $_CurrentAuthn2FAConfig.twoFactorAuthenticationEnabled = $false

                    }                    

                }

                'EnableEmergencyLocalLogin'
                {

                    if ($EnableEmergencyLocalLogin)
                    {

                        "[{0}] Enable Emergency Local Login on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                        $_CurrentAuthn2FAConfig.emergencyLocalLoginEnabled = $true

                    }

                    else
                    {

                        "[{0}] Disable Emergency Local Login on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                        
                        $_CurrentAuthn2FAConfig.emergencyLocalLoginEnabled = $false

                    }                    

                }

                'EmergencyLoginAllowType'
                {

                    switch ($EmergencyLoginAllowType)
                    {

                        'APPLIANCECONSOLEONLY'
                        {

                            "[{0}] Enable Emergency Local Login via console only on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            $_CurrentAuthn2FAConfig.emergencyLocalLoginType = $TwoFactorLocalLoginTypeEnum['APPLIANCECONSOLEONLY']

                        }

                        'NETWORKANDAPPLIANCECONSOLE'
                        {

                            "[{0}] Enable Emergency Local Login via console only on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
                            
                            $_CurrentAuthn2FAConfig.emergencyLocalLoginType = $TwoFactorLocalLoginTypeEnum['NETWORKANDAPPLIANCECONSOLE']

                        }

                    }

                }

                'SubjectAlternativeNamePatterns'
                {

                    "[{0}] Setting SAN pattern values on the appliance to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', $SubjectAlternativeNamePatterns.ToArray()) | Write-Verbose

                    $_Current2FALoginCertConfig.subjectAlternateNamePatterns = [String]::Join(', ', $SubjectAlternativeNamePatterns.ToArray())

                }

                'SubjectPatterns'
                {

                    "[{0}] Setting SAN pattern values on the appliance to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', $SubjectPatterns.ToArray()) | Write-Verbose

                    $_Current2FALoginCertConfig.subjectPatterns = [String]::Join(', ', $SubjectPatterns.ToArray())

                }

                'DirectoryDomainType'
                {

                    "[{0}] Setting DirectoryDomainType on the appliance to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DirectoryDomainType | Write-Verbose

                    $_Current2FALoginCertConfig.certificateDomainIdentifier = $DirectoryDomainType

                }

                'ValidationOids'
                {

                    $_ValidationOids = [System.Collections.ArrayList]::new()

                    ForEach ($e in $ValidationOids)
                    {

                        [void]$_ValidationOids.Add($e)
                        
                    }

                    "[{0}] Setting ValidationOids on the appliance to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), [String]::Join(', ', $_ValidationOids.ToArray()) | Write-Verbose
                    
                    $_Current2FALoginCertConfig.validationOids = $_ValidationOids

                }

                'DirectoryDomain'
                {

                    "[{0}] Setting Directory Domain Identifier Pattern on the appliance to {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $DirectoryDomain | Write-Verbose

                    $_Current2FALoginCertConfig.certificateDomainIdentifierPattern = $DirectoryDomain

                }

            }

            # Update Appliance Authn Glboal Settings

            Try
            {

                Send-HPOVRequest -Uri $AuthnSettingsUri -Method PUT -Body $_CurrentAuthn2FAConfig -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Update LoginCertificateConfigDto
            
            Try
            {

                Send-HPOVRequest -Uri $Authn2FALoginCertificateConfigUri -Method PUT -Body $_Current2FALoginCertConfig -Hostname $_appliance.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)
                
            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceAvailableSecurityMode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateSet ('Legacy', 'FIPS', 'CNSA')]
        [String[]]$ModeName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if (-not $PSBoundParameters['ModeName'])
        {

            $ModeName = 'Legacy', 'FIPS', 'CNSA'

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            ForEach ($_modeName in $ModeName)
            {

                $_uri = '{0}/{1}' -f $ApplianceSecurityModesUri, $_modeName

                Try
                {

                    $_SecurityMode = Send-HPOVRequest -Uri $_uri -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                New-Object HPOneView.Appliance.SecurityMode ($_SecurityMode.modeName, 
                                                             $_SecurityMode.currentMode, 
                                                             $_SecurityMode.ApplianceConnection)

            }            

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceCurrentSecurityMode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    param
    (

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_CollectionName = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_uri = '{0}' -f $ApplianceCurrentSecurityModeUri

            Try
            {

                $_SecurityMode = Send-HPOVRequest -Uri $_uri -ApplianceConnection $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            New-Object HPOneView.Appliance.SecurityMode ($_SecurityMode.modeName, 
                                                         $_SecurityMode.currentMode, 
                                                         $_SecurityMode.ApplianceConnection)            

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceCurrentSecurityMode
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High' )]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [HPOneView.Appliance.SecurityMode]$SecurityMode,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_CollectionName = [System.Collections.ArrayList]::new()

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Switch ($SecurityMode.ModeName)
            {

                'FIPS'
                {

                    Write-Warning 'While in FIPS cryptography mode, the appliance uses strong cryptographic protocols and ciphers for all internal and external configuration and communications as defined by the FIPS standard.'

                }

                'CNSA'
                {

                    Write-Warning 'While in CNSA cryptography mode, the appliance uses strong cryptographic protocols and ciphers for all internal and external configuration and communications as defined by the CNSA standard.'

                }

            }

            Write-Host ""
            Write-Warning "Changing the cryptography mode will generate new appliance certificates if the current certificates are self-signed and are not compatible with the new cryptography mode. Any externally signed appliance certificates will need to be re-imported by the user before changing the mode.`r`n`r`nIt is extremely important to create and review the compatibility report for the new cryptography mode before proceeding. Not doing so could result in disruptions to the normal operation of the appliance. Cancel this operation and review the report if you have not already done so."

            $_uri = '{0}' -f $ApplianceCurrentSecurityModeUri

            $_Body = @{
                modeName = $SecurityMode.ModeName
            }

            $_Message = 'change appliance active security mode to "{0}"' -f $SecurityMode.ModeName

            if ($PSCmdlet.ShouldProcess($_appliance, $_Message))
            {

                Try
                {

                    Send-HPOVRequest -Uri $_uri -Method PUT -Body $_Body -ApplianceConnection $_appliance | Wait-HPOVTaskComplete -ApplianceWillReboot

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVApplianceSecurityProtocol
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol]], ParameterSetName = "Default")]
    param
    (

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ('TLSv1', 'TLSv1.1', 'TLSv1.2')]
        [String[]]$TlsVersion,

        [Parameter (ParameterSetName = 'Default', Mandatory = $false)]
        [ValidateSet ('Legacy', 'FIPS', 'CNSA')]
        [String[]]$SecurityMode,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject']))
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        if (-not $PSBoundParameters['TlsVersion'])
        {

            $TlsVersion = 'TLSv1', 'TLSv1.1', 'TLSv1.2'
    
        }

        $_ApplianceProtocolsCollection = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol]'

    }

    Process
    {        

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # need to get the current security mode
            try
            {

                $_CurrentSecurityMode = Send-HPOVRequest -Uri $ApplianceCurrentSecurityModeUri -Hostname $_appliance

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_TlsVersion in $TlsVersion)
            {

                $_uri = '{0}/{1}' -f $ApplianceSecurityProtocolsUri, $_TlsVersion.Replace('tls','TLS')

                if ($PSBoundParameters['SecurityMode'])
                {

                    ForEach ($_SecurityMode in $SecurityMode)
                    {

                        $_CipherSuitesCol = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol+CipherSuite]'

                        $__uri = '{0}?mode={1}' -f $_uri, $_SecurityMode

                        try
                        {

                            $_SecurityProtocolWithMode = Send-HPOVRequest -Uri $__uri -Hostname $_appliance

                        }

                        catch
                        {

                            $PSCmdlet.ThrowTerminatingError($_)

                        }

                        ForEach ($_cipherSuite in $_SecurityProtocolWithMode.cipherSuites)
                        {

                            $_CipherSuite = New-Object HPOneView.Appliance.SecurityProtocol+CipherSuite($_cipherSuite.cipherSuiteName, $_cipherSuite.enabled)
                            $_CipherSuitesCol.Add($_CipherSuite)

                        }

                        $_Protocol = New-Object HPOneView.Appliance.SecurityProtocol($_SecurityProtocolWithMode.protocolName,
                                                                                     $_CipherSuitesCol, 
                                                                                     $_SecurityProtocolWithMode.category,
                                                                                     $_SecurityMode,
                                                                                     ($_CurrentSecurityMode.ModeName -eq $_SecurityMode),
                                                                                     $_SecurityProtocolWithMode.enabled,
                                                                                     $_SecurityProtocolWithMode.ApplianceConnection)

                        $_ApplianceProtocolsCollection.Add($_Protocol)

                    }

                }

                else
                {

                    $_CipherSuitesCol = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol+CipherSuite]'

                    try
                    {

                        $_ApplianceSecurityProtocols = Send-HPOVRequest -Uri ($_uri + "?mode=$($_CurrentSecurityMode.modeName)") -Hostname $_appliance

                    }

                    catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                    ForEach ($_SecurityProtocol in $_ApplianceSecurityProtocols)
                    {

                        ForEach ($_cipherSuite in $_SecurityProtocol.cipherSuites)
                        {

                            $_CipherSuite = New-Object HPOneView.Appliance.SecurityProtocol+CipherSuite($_cipherSuite.cipherSuiteName, $_cipherSuite.enabled)
                            $_CipherSuitesCol.Add($_CipherSuite)

                        }

                        $_Protocol = New-Object HPOneView.Appliance.SecurityProtocol($_SecurityProtocol.protocolName,
                                                                        $_CipherSuitesCol, 
                                                                        $_SecurityProtocol.category,
                                                                        $_CurrentSecurityMode.modeName,
                                                                        $True,
                                                                        $_SecurityProtocol.enabled,
                                                                        $_SecurityProtocol.ApplianceConnection)

                        $_ApplianceProtocolsCollection.Add($_Protocol)

                    }                    

                }

            }

        }        

    }

    end
    {

        $_ApplianceProtocolsCollection | Sort-Object Mode        

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Set-HPOVApplianceSecurityProtocol
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol]], ParameterSetName = "Default")]
    param
    (

        [Parameter (ParameterSetName = 'Default', Mandatory)]
        [ValidateSet ('TLSv1', 'TLSv1.1', 'TLSv1.2')]
        [String[]]$EnableTlsVersion,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not($ConnectedSessions))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
            {

                Try
                {

                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try
            {

                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException]
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SecurityProtocolsToSet = NewObject -ApplianceSecurityProtocols

        ForEach ($_Protocol in $EnableTlsVersion)
        {

            "[{0}] Will enable '{1}' security protocol." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Protocol | Write-Verbose

            ($_SecurityProtocolsToSet | Where-Object protocolName -eq $_Protocol).enabled = $true

        }

        $_ApplianceProtocolsCollection = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.SecurityProtocol]'

    }

    Process
    {        

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_WaitedFoReboot = $false

            "[{0}] Processing appliance {1} (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Write-Warning "Changing the appliance security protocol(s) will immediately reboot the appliance."

            $_ShouldProcessMessage = "enable only '{0}' security protocol(s)" -f [String]::Join("','", $EnableTlsVersion)

            if ($PSCmdlet.ShouldProcess($_appliance, $_ShouldProcessMessage))
            {

                try
                {

                    $_CurrentSecurityMode = Send-HPOVRequest -Uri $ApplianceSecurityProtocolsUri -Method PUT -Body $_SecurityProtocolsToSet -Hostname $_appliance

                }

                catch
                {

                    # Appliance has likely rebooted.
                    if ($_.Exception.Message -match 'The operation has timed out' -or $_.Exception.Message -match 'An unexpected error occurred on a receive')
                    {

                        Write-Warning "Appliance has now started to reboot."

                        # Lets wait 10 minutes for appliance to reboot. Waiting less time may cause excessive timeout issues waiting for heavily loaded appliance from rebooting in time.
                        Wait-Reboot

                        $_WaitedFoReboot = $true

                    }

                    else
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                try
                {

                    # In case the appliance didn't reboot in time and cause the operation timed out exception
                    if (-not $_WaitedFoReboot)
                    {

                        Wait-Reboot

                    }                    

                    Get-HPOVApplianceSecurityProtocol -ApplianceConnection $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }        

    }

    end
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Show-HPOVApplianceSecurityModeCompatibilityReport
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    [OutputType([HPOneView.Appliance.SecurityModeCompatibilityReport], ParameterSetName="Default")]
    param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [HPOneView.Appliance.SecurityMode]$TargetSecurityMode,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$UpdateReport,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = ($ConnectedSessions | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(),($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not $PSBoundParameters['TargetSecurityMode'])
        {

            $Pipelineinput = $True

        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not($ConnectedSessions))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -gt $ApplianceConnection.Count; $c++)
                {

                    Try
                    {

                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException]
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try
                {

                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException]
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        function GenerateCompatabilityReport
        {

            [CmdletBinding (DefaultParameterSetName = 'Default')]
            param
            (

                [Parameter (Mandatory, ParameterSetName = 'Default', Position = 0)]
                [ValidateNotNullOrEmpty()]
                [HPOneView.Appliance.SecurityMode]$_CurrentMode,

                [Parameter (Mandatory, ParameterSetName = 'Default', Position = 1)]
                [ValidateNotNullOrEmpty()]
                [HPOneView.Appliance.SecurityMode]$_TargetMode,

                [Parameter (Mandatory, ParameterSetName = 'Default', Position = 2)]
                [ValidateNotNullOrEmpty()]
                [Alias ('Appliance')]
                [HPOneView.Appliance.Connection]$_ApplianceConnection,

                [Parameter (Mandatory = $false, ParameterSetName = 'Default', Position = 3)]
                [Switch]$UpdateReport

            )

            Try
            {

                $_GenerateCompatabilityReport = NewObject -SecurityModeCompatabilityReport
                $_GenerateCompatabilityReport.currentMode = $_CurrentMode.ModeName
                $_GenerateCompatabilityReport.targetMode  = $_TargetMode.ModeName

                $_Uri = $ApplianceSecurityModeCompatibiltyReportUri.Clone()

                if ($UpdateReport.IsPresent)
                {

                    $_Uri += "?force=true"

                }

                Send-HPOVRequest -Uri $_Uri -Method POST -Body $_GenerateCompatabilityReport -Hostname $_ApplianceConnection | Wait-HPOVTaskComplete | Out-Null

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        # Get current security mode
        '[{0}] Getting current appliance security mode.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Try
        {

            $_CurrentApplianceSecurityMode = Get-HPOVApplianceCurrentSecurityMode -ApplianceConnection $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        # If current matches target, generate error saying mode already set
        if ($_CurrentApplianceSecurityMode.ModeName -eq $TargetSecurityMode.ModeName)
        {

            '[{0}] Appliance is already at the requested appliance security mode: {1}' -f $MyInvocation.InvocationName.ToString().ToUpper(), $TargetSecurityMode.ModeName | Write-Verbose

            $ExceptionMessage = "The appliance is already at the requested '{0}' security mode." -f $TargetSecurityMode.ModeName
            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ApplianceSecurityModeException ApplianceAlreadySetToSecurityMode ResourceExists "ApplianceConnection" -Message $ExceptionMessage
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            # Regenerate report
            if ($UpdateReport.IsPresent)
            {

                '[{0}] Refreshing the security mode compatability report.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {                    

                    GenerateCompatabilityReport $_CurrentApplianceSecurityMode $TargetSecurityMode $ApplianceConnection $UpdateReport.IsPresent

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            # Get supported security protocols for security mode
            Try
            {

                $_SupportedSecurityProtocolsFromMode = Get-HPOVApplianceSecurityProtocol -SecurityMode $TargetSecurityMode.ModeName -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Check to see if a report exists, if not, generate it
            Try
            {

                $_Report = Send-HPOVRequest -Uri $ApplianceSecurityModeCompatibiltyReportUri -Hostname $ApplianceConnection

                '[{0}] Report exists on appliance. Generating the security mode compatability report.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            Catch [HPOneview.ResourceNotFoundException]
            {

                '[{0}] Report does not exist. Creating the security mode compatability report.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {
                
                    GenerateCompatabilityReport $_CurrentApplianceSecurityMode $TargetSecurityMode $ApplianceConnection

                    '[{0}] Report created. Retrieving details.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_Report = Send-HPOVRequest -Uri $ApplianceSecurityModeCompatibiltyReportUri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Build report
            Try
            {

                '[{0}] Building compatibility report object(s).' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_externalServers = New-Object "System.Collections.Generic.List[HPOneView.Appliance.SecurityModeCompatibilityReport+ExternalServer]"

                ForEach ($_ExternalCert in ($_Report.members | Where-Object { $_.reportSection.sectionKey -eq 'EXTERNALCERTIFICATE'}))
                {

                    $_ExternalCompatbilityDetails = New-Object "System.Collections.Generic.List[HPOneView.Appliance.SecurityModeCompatibilityReport+CompapatibilityDetail]"

                    ForEach ($_CompatDetail in $_ExternalCert.nonCompatibilityDetails)
                    {

                        $_CompapatibilityDetail = New-Object HPOneView.Appliance.SecurityModeCompatibilityReport+CompapatibilityDetail ($_CompatDetail.nonCompatibilityKey, $_CompatDetail.nonCompatibilityAction)
                        $_ExternalCompatbilityDetails.Add($_CompapatibilityDetail)

                    }

                    $_externalServer = New-Object HPOneView.Appliance.SecurityModeCompatibilityReport+ExternalServer ($_ExternalCert.deviceName, 
                                                                                                                      $_ExternalCert.deviceType, 
                                                                                                                      $_ExternalCert.deviceUri, 
                                                                                                                      $_ExternalCompatbilityDetails, 
                                                                                                                      $_ExternalCert.ApplianceConnection)

                    $_externalServers.Add($_externalServer)
                    
                }

                $_managedDevices = New-Object "System.Collections.Generic.List[HPOneView.Appliance.SecurityModeCompatibilityReport+ManagedDevice]"

                ForEach ($_managedDevice in ($_Report.members | Where-Object { $_.reportSection.sectionKey -eq 'MANAGEDDEVICE'}))
                {

                    $_ManagedDeviceCompatbilityDetails = New-Object "System.Collections.Generic.List[HPOneView.Appliance.SecurityModeCompatibilityReport+CompapatibilityDetail]"

                    ForEach ($_CompatDetail in $_managedDevice.nonCompatibilityDetails)
                    {

                        $_CompapatibilityDetail = New-Object HPOneView.Appliance.SecurityModeCompatibilityReport+CompapatibilityDetail ($_CompatDetail.nonCompatibilityKey, $_CompatDetail.nonCompatibilityAction)
                        $_ManagedDeviceCompatbilityDetails.Add($_CompapatibilityDetail)

                    }

                    $_externalServer = New-Object HPOneView.Appliance.SecurityModeCompatibilityReport+ManagedDevice ($_managedDevice.deviceName, 
                                                                                                                     $_managedDevice.deviceType, 
                                                                                                                     $_managedDevice.deviceUri, 
                                                                                                                     $_ManagedDeviceCompatbilityDetails, 
                                                                                                                     $_managedDevice.ApplianceConnection)

                    $_managedDevices.Add($_externalServer)

                }

                $_applianceCerificates = New-Object "System.Collections.Generic.List[HPOneView.Appliance.SecurityModeCompatibilityReport+ApplianceCerificate]"

                ForEach ($_ApplianceCert in ($_Report.members | Where-Object { $_.reportSection.sectionKey -eq 'APPLIANCECERTIFICATE'}))
                {

                    $_ApplianceCertCompatbilityDetails = New-Object "System.Collections.Generic.List[HPOneView.Appliance.SecurityModeCompatibilityReport+CompapatibilityDetail]"

                    ForEach ($_CompatDetail in $_ApplianceCert.nonCompatibilityDetails)
                    {

                        $_CompapatibilityDetail = New-Object HPOneView.Appliance.SecurityModeCompatibilityReport+CompapatibilityDetail ($_CompatDetail.nonCompatibilityKey, $_CompatDetail.nonCompatibilityAction)
                        $_ApplianceCertCompatbilityDetails.Add($_CompapatibilityDetail)

                    }

                    $_applianceCerificate = New-Object HPOneView.Appliance.SecurityModeCompatibilityReport+ApplianceCerificate ($_ApplianceCert.deviceName, 
                                                                                                                                $_ApplianceCert.deviceType, 
                                                                                                                                $_ApplianceCert.deviceUri, 
                                                                                                                                $_ApplianceCertCompatbilityDetails, 
                                                                                                                                $_ApplianceCert.ApplianceConnection)

                    $_applianceCerificates.Add($_applianceCerificate)

                }

                New-Object HPOneView.Appliance.SecurityModeCompatibilityReport ($TargetSecurityMode.ModeName, 
                                                                                $_Report.created, 
                                                                                $_SupportedSecurityProtocolsFromMode, 
                                                                                $_applianceCerificates, 
                                                                                $_externalServers, 
                                                                                $_managedDevices, 
                                                                                $_Report.ApplianceConnection)

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

#######################################################
# Alerts & Events:
#

function Get-HPOVAlert 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $False, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('resourceUri','Resource')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('OK', 'Critical', 'Disabled', 'Warning', 'Unknown')]
        [String]$Severity,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('Appliance', 'DeviceBay', 'Enclosure', 'Fan', 'Firmware', 'Host', 'Instance', 'InterconnectBay', 'LogicalSwitch', 'Logs', 'ManagementProcessor', 'Memory', 'Network', 'Operational', 'Power', 'Processor', 'RemoteSupport', 'Storage', 'Thermal', 'Unknown')]
        [String]$HealthCategory,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$AssignedToUser,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('State')]
        [ValidateNotNullOrEmpty()]
        [String]$AlertState,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Int]$Count = 0,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [TimeSpan]$TimeSpan,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$Start,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$End = [DateTime]::Now,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'ResourcePipeline') 
        { 
            
            $Pipelineinput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_AlertResources = [System.Collections.ArrayList]::new()

        if (-not $Count)
        {

            $Count = -1

        }

    }
    
    Process 
    {

        $_uri = "{0}?sort:asc" -f $IndexUri

        $_Query = [System.Collections.ArrayList]::new()
        [void]$_Query.Add("category:alerts")

        If ($Pipelineinput -or $InputObject -is [PSCustomObject])
        {

            "[{0}] Processing InputObject from pipeline: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Pipelineinput | Write-Verbose

            # Check what type of resource is being provided
            switch ($InputObject.category)
            {

                { $ResourceCategoryEnum.ServerHardware, `
                    $ResourceCategoryEnum.Enclosure, `
                    $ResourceCategoryEnum.ServerProfile, `
                    $ResourceCategoryEnum.Interconnect, `
                    $ResourceCategoryEnum.Baseline -contains $_ }
                {

                    "[{0}] Processing '{1}' resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ | Write-Verbose

                    [void]$_Query.Add(("resourceUri:'{0}'" -f $InputObject.uri))

                }

                default
                {

                    $ExceptionMessage = 'The provided object {0} is not supported. Only Server Hardware, Server Profile and Enclosure are supported resources.' -f $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            # Generate error if ApplianceConnection properties do not match
            if ($InputObject -and $InputObject.ApplianceConnection.Name -ne $ApplianceConnection.Name)
            {

                $ExceptionMessage = "The provided input object '{0}' 'ApplianceConnection' NoteProperty ({1}) does notmatch the Appliance Connection." -f $InputObject.ApplianceConnection, $ApplianceConnection
                $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException ApplianceConnetionDoesNotMatchObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        if ($PSBoundParameters['Count'])
        {

            $_uri = "{0}&count={1}" -f $_uri, $Count

        }

        # Needs to be a filter statement in URI. NEED TO ADD TO GET-HPOVALERT FOR ITS TIMESPAN PARAMETER
        if ($TimeSpan)
        {

            $_uri = '{0}&filter="created > {1}"' -f $_uri, ([DateTime]::Now - $timespan).ToString("yyyy-MM-ddTHH:mm:ss:ff.fffZ")

        }

        elseif ($Start)
        {

            $_uri = '{0}&filter="created > {1}"&filter="created < {2}"' -f $_uri, $Start.ToString("yyyy-MM-ddTHH:mm:ss:ff.fffZ"), $End.ToString("yyyy-MM-ddTHH:mm:ss:ff.fffZ")

        }
    
        if ($PSBoundParameters['Severity']) 
        { 
            
            [Void]$_Query.Add(("severity='{0}'" -f $Severity))
        
        }
    
        if ($PSBoundParameters['HealthCategory']) 
        {
            
            [Void]$_Query.Add(("healthCategory:'{0}'" -f $HealthCategory))
        
        }
    
        if ($PSBoundParameters['AssignedToUser']) 
        { 
            
            [Void]$_Query.Add(("Owner:'{0}'" -f $AssignedToUser))
        
        }
    
        if ($PSBoundParameters['AlertState']) 
        { 
            
            [Void]$_Query.Add(("state='{0}'" -f ($AlertState.SubString(0,1).ToUpper() + $AlertState.SubString(1).tolower())))
        
        }

        $_uri = '{0}&query="{1}"' -f $_uri, [String]::Join(' AND ',$_Query.ToArray())

        "[{0}] URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uri | Write-Verbose

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $_ResourceAlerts = Get-AllIndexResources -Uri $_uri -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
        
            $_ResourceAlerts | ForEach-Object { 
                
                $_.PSObject.TypeNames.Insert(0,"HPOneView.Alert")

                [void]$_AlertResources.Add($_)
            
            }

        }

    }

    End 
    {

        Return $_AlertResources

    }

}

function Get-HPOVServiceAlert
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $False, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('Open', 'Closed', 'Pending', 'Received', 'Submitted', 'Error')]
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Int]$Count = 0,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [TimeSpan]$TimeSpan,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$Start,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [DateTime]$End = [DateTime]::Now,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'ResourcePipeline') 
        { 
            
            $Pipelineinput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_AlertResources = [System.Collections.ArrayList]::new()

        if (-not $Count)
        {

            $Count = -1

        }

    }
    
    Process 
    {

        $_uri = "{0}?sort:asc" -f $IndexUri

        $_Query = [System.Collections.ArrayList]::new()
        [void]$_Query.Add("category:alerts AND healthCategory:RemoteSupport AND ServiceEventSource:True AND NOT description:'Service Test Event'")

        If ($Pipelineinput -or $InputObject -is [PSCustomObject])
        {

            "[{0}] Processing InputObject from pipeline: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Pipelineinput | Write-Verbose

            # Check what type of resource is being provided
            switch ($InputObject.category)
            {

                { $ResourceCategoryEnum.ServerHardware, $ResourceCategoryEnum.Enclosure -contains $_ }
                {

                    "[{0}] Processing '{1}' resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ | Write-Verbose

                    if (-not (ValidateRemoteSupport -InputObject $InputObject))
                    {

                        $ExceptionMessage = "The resource {0} is not configured for Remote Support or does not support Remote Support." -f $InputObject.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    else
                    {

                        "[{0}] Remote Support is enabled." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ | Write-Verbose

                    }

                    [void]$_Query.Add(("resourceUri:'{0}'" -f $InputObject.uri))

                }

                $ResourceCategoryEnum.ServerProfile
                {

                    "[{0}] Processing '{1}' resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ | Write-Verbose

                    if (-not (ValidateRemoteSupport -InputObject $InputObject))
                    {

                        $ExceptionMessage = "The resource {0} is not configured for Remote Support or does not support Remote Support." -f $InputObject.Name
                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.RemoteSupportResourceException InvalidResourceObject InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    else
                    {

                        "[{0}] Remote Support is enabled." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_ | Write-Verbose

                    }

                    if ($null -eq $InputObject.serverHardwareUri)
                    {

                        $ExceptionMessage = 'The provided server profile object {0} is not assigned to a server hardware resource.' -f $InputObject.name
                        $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    [void]$_Query.Add(("resourceUri:'{0}'" -f $InputObject.serverHardwareUri))

                }

                default
                {

                    $ExceptionMessage = 'The provided object {0} is not supported. Only Server Hardware, Server Profile and Enclosure are supported resources.' -f $InputObject.name
                    $ErrorRecord = New-ErrorRecord HPOneview.InputObjectResourceException InvalidInputObjectResource InvalidArgument "InputObject" -TargetType 'PSObject' -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

            }

            # Generate error if ApplianceConnection properties do not match
            if ($InputObject -and $InputObject.ApplianceConnection.Name -ne $ApplianceConnection.Name)
            {

                $ExceptionMessage = "The provided input object '{0}' 'ApplianceConnection' NoteProperty ({1}) does notmatch the Appliance Connection." -f $InputObject.ApplianceConnection, $ApplianceConnection
                $ErrorRecord = New-ErrorRecord HPOneView.InputObjectResourceException ApplianceConnetionDoesNotMatchObject InvalidArgument 'InputObject' -TargetType 'PSObject' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

        if ($PSBoundParameters['Count'])
        {

            $_uri = "{0}&count={1}" -f $_uri, $Count

        }

        # Needs to be a filter statement in URI. NEED TO ADD TO GET-HPOVALERT FOR ITS TIMESPAN PARAMETER
        if ($TimeSpan)
        {

            $_uri = '{0}&filter="created > {1}"' -f $_uri, ([DateTime]::Now - $timespan).ToString("yyyy-MM-ddTHH:mm:ss:ff.fffZ")

        }

        elseif ($Start)
        {

            $_uri = '{0}&filter="created > {1}"&filter="created < {2}"' -f $_uri, $Start.ToString("yyyy-MM-ddTHH:mm:ss:ff.fffZ"), $End.ToString("yyyy-MM-ddTHH:mm:ss:ff.fffZ")

        }
    
        if ($PSBoundParameters['State']) 
        { 

            [void]$_Query.Add(("remoteSupportState:{0}" -f $State))

        }

        $_uri = '{0}&query="{1}"' -f $_uri, [String]::Join(' AND ',$_Query.ToArray())

        "[{0}] URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_uri | Write-Verbose

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            # Check if the appliance has remote support enabled. Exception if not.
            $_RemoteSupportStatus = $null

            "[{0}] Validate Remote Support is configured on the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_RemoteSupportStatus = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not $_RemoteSupportStatus.enableRemoteSupport)
            {

                "[{0}] Remote Support is not enabled and configured on the appliance. Generate non-terminating error." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $ExceptionMessage = 'Remote Support is not configured on the appliance, {0}. In order to set the Remote Support location for the DataCenter, Remote SUpport must be enabledon the appliance. Either enable Remote Support or do not attempt to set the Data Center location until Remote Support has been anabled on the appliance.' -f $ApplianceConnection.Name
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.RemoteSupportException RemoteSupportNotEnabled InvalidOperation 'ApplianceConnect' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Try
            {

                $_ResourceAlerts = Get-AllIndexResources -Uri $_uri -ApplianceConnection $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_alert in $_ResourceAlerts)
            {

                # Get resource serial number to add to object
                Try
                {

                    $_associatedresource = Send-HPOVRequest -Uri $_alert.associatedResource.resourceUri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                New-Object HPOneView.Appliance.ServiceAlert($_alert.serviceEventDetails.caseID,
                                                            $_alert.associatedResource.resourceName,
                                                            $_associatedresource.serialNumber,
                                                            $_alert.serviceEventDetails.remoteSupportState,
                                                            $_alert.description,
                                                            $_alert.correctiveAction,
                                                            $_alert.created,
                                                            $_alert.modified,
                                                            $_alert.resourceUri,
                                                            $_alert.uri,
                                                            $_alert.ApplianceConnection)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function ValidateRemoteSupport
{

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = $InputObject.ApplianceConnection
    
    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

    }

    Process
    {

        "[{0}] Resource name: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose
        "[{0}] Resource uri: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose
        "[{0}] Resource supportState: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.supportState | Write-Verbose

        if ($InputObject.supportState -eq 'Enabled')
        {

            return $true

        }

        else
        {

            return $false

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
        
    }
}

Function Get-HPOVServerProfileMessage
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $False, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$ServerProfile,
        
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if ($PSCmdlet.ParameterSetName -eq 'ResourcePipeline') 
        { 
            
            $Pipelineinput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }
        
        $_AlertResources = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        # Input object is a Server Profile resource, get special alerts URI
        if ($ServerProfile.category -eq $ResourceCategoryEnum.ServerProfile) 
        {
        
            "[{0}] Input object is a Server Profile. Getting special URI for alert messages." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            Try
            {

                [Array]$_serverAlerts = Send-HPOVRequest ($InputObject.uri + "/messages") -Hostname $InputObject.ApplianceConnection.Name

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
                
            "[{0}] Processing {1} Server Profile messages." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_serverAlerts.Count | Write-Verbose

            foreach ($_alert in $_serverAlerts) 
            {

                switch ($_alert.PSObject.Properties.Name) 
                {

                    "connections" 
                    { 
                            
                        if ($_alert.connections.count -gt 0) 
                        { 

                            "[{0}] Processing {1} Server Profile 'Connections' messages." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_alert.connections.count | Write-Verbose
                                
                            $_alert.connections.messages | ForEach-Object { 
                                    
                                $_.PSObject.TypeNames.Insert(0,"HPOneView.ServerProfileMessage")

                                Add-Member -InputObject $_ -NotePropertyName ServerProfileName -NotePropertyValue $InputObject.name

                                [void]$_AlertResources.Add($_)
                                
                            }

                        } 
                        
                    }

                    "serverHardware" 
                    { 
                            
                        if ($_alert.serverHardware.count -gt 0) 
                        {

                            "[{0}] Processing {1} Server Profile 'ServerHardware' messages." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_alert.serverHardware.count | Write-Verbose

                            $_alert.serverHardware.messages | ForEach-Object { 
                                    
                                $_.PSObject.TypeNames.Insert(0,"HPOneView.ServerProfileMessage")

                                Add-Member -InputObject $_ -NotePropertyName ServerProfileName -NotePropertyValue $InputObject.name

                                [void]$_AlertResources.Add($_)
                                
                            }
                            
                        } 
                        
                    }
                        
                    "firmwareStatus" 
                    { 
                            
                        if ($_alert.firmwareStatus.count -gt 0) 
                        { 

                            "[{0}] Processing {1} Server Profile 'FirmwareStatus' messages." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_alert.firmwareStatus.count | Write-Verbose
                                
                            $_alert.firmwareStatus.messages | ForEach-Object { 
                                    
                                $_.PSObject.TypeNames.Insert(0,"HPOneView.ServerProfileMessage")

                                Add-Member -InputObject $_ -NotePropertyName ServerProfileName -NotePropertyValue $InputObject.name

                                [void]$_AlertResources.Add($_)
                                
                            }
                            
                        } 
                        
                    }
                
                }

            }

        }

        else 
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidAlertObject InvalidArgument  "ServerProfile" -TargetType 'PSObject' -Message ("An invalid object was provided, {0}. Only Server Profile objects are supported." -f $ServerProfile.category)
            $PSCmdlet.WriteError($ErrorRecord)

        }

    }

    End 
    {

        Return $_AlertResources

    }

}

function Set-HPOVAlert
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Cleared')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Active')]
        [ValidateNotNullOrEmpty()]
        [Alias ('alertUri','Alert')]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$AssignToUser,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Notes,

        [Parameter (Mandatory, ParameterSetName = 'Cleared')]
        [Switch]$Cleared,

        [Parameter (Mandatory, ParameterSetName = 'Active')]
        [Switch]$Active,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Cleared')]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Active')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            "[{0}] Alert Object via pipeline" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            $Pipelineinput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_AlertResources = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        # Validate input object is correct
        if ($InputObject.category -ne 'alerts')
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidAlertObject InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message 'The Alert Parameter value is not a PSCustomObject or contains a valid resource category. Please check the value and try again.'
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            $_AlertUpdateObject = NewObject -UpdateAlert

            if (-not $PSBoundParameters['Notes'])
            {

                $_AlertUpdateObject.notes = 'Updated alert with: {0}' -f (($PSBoundParameters.Keys | Where-Object { 'Cleared','Active','AssignToUser' -contains $_ } | ForEach-Object { "{0} ({1})" -f $_,$PSBoundParameters[$_] } )-Join ", ")

            }

            switch ($PSBoundParameters.keys)
            {

                'Cleared'
                {

                    $_AlertUpdateObject.alertState = 'Cleared'

                }

                'Active'
                {

                    $_AlertUpdateObject.alertState = 'Active'

                }

                'AssignToUser'
                {

                    $_AlertUpdateObject.assignedToUser = $AssignToUser

                }

                'Notes'
                {
                
                    $_AlertUpdateObject.notes = $Notes
                
                }

            }

            if ((-not $PSboundParameters['Cleared']) -and (-not $PSboundParameters['Active']))
            {

                $_AlertUpdateObject.alertState = $InputObject.alertState

            }

            if (-not($InputObject.ApplianceConnection.Name) -and -not($ApplianceConnection))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidAlertObject InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message 'The Alert Parameter value does not contain a valid ApplianceConnection property. Please check the value and try again.'
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            if ($InputObject.alertState -eq 'Locked' -and ($PSboundParameters['Cleared'] -or $PSboundParameters['Active']))
            {

                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidAlertState InvalidOperation 'InputObject' -TargetType $InputObject.GetType().Name -Message "The Alert provided is a Locked alert and it's state cannot be modified."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Try
            {

                if ($InputObject.eTag)
                {

                    $_AlertUpdateObject.eTag = $InputObject.eTag

                }

                $_resp = Send-HPOVRequest -Uri $InputObject.uri -Method PUT -Body $_AlertUpdateObject -Hostname $ApplianceConnection.Name
            
                $_resp.PSObject.TypeNames.Insert(0,"HPOneView.Alert")

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }        

            [void]$_AlertResources.Add($_resp)

        }

    }

    End
    {        

        return $_AlertResources

    }

}

function Clear-HPOVAlert  
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    ()

    Write-Warning 'This CMDLET is deprecated. Please use Set-HPOVAlert.'

}

function Remove-HPOVAlert
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [Switch]$Force,
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            

            $Pipelineinput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }


    }

    Process 
    {

        # Validate input object is correct
        if ($InputObject.category -ne 'alerts')
        {

            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidAlertObject InvalidArgument 'InputObject' -TargetType $InputObject.GetType().Name -Message 'The Alert Parameter value is not a PSCustomObject or contains a valid resource category. Please check the value and try again.'
            $PSCmdlet.WriteError($ErrorRecord)

        }

        else
        {

            $RemoveMessage = "remove '{0}' alert" -f $InputObject.description

            if ($PSCmdlet.ShouldProcess($InputObject.ApplianceConnection.Name, $RemoveMessage))
            {

                "[{0}] Removing alert: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($InputObject | Out-String) | Write-Verbose
                "[{0}] URI: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.uri | Write-Verbose

                $_Uri = '{0}' -f $InputObject.uri

                if ($Force)
                {

                    $_Uri += '?force=true'

                }

                try
                {

                    Send-HPOVRequest -Uri $_Uri -Method DELETE -Hostname $InputObject.ApplianceConnection -AddHeader @{'If-Match' = $InputObject.eTag }     

                }

                catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['whatif']) 
            {

                "[{0}] -WhatIf was passed" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
            }

        }

    }

    End
    {        

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}
    
function Get-HPOVLicense 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateSet ("OneViewAdvanced", "OneView", "OneViewAdvancedNoiLO", "OneViewNoiLO","all")]
        [String]$Type,
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateSet ("Unlicensed", "Permanent",$null)]
        [String]$State,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Summary,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$Report,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose
            
        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_LicenseResources = [System.Collections.ArrayList]::new()

        [String]$filter = $null
        
        If ($PSboundParameters['Type'])
        {

            "[{0}] License Type: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Type | Write-Verbose

            switch ($Type)
            {

                # User wants the HP OneView License report
                {$_ -match "OneView","OneViewAdvanced"} 
                {

                    $filter += "?filter=`"product='HP OneView Advanced'`""

                }

                # User wants the HP OneView without iLO License Report
                {$_ -match "OneViewNoiLO","OneViewAdvancedNoiLO"} 
                {

                    $filter += "?filter=`"product='HP OneView Advanced w/o iLO'`""

                }

            }

        }

        If ($PSboundParameters['State'])
        {

            "[{0}] License State: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $State | Write-Verbose

            # Check to see if the license type/product was specified, as we would have an existing filter value
            If ($filter)
            {

                $filter += "&filter=`"licenseType='$State'`""

            }
            ElseIf (-not($filter))
            {

                $filter += "?filter=`"licenseType='$State'`""

            }

        }

        ElseIf (-not($PSboundParameters['State']))
        {

            "[{0}] No license state provided ({1})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $State | Write-Verbose

        }
  
        If ($PSboundParameters['Report'])
        {
            
            "[{0}] Parameter is being deprecated." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Write-Warning "The -Report parameter is being deprecated. Node information is contained within the .Nodes property of the returned object."
            
        }

        elseif ($PSboundParameters['Summary'])
        {

            "[{0}] Generating Summary Report" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
            
            # Check to see if the license type/product was specified, as we would have an existing filter value
            If ($filter)
            {

                $disSummary = "&view=summary"

            }
            ElseIf (-not($filter))
            {

                $disSummary = "?view=summary"

            }

        }

    }

    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose
                    
            Try
            {

                # Send the request
                $_Uri = "{0}{1}{2}" -f $ApplianceLicensePoolUri, $Filter, $disSummary
                $_LicenseCol = Send-HPOVRequest -Uri $_Uri -Hostname $_appliance

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            ForEach ($_license in $_LicenseCol.members)
            {

                $_Nodes          = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.LicensedNode]'
                # $_UnlicensedNodes = New-Object 'System.Collections.Generic.List[HPOneView.Appliance.UnlicensedNode]'
                $_AdditionalKeys = New-Object 'System.Collections.Generic.List[String]'

                ForEach ($_node in $_license.nodes)
                {

                    "[{0}] Adding '{1}' to '{2}' license pool collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_node.nodeName, $_license.product | Write-Verbose

                    $_LicensedNode = New-Object HPOneView.Appliance.LicensedNode ($_node.nodeName,
                                                                                  $_node.nodeId,
                                                                                  $_node.appliedDate,
                                                                                  $_node.nodeUri)

                    [void]$_Nodes.Add($_LicensedNode)

                }

                if ($_license.additionalKeys.Count -gt 0)
                {

                    $_license.additionalKeys | ForEach-Object { [void]$_AdditionalKeys.Add($_) }

                }

                "[{0}] Creating '{1} ({2})' license pool object." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_license.product, $_license.licenseType | Write-Verbose

                New-Object HPOneView.Appliance.License ($_license.product,
                                                        $_license.licenseType,
                                                        $_license.productDescription,
                                                        $_license.eon,
                                                        $_license.salesOrder,
                                                        $_license.availableCapacity,
                                                        $_license.totalCapacity,
                                                        $_license.key,
                                                        $_license.uri,
                                                        $_Nodes,
                                                        $_AdditionalKeys,
                                                        $_license.created,
                                                        $_license.ApplianceConnection)

            }

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVLicense 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "licenseKey")]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "licenseKey")]
        [ValidateNotNullOrEmpty()]
        [String]$LicenseKey,
        
        [Parameter (Mandatory, ParameterSetName = "InputFile")]
        [ValidateScript({Test-Path $_})]
        [String]$File,
        
        [Parameter (Mandatory = $false, ParameterSetName = "licenseKey")]
        [Parameter (Mandatory = $false, ParameterSetName = "InputFile")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_LicenseResponseCollection = [System.Collections.ArrayList]::new()

        if ($file)
        {

            [Array]$LicenseKey = Get-Content $file

        }

    }

    Process 
    {

        # Loop through all keys, and add one by one.
        foreach ($_lk in ($LicenseKey | Where-Object { -not $_.startswith("#") }))
        {

            "[{0}] Processing LicenseKey: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_lk | Write-Verbose 

            $_key     = NewObject -LicenseKey
            $_key.key = '{0}' -f $_lk

            Try 
            {
            
                $_ret = Send-HPOVRequest -Uri $ApplianceLicensePoolUri -Method POST -Body $_key -Hostname $ApplianceConnection

            }

            Catch 
            {

                $_Exception = $_

                Switch ($_.FullyQualifiedErrorId)
                {

                    "LICENSE_ALREADY_EXISTS"
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LicenseKeyException LicenseKeyAlreadyExists ResourceExists 'LicenseKey' -Message "The license key provided already exists on the appliance. Please correct the value, and try again."

                    }

                    "ADD_LICENSE_FAILED"
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LicenseKeyException InstallLicenseFailure InvalidResult 'LicenseKey' -Message $_Exception.Message                        

                    }

                    default
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.LicenseKeyException InvalidResult InvalidResult 'LicenseKey' -Message $_Exception.Exception.Message

                    }

                }

                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            $_AdditionalKeys = New-Object 'System.Collections.Generic.List[String]'

            if ($_ret.additionalKeys.Count -gt 0)
            {

                $_ret.additionalKeys | ForEach-Object { [void]$_AdditionalKeys.Add($_) }

            }

            New-Object HPOneView.Appliance.License ($_ret.product,
                                                    $_ret.licenseType,
                                                    $_ret.productDescription,
                                                    $_ret.eon,
                                                    $_ret.salesOrder,
                                                    $_ret.availableCapacity,
                                                    $_ret.totalCapacity,
                                                    $_ret.key,
                                                    $_ret.uri,
                                                    $null,
                                                    $_AdditionalKeys,
                                                    $_ret.created,
                                                    $_ret.ApplianceConnection)
            
        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
    
    }

}

function Remove-HPOVLicense 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('uri', 'name', 'license','Resource')]
        [HPOneView.Appliance.License]$InputObject,
    
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Resource'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }                    

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ResponseCollection = [System.Collections.ArrayList]::new()
        $_LicenseCollection = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        if ($PipelineInput)
        {

            "[{0}] Processing Pipeline input" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        }

        if ($null -ne $InputObject)
        {

            if ($InputObject -is [HPOneView.Appliance.License])
            {

                if (-not $InputObject.ApplianceConnection)
                {

                    $ExceptionMessage = "The License resource provided is missing the source ApplianceConnection property. Please check the object provided and try again."
                    $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message $ExceptionMessage
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                if ($PSCmdlet.ShouldProcess($InputObject.product, ("remove license from appliance {0}" -f $InputObject.ApplianceConnection)))
                {    

                    "[{0}] Removing License '{1}' [{2}]; URI: {3}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.Product, $InputObject.Description, $InputObject.Uri | Write-Verbose

                    try
                    {

                        Send-HPOVRequest -Uri $InputObject.uri -Method DELETE -Hostname $InputObject.ApplianceConnection -AddHeader @{'If-Match' = $InputObject.eTag }

                    }

                    catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSBoundParameters['whatif']) 
                { 
                            
                    "[{0}] User provided -WhatIf parameter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

                else 
                {

                    "[{0}] User cancelled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }

            else
            {

                $ExceptionMessage = "The License resource is not an expected category type [{0}]. Allowed resource category types is '[HPOneView.Library.License'. Please check the object provided and try again." -f $InputObject.Getype().FullName
                $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidArgumentValue InvalidArgument "InputObject" -TargetType PSObject -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
        
    }

}

function Set-HPOVSmtpConfig 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (
    

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [validatescript({if ($_ -as [Net.Mail.MailAddress]) {$true} else { Throw "The Parameter value is not an email address. Please correct the value and try again." }})]
        [System.String]$SenderEmailAddress,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('SmtpServer')]        
        [ValidateNotNullOrEmpty()]
        [System.String]$Server,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('SmtpPort')]
        [ValidateNotNull()]
        [System.Int32]$Port,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('None', 'TLS', 'StartTls')]
        [String]$ConnectionSecurity = 'None',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Object]$Password,

        [Parameter (Mandatory, ParameterSetName = "Disabled")]
        [Switch]$AlertEmailDisabled,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Switch]$AlertEmailEnabled,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Disabled")]
        [Switch]$Async,
    
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Disabled")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
        
    )
    
    Begin 
    {
    
        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        if ($PSBoundParameters['Password'])
        {

            if ($Password -is [SecureString])
            {

                $_DecryptPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))

            }

            else 
            {

                $_DecryptPassword = $Password

            }
        
        }

        $_ResponseCollection = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            $_SmtpConfig = NewObject -SmtpConfig
        
            $_SmtpConfig.password           = $_DecryptPassword
            $_SmtpConfig.smtpServer         = $Server
            $_SmtpConfig.alertEmailDisabled = if ($alertEmailDisabled.IsPresent) { $True }
                                                elseif ($alertEmailEnabled.IsPresent) { $False }
                                                else { $False }

            if ($PSBoundParameters['ConnectionSecurity'])
            {

                $_SmtpConfig.smtpProtocol = $SmtpConnectionSecurityEnum[$ConnectionSecurity]

            }

            Try
            {

                # Get current SMTP Configuration
                $_CurrentSmtpConfiguation = Send-HPOVRequest -Uri $SmtpConfigUri -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['AlertEmailEnabled'] -and -not $PSBoundParameters['SenderEmailAddress'] -and -not $_CurrentSmtpConfiguation.senderEmailAddress) 
            { 
                
                $ExceptionMessage = 'The -AlertEmailEnabled Parameter requires the -SenderEmailAddress Parameter to be provided when the appliance is first configured.'
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.EmailAlertResourceException InvalidArgumentValue InvalidArgument 'AlertEmailEnabled' -TargetType 'SwitchParameter' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)
            
            }

            elseif ($PSBoundParameters['AlertEmailEnabled'] -and -not $PSBoundParameters['SenderEmailAddress'] -and $_CurrentSmtpConfiguation.senderEmailAddress)
            {

                $_SmtpConfig.senderEmailAddress = $_CurrentSmtpConfiguation.senderEmailAddress

            }
            
            elseif ($PSBoundParameters['SenderEmailAddress'])
            { 
                
                $_SmtpConfig.senderEmailAddress = $SenderEmailAddress 
            
            }

            elseif ($_CurrentSmtpConfiguation.senderEmailAddress)
            {

                $_SmtpConfig.senderEmailAddress = $_CurrentSmtpConfiguation.senderEmailAddress 
                
            }

            if (-not $_CurrentSmtpConfiguation.smtpServer -and -not $PSBoundParameters['Server'] -and $PSBoundParameters['Port'])
            {

                $ExceptionMessage = "When specifying an SMTP Server Port value, the -Server parameter or an existing SMTP Server value must be present on the appliance."

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.EmailAlertResourceException InvalidSmtpServer InvalidArgument "Port" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($_CurrentSmtpConfiguation.smtpServer -and -not $PSBoundParameters['Server'] -and $PSBoundParameters['Port'])
            {

                "[{0}] Using configured SMTP Server: {1}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_CurrentSmtpConfiguation.smtpServer | Write-Verbose

                $_SmtpConfig.smtpServer = $_CurrentSmtpConfiguation.smtpServer

            }

            if (-not $_CurrentSmtpConfiguation.smtpPort -and -not $PSBoundParameters['Port'] -and $PSBoundParameters['Server'])
            {

                "[{0}] Using default SMTP TCP Port 25." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                $_SmtpConfig.smtpPort = $Port

            }

            # Copy existing email alert filter settings
            if ($_CurrentSmtpConfiguation.alertEmailFilters)
            {

                [Array]$_SmtpConfig.alertEmailFilters = $_CurrentSmtpConfiguation.alertEmailFilters

            }

            # "[{0}] SMTP Configuration: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_resp = Send-HPOVRequest -Uri $SmtpConfigUri -Method POST -Body $_SmtpConfig -Hostname $_appliance

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Async'])
            {

                $_resp

            }

            else
            {

                $_resp | Wait-HPOVTaskComplete

            }

        }

    }    
    
    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Test-HPOVEmailAlert
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (    

        [Parameter (Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Array]$Recipients,

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Subject = 'This is a test message.',

        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [String]$Body = 'Test email message from HPE OneView appliance.',
    
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SMTPConfigCollection = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        $_EmailTest = NewObject -TestSmtpConfig        
        
        # Add recipients to property
        ForEach ($_recipient in $Recipients)
        {
            
            # Validate recipient is a valid Email Address
            if (-not $_recipient -as [Net.Mail.MailAddress])
            {

                $ExceptionMessage = 'The provided recipient email address {0} is invalid.' -f $_recipient
                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.EmailAlertResourceException InvalidEmailAddress InvalidArgument "Recipients" -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)            

            }

            [void]$_EmailTest.toAddress.Add($_recipient)

        }

        if ([Regex]::Match($Body,$HtmlPattern).Success)
        {

            $_EmailTest.htmlMessageBody = $Body

        }

        else
        {

            $_EmailTest.textMessageBody = $Body

        }

        $_EmailTest.subject = $Subject

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {
     
                $null = Send-HPOVRequest -Uri $TestNotificationUri -Method POST -Body $_EmailTest -Hostname $_appliance

            }

            catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            # Add properties
            $_EmailTest | Add-Member -NotePropertyName category -NotePropertyValue appliance
            $_EmailTest | Add-Member -NotePropertyName uri -NotePropertyValue $TestNotificationUri
            $_EmailTest | Add-Member -NotePropertyName ccAddress -NotePropertyValue @()
            $_EmailTest | Add-Member -NotePropertyName bccAddress -NotePropertyValue @()
            $_EmailTest | Add-Member -NotePropertyName eTag -NotePropertyValue $null
            $_EmailTest | Add-Member -NotePropertyName created -NotePropertyValue $null
            $_EmailTest | Add-Member -NotePropertyName modified -NotePropertyValue $null
            $_EmailTest | Add-Member -NotePropertyName ApplianceConnection -NotePropertyValue (New-Object HPOneView.Library.ApplianceConnection($_appliance.Name, $_appliance.ID))
            $_EmailTest

        }

    }

    End 
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }    

}

function Get-HPOVSMTPConfig 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (    
    
        [Parameter (Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)
    
    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_SMTPConfigCollection = [System.Collections.ArrayList]::new()

    }
    
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing '{1}' Appliance (of {2})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name, $ApplianceConnection.Count | Write-Verbose

            Try
            {

                $currentSmtpConfig = Send-HPOVRequest $SmtpConfigUri -Hostname $_appliance

            }
            
            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
    
            $currentSmtpConfig | ForEach-Object { 
                
                $_.PSObject.TypeNames.Insert(0,"HPOneView.Appliance.SmtpConfiguration") 
            
                [void]$_SMTPConfigCollection.Add($_)
            
            }    

        }

    }
    
    End 
    {

        Return $_SMTPConfigCollection
    
    }

}

function Add-HPOVSmtpAlertEmailFilter 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "RemoteSupportFilter")]
        [Switch]$RemoteSupportFilter,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [System.String]$Name,
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('query')]
        [ValidateNotNullOrEmpty()]
        [System.String]$Filter,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [Alias ('recipients')]
        [ValidateNotNullOrEmpty()]
        [validatescript({$_ | ForEach-Object { if ($_ -as [Net.Mail.MailAddress]) {$true} else { Throw "The Parameter value '$_' is not an email address. Please correct the value and try again." }}})]
        [System.Array]$Emails,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [System.Array]$Scope,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateSet ('AND','OR')]
        [System.String]$ScopeMatchPreference = 'OR',

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "RemoteSupportFilter")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "RemoteSupportFilter")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {
            
            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

        if (-not($PSBoundParameters['Filter']))
        {

            Write-Warning 'The Filter provided is Null or Empty. This will return all resources and severities, which will cause performance issues in a large environment.'

        }

        # This is needed as the scopeQuery property cannot be null
        if (-not $PSBoundParameters['Scope'])
        {

            [String]$Scope = ""

        }

        else
        {

            $_ScopeEntries = [System.Collections.ArrayList]::new()

            ForEach ($_entry in $Scope)
            {

                if (-not $_entry.StartsWith("scope:'"))
                {

                    $_entry = "scope:'{0}'" -f $_entry
                    
                }

                [void]$_ScopeEntries.Add($_entry)                

            }

            [String]$Scope = [System.String]::Join(" $ScopeMatchPreference ",$_ScopeEntries.ToArray())

        }

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            $_resp = $null

            if ($PSBoundParameters['RemoteSupportFilter'])
            {

                "[{0}] Getting current remote support configuration from '{1}'." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance | Write-Verbose

                Try
                {

                    $_remoteSupportConfig = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if (-not $_remoteSupportConfig.enableEmailNotification)
                {

                    $_remoteSupportConfig.enableEmailNotification = $true

                    "[{0}] Enabling remote support email filter." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    Try
                    {

                        $_resp = Send-HPOVRequest -Uri $RemoteSupportConfigUri -Method PUT -Body $_remoteSupportConfig -Hostname $_appliance.Name

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                else
                {

                    "[{0}] Remote support email filter already configured." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }

            else
            {

                "[{0}] Getting current SMTP Configuration from '$($_appliance.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    $_smtpFilterConfiguration = Send-HPOVRequest $SmtpConfigUri -Hostname $_appliance.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }
                
                $_OriginalFilterConfig = $_smtpFilterConfiguration.alertEmailFilters

                # Rebuild property as ArrayList
                $_smtpFilterConfiguration.alertEmailFilters = [System.Collections.ArrayList]::new()

                $_OriginalFilterConfig | ForEach-Object {

                    [void]$_smtpFilterConfiguration.alertEmailFilters.Add($_)

                }
            
                # Create new alert filter object
                $_alertFilter = NewObject -AlertFilter
            
                $_alertFilter.filter          = $filter
                $_alertFilter.displayFilter   = $filter
                $_alertFilter.userQueryFilter = $filter
                $_alertFilter.emails          = $Emails
                $_alertFilter.scopeQuery      = $Scope
                $_alertFilter.filterName      = $Name

                "[{0}] Processing SMTP Alert Configuration for '$($_appliance.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                [void]$_smtpFilterConfiguration.alertEmailFilters.Add($_alertFilter)

                Try
                {

                    $_resp = Send-HPOVRequest -Uri $SmtpConfigUri -Method POST -Body $_smtpFilterConfiguration -Hostname $_appliance.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            if ($null -ne $_resp)
            {

                if ($PSBoundParameters['Async'])
                {

                    $_resp

                }

                else
                {

                    $_resp | Wait-HPOVTaskComplete

                }

            }
            
        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose 
    
    }

}

# //TODO: Need to return Email filters, including remote support from GET /rest/support/configuration in the enableEmailNotification boolean property
function Get-HPOVSmtpAlertEmailFilter
{


}

function Get-HPOVLoginMessage
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Getting current Login Message Configuration from '$($_appliance.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_LoginDomainGlobalSettings = Send-HPOVRequest -Uri $authnSettingsUri -Hostname $_appliance

                $_LoginMessageObject = New-Object HPOneView.Appliance.LoginMessage($_LoginDomainGlobalSettings.loginMessage.message, 
                                                                                   $_LoginDomainGlobalSettings.loginMessage.acknowledgment,
                                                                                   $_appliance)

                $_LoginMessageObject

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }
    
    End 
    {
    
        "[{0}] Done. " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Set-HPOVLoginMessage
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (
    
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [String]$Message,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ChangeEnablement")]
        [Bool]$Acknowledgment = $False,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Parameter (Mandatory = $false, ParameterSetName = "ChangeEnablement")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command again."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {


            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Getting current Login Message Configuration from '$($_appliance.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            Try
            {

                $_LoginDomainGlobalSettings = Send-HPOVRequest -Uri $authnSettingsUri -Hostname $_appliance.Name

                if ($PSBoundParameters['Message'])
                {

                $_LoginDomainGlobalSettings.loginMessage.message        = $Message

                }
                
                $_LoginDomainGlobalSettings.loginMessage.acknowledgment = [Bool]$Acknowledgment

                "[{0}] Updating Login Message Configuration." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_NewLoginDomainGlobalSettings = Send-HPOVRequest -Uri $authnSettingsUri -Method PUT -Body $_LoginDomainGlobalSettings -Hostname $_appliance

                $_LoginMessageObject = New-Object HPOneView.Appliance.LoginMessage($_NewLoginDomainGlobalSettings.loginMessage.message, 
                                                                                   $_NewLoginDomainGlobalSettings.loginMessage.acknowledgment,
                                                                                   $_appliance)

                $_LoginMessageObject

            }

            Catch
            {
                
                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

    }
    
    End 
    {
    
        "[{0}] Done. " -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Get-HPOVRemoteSyslog 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (
    
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Appliance')]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            Try
            {

                $_RemoteSyslogSettings = Send-HPOVRequest $RemoteSyslogUri -Hostname $_appliance.Name

                $_RemoteSyslogSettings.PSObject.TypeNames.Insert(0,'HPOneView.RemoteSyslog')

                [void]$_ColStatus.Add($_RemoteSyslogSettings)

            }

            Catch
            {
                
                $_ColStatus

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
        }

    }
    
    End 
    {
    
        Return $_ColStatus
    
    }

}

function Set-HPOVRemoteSyslog 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (
    
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Net.IPAddress]$Destination,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateRange(1,65535)]
        [Int]$Port = 514,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$SendTestMessage,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            $_RemoteSyslogConfig = NewObject -RemoteSyslog
            $_RemoteSyslogConfig.enabled = $true

            switch ($PSBoundParameters.Keys)
            {

                'Destination'
                {
                
                     "[{0}] Setting RemoteSyslog destination to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSBoundParameters['Destination'] | Write-Verbose

                    $_RemoteSyslogConfig.remoteSyslogDestination = $Destination.ToString()
                
                }

                'Port'
                {
                
                    "[{0}] Setting RemoteSyslog destination TCP Port to: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $PSBoundParameters['Port'] | Write-Verbose
                
                    $_RemoteSyslogConfig.remoteSyslogPort = $Port.ToString()

                }

                'SendTestMessage'
                {
                
                    "[{0}] Will generate a test SysLog entry." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                    $_RemoteSyslogConfig.sendTestLog = $true
                
                }

            }

            Try
            {

                "[{0}] Sending API POST request." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_results = Send-HPOVRequest $RemoteSyslogUri PUT $_RemoteSyslogConfig -Hostname $_appliance.Name
                
            }

            Catch
            {
                
                $_ColStatus

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Async'])
            {

                $_results

            }

            else
            {

                $_results | Wait-HPOVTaskComplete

            }

        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Enable-HPOVRemoteSyslog
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            Try
            {

                "[{0}] Getting current settings from the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_RemoteSyslogSettings = Get-HPOVRemoteSyslog -ApplianceConnection $_appliance.Name

            }

            Catch
            {
                
                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_RemoteSyslogSettings.enabled)
            {

                "[{0}] SysLog already enabled." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

            else
            {

                $_RemoteSyslogSettings.enabled = $true

                Try
                {

                    $_results = Send-HPOVRequest -Uri $RemoteSyslogUri -Method PUT -Body $_RemoteSyslogSettings -Hostname $_appliance.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            if ($PSBoundParameters['Async'])
            {

                $_results

            }

            else
            {

                $_results | Wait-HPOVTaskComplete

            }
            
        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Disable-HPOVRemoteSyslog
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $_ColStatus = [System.Collections.ArrayList]::new()

    }
     
    Process 
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            Try
            {

                "[{0}] Getting current settings from the appliance." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                $_RemoteSyslogSettings = Get-HPOVRemoteSyslog -ApplianceConnection $_appliance.Name

            }

            Catch
            {
                
                $PSCmdlet.ThrowTerminatingError($_)

            }

            if (-not($_RemoteSyslogSettings.enabled))
            {

                "[{0}] SysLog is already disabled." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            }

            else
            {

                $_RemoteSyslogSettings.enabled = $false

                Try
                {

                    $_results = Send-HPOVRequest -Uri $RemoteSyslogUri -Method PUT -Body $_RemoteSyslogSettings -Hostname $_appliance.Name

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                if ($PSBoundParameters['Async'])
                {

                    $_results

                }

                else
                {

                    $_results | Wait-HPOVTaskComplete

                }

            }
            
        }

    }
    
    End 
    {
    
        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose
    
    }

}

function Get-HPOVScope
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [SupportsWildcards()]
        [String]$Name,        

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        $_uri = $ScopesUri

        if ($PSBoundParameters['Name'])
        {

            if ($Name.Contains('*'))
            {

                $_uri = "{0}?query=name matches '{1}'" -f $_uri, $Name.Replace('*','%25')

            }

            else
            {

                $_uri = "{0}?query=name eq '{1}'" -f $_uri, $Name

            }

        }        

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            # Get Scope resource
            Try
            {

                $_Scopes = Send-HPOVRequest $_uri -Hostname $_appliance                

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Name'] -and $_Scopes.count -eq 0)
            {

                $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ScopeResourceException ScopeResourceNotFound ObjectNotFound -TargetObject 'Name' -Message ('{0} was not found on {1} appliance. Check the Name Parameter value.' -f $Name, $_appliance.Name)
                $PSCmdlet.WriteError($ErrorRecord)

            }

            # Process Scopes Collection from API
            ForEach ($_scopemember in $_Scopes.members)
            {

                $_Scope = New-Object HPOneView.Appliance.ScopeCollection($_scopemember.name, 
                                                                         $_scopemember.description, 
                                                                         $_scopemember.uri, 
                                                                         $_scopemember.eTag, 
                                                                         $_scopemember.ApplianceConnection)

                # Lookup Scope resource associations, and add to [ScopeCollectionMembers] Members property
                Try
                {

                    $_IndexAssocationUri = '{0}?filter=scopeuris:{1}' -f $IndexUri, $_scopemember.uri

                    $_AssociatedResources = Send-HPOVRequest -Uri $_IndexAssocationUri -Hostname $_appliance

                }

                Catch
                {

                  $PSCmdlet.ThrowTerminatingError($_)

                }

                ForEach ($_Member in ($_AssociatedResources.members | Sort-Object name))
                {

                    $_ScopeMember = New-Object HPOneView.Appliance.ScopeCollectionMemberEntry($_Member.name, $ScopeCategoryEnum[$_Member.category], $_Member.uri)

                    [void]$_Scope.Members.Add($_ScopeMember)

                }

                $_Scope

            }

        }
        
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function New-HPOVScope
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [String]$Description,

        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            $_Scope = New-Object HPOneView.Appliance.Scope($Name, $Description)

            # Get Scope resource
            Try
            {

                $_ScopeTask = Send-HPOVRequest -Uri $ScopesUri -Method POST -Body $_Scope -Hostname $_appliance    | Wait-HPOVTaskComplete            

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($_ScopeTask.taskState -eq 'Completed')
            {

                try
                {

                    $_scoperesource = Send-HPOVRequest -Uri $_ScopeTask.associatedResource.resourceUri -Hostname $_appliance

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                # Return Strongly typed object
                New-Object HPOneView.Appliance.ScopeCollection($_Scope.name, 
                                                               $_Scope.description, 
                                                               $_Scope.uri, 
                                                               $_Scope.eTag, 
                                                               (New-Object HPOneView.Library.ApplianceConnection($_appliance.Name, $_appliance.ConnectionId)))

            }

            else
            {

                $ExceptionMessage = [String]::Join(' ', $_ScopeTask.taskErrors.message)
                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.ScopeResourceException InvalidResult InvalidResult 'ApplianceConnection' -Message $ExceptionMessage
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }            

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVResourceToScope
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default", ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,
        
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Alias('Resource')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Switch]$Async,

        [Parameter (Mandatory = $false, ParameterSetName = "Default", ValueFromPipelineByPropertyName)]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Scope'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        #$_UpdateScopeMembers = NewObject -ScopeMemberUpdate
        $_UpdateScopeMembers = NewObject -PatchOperation
        $_UpdateScopeMembers.op = 'add'
        $_UpdateScopeMembers.path = '/addedResourceUris'
        $_UpdateScopeMembers.value = [System.Collections.ArrayList]::new()

        ForEach ($_resource in $InputObject)
        {

            # Validate Resource is allowed
            if ($ScopeCategoryEnum[$_resource.category])
            {

                # Generate error that Resource already contains the Scope Uri
                if ($_resource.scopeUris -contains $Scope.Uri)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ScopeResourceException ResourceAlreadyWithinScope ResourceExists -TargetObject 'InputObject' -TargetType 'PSObject' -Message ('{0} is already a member of {1} scope.' -f $_resource.name, $Scope.Name)
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                # Add resource URI to collection
                else
                {

                    "[{0}] {1} Resource is not a member of {2} Scope, adding to collection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_resource.name, $Scope.Name | Write-Verbose

                    [void]$_UpdateScopeMembers.value.Add($_resource.uri)            

                }

            }

        }

        Try
        {

            $_Resp = Send-HPOVRequest -Uri $Scope.Uri -Method PATCH -Body $_UpdateScopeMembers -Hostname $ApplianceConnection #-OverrideContentType 'application/json-patch+json'

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSboundParameters['Async'])
        {

            $_Resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVResourceFromScope
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default", ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.ScopeCollection]$Scope,
        
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Alias('Resource')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,
        
        [Parameter (Mandatory = $false, ParameterSetName = "Default")]
        [ValidateNotNullorEmpty()]
        [Switch]$Async,    

        [Parameter (Mandatory = $false, ParameterSetName = "Default", ValueFromPipelineByPropertyName)]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Scope'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        $_UpdateScopeMembers = NewObject -PatchOperation
        $_UpdateScopeMembers.op = 'replace'
        $_UpdateScopeMembers.path = '/removedResourceUris'
        $_UpdateScopeMembers.value = [System.Collections.ArrayList]::new()

        ForEach ($_resource in $InputObject)
        {

            # Validate Resource is allowed
            if ($ScopeCategoryEnum[$_resource.category])
            {

                # Generate error that Resource already contains the Scope Uri
                if ($Scope.Members.Uri -notcontains $_resource.uri)
                {

                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.ScopeResourceException ResourceDoesNotExistWithinScope ObjectNotFound -TargetObject 'InputObject' -TargetType 'PSObject' -Message ('{0} is not found to be a member of {1} scope.' -f $_resource.name, $Scope.Name)
                    $PSCmdlet.WriteError($ErrorRecord)

                }

                # Add resource URI to collection
                else
                {

                    "[{0}] {1} Resource is a member of {2} Scope. Removing." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_resource.name, $Scope.Name | Write-Verbose

                    [void]$_UpdateScopeMembers.value.Add($_resource.uri)                

                }

            }

        }

        Try
        {

            $_Resp = Send-HPOVRequest -Uri $Scope.Uri -Method PATCH -Body $_UpdateScopeMembers -Hostname $ApplianceConnection

        }

        Catch
        {

            $PSCmdlet.ThrowTerminatingError($_)

        }

        if ($PSboundParameters['Async'])
        {

            $_Resp

        }

        else
        {

            $_resp | Wait-HPOVTaskComplete

        }

    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Remove-HPOVScope
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "Default", ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [HPOneView.Appliance.ScopeCollection[]]$Scope,    

        [Parameter (Mandatory = $false, ParameterSetName = "Default", ValueFromPipelineByPropertyName)]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['Scope'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        $_ScopeCollection = [System.Collections.ArrayList]::new()

    }

    Process
    {

        "[{0}] Processing Scope: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Scope.Name | Write-Verbose

        [void]$_ScopeCollection.Add($Scope)

    }

    End
    {

        "[{0}] Processing $($_ScopeCollection.count) Scope object resources to remove." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        # Process Storage Resources
        ForEach ($_Scope in $_ScopeCollection)
        {

            if ($PSCmdlet.ShouldProcess($_Scope.ApplianceConnection.Name,"Remove Scope '$($_Scope.Name)' from appliance")) 
            {

                "[{0}] Removing Scope '$($_Scope.name)' from appliance '$($_Scope.ApplianceConnection.Name)'." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                Try
                {

                    Send-HPOVRequest -Uri $_Scope.Uri -Method DELETE -Hostname $_Scope.ApplianceConnection.Name -addHeader @{'If-Match' = $_Scope.eTag}

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

            elseif ($PSBoundParameters['WhatIf'])
            {

                "[{0}] WhatIf Parameter was passed." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            }

        }

    }

}

function Get-HPOVLabel
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory = $false)]
        [ValidateNotNullorEmpty()]
        [Object]$Name,

        [Parameter (Mandatory = $false)]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
        {

            For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++) 
            {

                Try 
                {
            
                    $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $ApplianceConnection[$c].Name -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            Try 
            {
            
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        ForEach ($_appliance in $ApplianceConnection)
        {

            "[{0}] Processing {1} appliance connection." -f $MyInvocation.InvocationName.ToString().ToUpper(), $_appliance.Name | Write-Verbose

            # Get label resources
            Try
            {

                $_Labels = Send-HPOVRequest -Uri $LabelsUri -Hostname $_appliance                

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

            if ($PSBoundParameters['Name'])
            {

                [Array]$_Labels.members = $_Labels.members | Where-Object name -match $Name
                
                if ($_Labels.members.count -eq 0)
                {

                    $ExceptionMessage = '{0} was not found on {1} appliance. Check the Name Parameter value.' -f $Name, $_appliance.Name
                    $ErrorRecord = New-ErrorRecord HPOneView.Appliance.LabelResourceException LabelResourceNotFound ObjectNotFound -TargetObject 'Name' -Message $ExceptionMessage
                    $PSCmdlet.WriteError($ErrorRecord)

                }

            }    

            # Process Scopes Collection from API
            ForEach ($_label in $_Labels.members)
            {

                New-Object HPOneView.Appliance.Label($_label.name, $_label.eTag, $_label.uri, $_label.ApplianceConnection)

            }

        }
        
    }

    End
    {

        "[{0}] Done." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Add-HPOVResourceToLabel
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding ()]
    Param
    (

        [Parameter (Mandatory)]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName)]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        ForEach ($_Resource in $InputObject)
        {

            "[{0}] Processing Label: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name | Write-Verbose

            Try
            {

                $_Uri = '{0}{1}' -f $LabelsResourcesBaseUri, $_Resource.uri
                $ExistingLabels = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }
            
            # Label already exists. Generate non-terminating error?
            if ($Name -contains $ExistingLabels.labels)
            {

                "[{0}] Resource {1} is already associated with {2} label ({3})" -f $MyInvocation.InvocationName.ToString().ToUpper(), $_Resource.name, $Name, [String]::Join($ExistingLabels.labels, ', ') | Write-Verbose

                Write-Warning "Resource is already associated with label."

            }

            else
            {

                if ($ExistingLabels.labels.count -gt 0)
                {

                    "[{0}] Appending {1} label to resource {2} association." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_Resource.name | Write-Verbose                

                    [Array]$ExistingLabels.labels += $Name

                }

                else
                {

                    "[{0}] Associating {1} label to resource {2}." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $_Resource.name | Write-Verbose

                    [Array]$ExistingLabels.labels = $Name

                }

                Try
                {

                    Send-HPOVRequest -Uri $ExistingLabels.uri -Method PUT -Body $ExistingLabels -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    End
    {

        '[{0}] Done.' | Write-Verbose

    }    

}

function Remove-HPOVResourceFromLabel
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = 'Default', SupportsShouldProcess, ConfirmImpact = 'High')]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateNotNullorEmpty()]
        [String]$Name,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'RemoveAll')]
        [ValidateNotNullorEmpty()]
        [Object]$InputObject,

        [Parameter (Mandatory = $false, ParameterSetName = 'RemoveAll')]
        [Switch]$RemoveAllLabelsFromResource,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = 'RemoveAll')]
        [Alias ('Appliance')]
        [ValidateNotNullOrEmpty()]
        [Object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        if (-not($PSBoundParameters['InputObject'])) 
        { 
            
            $PipelineInput = $True 
        
        }

        else
        {

            "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

            if (-not($ApplianceConnection) -and -not(${Global:ConnectedSessions}))
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError "ApplianceConnection" -Message "No Appliance connection session found. Please use Connect-HPOVMgmt to establish a connection, then try your command agian."
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            elseif ($ApplianceConnection -is [System.Collections.IEnumerable] -and $ApplianceConnection -isnot [System.String])
            {

                For ([Int]$c = 0; $c -lt $ApplianceConnection.Count; $c++)
                {

                    Try 
                    {
            
                        $ApplianceConnection[$c] = Test-HPOVAuth $ApplianceConnection[$c]

                    }

                    Catch [HPOneview.Appliance.AuthSessionException] 
                    {

                        $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError $_connection -Message $_.Exception.Message -InnerException $_.Exception
                        $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                    }

                    Catch 
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

            }

            else
            {

                Try 
                {
            
                    $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

                }

                Catch [HPOneview.Appliance.AuthSessionException] 
                {

                    $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -Message $_.Exception.Message -InnerException $_.Exception
                    $PSCmdlet.ThrowTerminatingError($ErrorRecord)

                }

                Catch 
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

    }

    Process
    {

        if ($InputObject -isnot [HPOneView.Appliance.Label])
        {

            "[{0}] Processing Label {1} for {2} resource." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $InputObject.name | Write-Verbose

            if ($PSCmdlet.ParameterSetName -eq 'RemoveAll')
            {

                if ($PSCmdlet.ShouldProcess($InputObject.name, 'remove resource from all associated labels'))
                {

                    "[{0}] Removing {1} resource from all labels." -f $MyInvocation.InvocationName.ToString().ToUpper(), $InputObject.name | Write-Verbose

                    Try
                    {

                        $_Uri = '{0}{1}' -f $LabelsResourcesBaseUri, $InputObject.uri
                        Send-HPOVRequest -Uri $_Uri -Method DELETE -AddHeader @{'If-Match' = '*'} -Hostname $ApplianceConnection

                    }

                    Catch
                    {

                        $PSCmdlet.ThrowTerminatingError($_)

                    }

                }

                elseif ($PSBoundParameters['WhatIf'])
                {

                    "[{0}] User specified -WhatIf" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

                }

            }

            else
            {

                Try
                {

                    $_Uri = '{0}{1}' -f $LabelsResourcesBaseUri, $InputObject.uri
                    $ExistingLabels = Send-HPOVRequest -Uri $_Uri -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

                "[{0}] Removing {1} label from resource {2} association." -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $InputObject.name | Write-Verbose                

                [Array]$ExistingLabels.labels = $ExistingLabels.labels | Where-Object name -ne $Name

                Try
                {

                    Send-HPOVRequest -Uri $ExistingLabels.uri -Method PUT -Body $ExistingLabels -Hostname $ApplianceConnection

                }

                Catch
                {

                    $PSCmdlet.ThrowTerminatingError($_)

                }

            }

        }

        else
        {

            $_Message = "An invalid InputObject argument value type was provided, {0}. Labels cannot be removed via the appliance API. Labels are automatically removed when the last association to a resource is removed. Please provide a resource object to remove the label association." -f $InputObject.name
            $ErrorRecord = New-ErrorRecord InvalidOperationException InvalidInputObjectParameterValue InvalidArgument 'InputObject' -TargetType "$($InputObject.GetType().Name)" -Message $_Message
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

########################################################
# HP Support CMDLETs

function Enable-HPOVDebug 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "default",HelpMessage = "Provide the debug Scope.")]
        [ValidateNotNullOrEmpty()]
        [String]$Scope,

        [Parameter (Mandatory, ParameterSetName = "default",HelpMessage = "Provide the component Logger Name.")]
        [ValidateNotNullOrEmpty()]
        [String]$LoggerName,

        [Parameter (Mandatory, ParameterSetName = "default",HelpMessage = "Specify the verbose log level (ERROR, WARN, DEBUG or TRACE are allowed).")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet ('ERROR','WARN','DEBUG','TRACE', IgnoreCase = $False)]
        [String]$Level,

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        [console]::WriteLine()
        Write-Warning "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
        Write-Warning "!!! FOR HP SUPPORT USE ONLY. DO NOT USE UNLESS OTHERWISE INSTRUCTED TO BY HP SUPPORT !!!"
        Write-Warning "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
        [console]::WriteLine() 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif  ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        else
        {

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

        $colStatus = [System.Collections.ArrayList]::new()

    }

    Process 
    {

        $_debug = NewObject -ApplianceDebug

        $_debug.scope      = $Scope
        $_debug.loggerName = $LoggerName
        $_debug.level      = $Level

        "[{0}] Setting '{1}' at '{2}:{3}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Level, $Scope, $LoggerName | Write-Verbose

        Try
        {

            $resp = Send-HPOVRequest $script:applianceDebugLogSetting POST $_debug -Hostname $ApplianceConnection

        }

        Catch
        {

            "Unable to set '{0}:{1}' to '{2}' logging level. Error '{3}'" -f $Scope, $LoggerName, $Level, $_.Exception.Message

            $PSCmdlet.ThrowTerminatingError($_)

        }

        "'{0}:{1}' successfully set to '{2}' on Appliance {3}" -f $Scope, $LoggerName, $Level, $ApplianceConnection

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        Write-Warning "Remember to set '$Scope`:$LoggerName' back to 'INFO' with 'Disable-HPOVDebug $Scope $LoggerName'"

    }

}

function Disable-HPOVDebug 
{

    # .ExternalHelp HPOneView.500.psm1-help.xml

    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$Scope,

        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$LoggerName,

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin 
    {

        [console]::WriteLine()
        Write-Warning "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
        Write-Warning "!!! FOR HP SUPPORT USE ONLY. DO NOT USE UNLESS OTHERWISE INSTRUCTED TO BY HP SUPPORT !!!"
        Write-Warning "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
        [console]::WriteLine() 

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif  ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        else
        {

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process 
    {

        $_debug = NewObject -ApplianceDebug

        $_debug.scope      = $Scope
        $_debug.loggerName = $LoggerName
        $_debug.level      = 'INFO'

        "[{0}] Setting '{1}' at '{2}:{3}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Level, $Scope, $LoggerName | Write-Verbose

        Try
        {

            $resp = Send-HPOVRequest $script:applianceDebugLogSetting POST $_debug -Hostname $ApplianceConnection

        }

        Catch
        {

            "Unable to set '{0}:{1}' to '{2}' logging level. Error '{3}'" -f $Scope, $LoggerName, $Level, $_.Exception.Message

            $PSCmdlet.ThrowTerminatingError($_)

        }

        "'{0}:{1}' successfully set to '{2}' on Appliance {3}" -f $Scope, $LoggerName, $Level, $ApplianceConnection.Name

    }

    End 
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

function Get-HPOVFixMeInstallationLog
{

    
    # .ExternalHelp HPOneView.500.psm1-help.xml
    
    [CmdletBinding (DefaultParameterSetName = "default")]
    Param
    (

        [Parameter (Mandatory = $false, ParameterSetName = "default", ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [System.IO.DirectoryInfo]$Location = [Environment]::CurrentDirectory,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [ValidateNotNullorEmpty()]
        [Alias ('Appliance')]
        [object]$ApplianceConnection = (${Global:ConnectedSessions} | Where-Object Default)

    )

    Begin
    {

        "[{0}] Bound PS Parameters: {1}"  -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose

        $Caller = (Get-PSCallStack)[1].Command

        "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose

        "[{0}] Verify auth" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

        if (-not($ApplianceConnection -is [HPOneView.Appliance.Connection]) -and (-not($ApplianceConnection -is [System.String])))
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException InvalidApplianceConnectionDataType InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter is not type [HPOneView.Appliance.Connection] or [System.String]. Please correct this value and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        elseif  ($ApplianceConnection.Count -gt 1)
        {

            $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException MultipleApplianceConnections InvalidArgument 'ApplianceConnection' -Message 'The specified ApplianceConnection Parameter contains multiple Appliance Connections. This CMDLET only supports 1 Appliance Connection in the ApplianceConnect Parameter value. Please correct this and try again.'
            $PSCmdlet.ThrowTerminatingError($ErrorRecord)

        }

        else
        {

            Try 
            {
    
                $ApplianceConnection = Test-HPOVAuth $ApplianceConnection

            }

            Catch [HPOneview.Appliance.AuthSessionException] 
            {

                $ErrorRecord = New-ErrorRecord HPOneview.Appliance.AuthSessionException NoApplianceConnections AuthenticationError 'ApplianceConnection' -TargetType $ApplianceConnection.GetType().Name -Message $_.Exception.Message -InnerException $_.Exception
                $PSCmdlet.ThrowTerminatingError($ErrorRecord)

            }

            Catch 
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    Process
    {

        $_uri = $ApplianceFixmeLogsDownloadUri

        ForEach ($_appliance in $ApplianceConnection)
        {

            Try
            {

                Download-File -Uri $_uri -ApplianceConnection $_appliance -SaveLocation $Location

            }

            Catch
            {

                $PSCmdlet.ThrowTerminatingError($_)

            }

        }

    }

    End
    {

        '[{0}] Done.' -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose

    }

}

# // TODO:
function Enable-HPOVNessusSupport
{


}

# // TODO:
function Disable-HPOVNessusSupport
{



}

########################################################
# PowerShell Filters

filter ColorPattern( [String]$Pattern, [hashtable]$Color) 
{

    $split = $_ -split $Pattern

    $found = [regex]::Matches( $_, $Pattern, 'IgnoreCase' )

    for( $i = 0; $i -lt $split.Count; ++$i ) 
    {

        [ConsoleColor]$displayColor = $Color.keys | ForEach-Object { if ($_ -ieq $found[$i]) { $color[$_]} }
        Write-Host $split[$i] -NoNewline
        Write-Host $found[$i] -NoNewline -ForegroundColor $displayColor

    }

    [console]::WriteLine()

}

filter Convert-IP2Decimal
{

    ([Net.IPAddress][String]([Net.IPAddress]$_)).Address
    
}


filter Convert-Decimal2IP
{

    ([System.Net.IPAddress]$_).IPAddressToString 
    
}

#######################################################
# CMDLET Aliases
set-Alias New-HPOVEnclosure Add-HPOVEnclosure
set-Alias New-HPOVServer Add-HPOVServer 
set-Alias Wait-HPOVTaskAccepted Wait-HPOVTaskStart
set-Alias Get-HPOVServerHardwareTypes Get-HPOVServerHardwareType
set-Alias New-HPOVStorageSystem Add-HPOVStorageSystem
set-Alias New-HPOVSanManager Add-HPOVSanManager
set-Alias New-HPOVStoragePool Add-HPOVStoragePool
# Set-Alias New-HPOVPowerDevice Add-HPOVPowerDevice
set-Alias Set-HPOVRole Set-HPOVUserRole
set-Alias Get-HPOVSppFile Get-HPOVBaseline
set-Alias Add-HPOVSppFile Add-HPOVBaseline
set-Alias New-HPOVLdap New-HPOVLdapDirectory
set-Alias Remove-HPOVLdap Remove-HPOVLdapDirectory
set-Alias Get-HPOVProfile Get-HPOVServerProfile
set-Alias New-HPOVAddressRange New-HPOVAddressPoolRange
set-Alias New-HPOVProfile New-HPOVServerProfile
set-Alias Get-HPOVProfileAssign New-HPOVServerProfileAssign
set-Alias Copy-HPOVProfile Copy-HPOVServerProfile
set-Alias Remove-HPOVProfile Remove-HPOVServerProfile 
set-Alias Get-HPOVProfileConnectionList Get-HPOVServerProfileConnectionList
set-Alias New-HPOVProfileConnection New-HPOVServerProfileConnection
set-Alias New-HPOVProfileAttachVolume New-HPOVServerProfileAttachVolume
set-Alias sr Send-HPOVRequest
Set-Alias Show-HPOVBaselineRepositorySize Get-HPOVBaselineRepository
Set-Alias Get-HPOVHypervisorManager Get-HPOVClusterManager
Set-Alias Add-HPOVHypervisorManager Add-HPOVClusterManager
Set-Alias Set-HPOVHypervisorManager Set-HPOVClusterManager
Set-Alias Remove-HPOVHypervisorManager Remove-HPOVClusterManager

#######################################################
# Export the public functions from this module
# Generic suport functions:
Export-ModuleMember -function Send-HPOVRequest -Alias sr
Export-ModuleMember -function Connect-HPOVMgmt
Export-ModuleMember -function Push-HPOVAppliancePermission
Export-ModuleMember -function Pop-HPOVAppliancePermission
Export-ModuleMember -function Disconnect-HPOVMgmt
Export-ModuleMember -function Set-HPOVApplianceDefaultConnection
Export-ModuleMember -function Ping-HPOVAddress
Export-ModuleMember -function New-HPOVResource
Export-ModuleMember -function Set-HPOVResource
Export-ModuleMember -function Remove-HPOVResource
Export-ModuleMember -function Wait-HPOVApplianceStart
Export-ModuleMember -function Enable-HPOVDebug
Export-ModuleMember -function Disable-HPOVDebug
Export-ModuleMember -function Get-HPOVFixMeInstallationLog
Export-ModuleMember -function Get-HPOVRemoteSyslog
Export-ModuleMember -function Set-HPOVRemoteSyslog
Export-ModuleMember -function Enable-HPOVMSDSC
Export-ModuleMember -function Disable-HPOVMSDSC
Export-ModuleMember -function Start-HPOVLibraryTrace
Export-ModuleMember -function Stop-HPOVLibraryTrace
Export-ModuleMember -function Get-HPOVCommandTrace
Export-ModuleMember -function Get-HPOVRemoteSyslog
Export-ModuleMember -function Set-HPOVRemoteSyslog
Export-ModuleMember -function Enable-HPOVRemoteSyslog
Export-ModuleMember -function Disable-HPOVRemoteSyslog
Export-ModuleMember -function Get-HPOVApplianceProxy
Export-ModuleMember -function Set-HPOVApplianceProxy
Export-ModuleMember -function Remove-HPOVApplianceProxy
Export-ModuleMember -function Invoke-HPOVWebBrowser
Export-ModuleMember -function Show-HPOVActiveUser
Export-ModuleMember -Function ConvertTo-HPOVPowerShellScript

# Remote Support:
Export-ModuleMember -function Get-HPOVRemoteSupport
Export-ModuleMember -function Set-HPOVRemoteSupport
Export-ModuleMember -function Get-HPOVRemoteSupportContact
Export-ModuleMember -function New-HPOVRemoteSupportContact
Export-ModuleMember -function Set-HPOVRemoteSupportPrimaryContact
Export-ModuleMember -function Remove-HPOVRemoteSupportContact
Export-ModuleMember -function Get-HPOVRemoteSupportDefaultSite
Export-ModuleMember -function Set-HPOVRemoteSupportDefaultSite
Export-ModuleMember -function Get-HPOVRemoteSupportSetting
Export-ModuleMember -function Set-HPOVRemoteSupportSetting
Export-ModuleMember -function Start-HPOVRemoteSupportCollection
Export-ModuleMember -function Get-HPOVRemoteSupportPartner
Export-ModuleMember -function New-HPOVRemoteSupportPartner
Export-ModuleMember -function Remove-HPOVRemoteSupportPartner
Export-ModuleMember -function Set-HPOVRemoteSupportDataCollectionSchedule
Export-ModuleMember -function Get-HPOVRemoteSupportDataCollectionSchedule
Export-ModuleMember -function Get-HPOVRemoteSupportEntitlementStatus
Export-ModuleMember -function Enable-HPOVRemoteSupport
Export-ModuleMember -function Disable-HPOVRemoteSupport
Export-ModuleMember -function Update-HPOVRemoteSupportEntitlement

# Appliance Configuration:
Export-ModuleMember -function Get-HPOVApplianceAuditLogForwarding
Export-ModuleMember -function Set-HPOVApplianceAuditLogForwarding
Export-ModuleMember -function Test-HPOVApplianceAuditLogForwarding
Export-ModuleMember -function Get-HPOVApplianceCertificateStatus
Export-ModuleMember -function Get-HPOVApplianceDateTime
Export-ModuleMember -function Set-HPOVApplianceDateTime
Export-ModuleMember -function New-HPOVApplianceSelfSignedCertificate
Export-ModuleMember -function New-HPOVApplianceCsr
Export-ModuleMember -function Install-HPOVApplianceCertificate
Export-ModuleMember -function Get-HPOVApplianceTrustedCertificate
Export-ModuleMember -function Add-HPOVApplianceTrustedCertificate
Export-ModuleMember -function Remove-HPOVApplianceTrustedCertificate
Export-ModuleMember -function Update-HPOVApplianceTrustedAuthorityCrl
Export-ModuleMember -function Get-HPOVVersion
Export-ModuleMember -function Get-HPOVHealthStatus
Export-ModuleMember -function Get-HPOVXApiVersion
Export-ModuleMember -function Get-HPOVEulaStatus
Export-ModuleMember -function Set-HPOVEulaStatus
Export-ModuleMember -function Get-HPOVApplianceNetworkConfig
Export-ModuleMember -function Set-HPOVApplianceNetworkConfig
Export-ModuleMember -function Get-HPOVSnmpReadCommunity
Export-ModuleMember -function Set-HPOVSnmpReadCommunity
Export-ModuleMember -function Get-HPOVApplianceTrapDestination
Export-ModuleMember -function New-HPOVApplianceTrapDestination
Export-ModuleMember -function Remove-HPOVApplianceTrapDestination
Export-ModuleMember -function Get-HPOVApplianceSnmpV3EngineId
Export-ModuleMember -function Set-HPOVApplianceSnmpV3EngineId
Export-ModuleMember -function New-HPOVSnmpV3User
Export-ModuleMember -function Get-HPOVSnmpV3User
Export-ModuleMember -function Remove-HPOVSnmpV3User
Export-ModuleMember -function Get-HPOVApplianceGlobalSetting
Export-ModuleMember -function Set-HPOVApplianceGlobalSetting
Export-ModuleMember -function Get-HPOVBaseline -Alias Get-HPOVSppFile
Export-ModuleMember -function Add-HPOVBaseline -Alias Add-HPOVSppFile
Export-ModuleMember -function New-HPOVCustomBaseline
Export-ModuleMember -function Restore-HPOVCustomBaseline
Export-ModuleMember -function Remove-HPOVBaseline
Export-ModuleMember -function Get-HPOVBaselineRepository -Alias Show-HPOVBaselineRepositorySize
Export-ModuleMember -function New-HPOVExternalRepository
Export-ModuleMember -function Set-HPOVExternalRepository
Export-ModuleMember -function Update-HPOVExternalRepository
Export-ModuleMember -function Remove-HPOVExternalRepository
Export-ModuleMember -function New-HPOVSupportDump
Export-ModuleMember -function New-HPOVBackup
Export-ModuleMember -function Get-HPOVBackup
Export-ModuleMember -function Save-HPOVBackup
Export-ModuleMember -function New-HPOVRestore
Export-ModuleMember -function Get-HPOVAutomaticBackupConfig
Export-ModuleMember -function Set-HPOVAutomaticBackupConfig
Export-ModuleMember -function Get-HPOVScmbCertificates
Export-ModuleMember -function Remove-HPOVScmbCertificate
Export-ModuleMember -function Install-HPOVUpdate
Export-ModuleMember -function Get-HPOVPEndingUpdate
Export-ModuleMember -function Remove-HPOVPEndingUpdate
Export-ModuleMember -function Import-HPOVSSLCertificate
Export-ModuleMember -function Restart-HPOVAppliance
Export-ModuleMember -function Stop-HPOVAppliance
Export-ModuleMember -function Get-HPOVComposerNode
Export-ModuleMember -function Enable-HPOVComposerHANode
Export-ModuleMember -function Remove-HPOVStandbyComposerNode
Export-ModuleMember -function Get-HPOVLabel
Export-ModuleMember -function Add-HPOVResourceToLabel
Export-ModuleMember -function Remove-HPOVResourceFromLabel

# Server hardware and enclosures:
Export-ModuleMember -function Get-HPOVServer
Export-ModuleMember -function Add-HPOVServer -Alias New-HPOVServer
Export-ModuleMember -function Set-HPOVServerPower
Export-ModuleMember -function Get-HPOVServerOneTimeBoot
Export-ModuleMember -function Set-HPOVServerOneTimeBoot
Export-ModuleMember -function Start-HPOVServer
Export-ModuleMember -function Stop-HPOVServer
Export-ModuleMember -function Restart-HPOVServer
Export-ModuleMember -function Remove-HPOVServer
Export-ModuleMember -function Update-HPOVServer
Export-ModuleMember -function Update-HPOVServerHardwareLicenseIntent
Export-ModuleMember -function Get-HPOVRackManager
Export-ModuleMember -function Add-HPOVRackManager
Export-ModuleMember -function Update-HPOVRackManager
Export-ModuleMember -function Remove-HPOVRackManager
Export-ModuleMember -function Get-HPOVEnclosure
Export-ModuleMember -function Set-HPOVEnclosure
Export-ModuleMember -function Update-HPOVEnclosure
Export-ModuleMember -function Add-HPOVEnclosure -Alias New-HPOVEnclosure
Export-ModuleMember -function Add-HPOVRemoteFrame
Export-ModuleMember -function New-HPOVLogicalEnclosure
Export-ModuleMember -function Get-HPOVLogicalEnclosure
Export-ModuleMember -function Set-HPOVLogicalEnclosure
Export-ModuleMember -function Update-HPOVLogicalEnclosure 
Export-ModuleMember -function Update-HPOVLogicalEnclosureFirmware 
Export-ModuleMember -function Remove-HPOVLogicalEnclosure
Export-ModuleMember -function Remove-HPOVEnclosure
Export-ModuleMember -function Get-HPOVEnclosureGroup
Export-ModuleMember -function New-HPOVEnclosureGroup
Export-ModuleMember -function Set-HPOVEnclosureGroup
Export-ModuleMember -function Remove-HPOVEnclosureGroup
Export-ModuleMember -function Get-HPOVServerHardwareType -Alias Get-HPOVServerHardwareTypes
Export-ModuleMember -function Set-HPOVServerHardwareType
Export-ModuleMember -function Show-HPOVFirmwareReport
Export-ModuleMember -function Invoke-HPOVVcmMigration
Export-ModuleMember -function Enable-HPOVDeviceUid
Export-ModuleMember -function Disable-HPOVDeviceUid
Export-ModuleMember -function Set-HPOVEnclosureActiveFLM
Export-ModuleMember -function Reset-HPOVEnclosureDevice
Export-ModuleMember -function Get-HPOVIloSso
Export-ModuleMember -function ConvertTo-HPOVImageStreamerConfiguration
# Export-ModuleMember -function Show-HPOVUtilization

# Storage
Export-ModuleMember -function Get-HPOVStorageSystem
Export-ModuleMember -function Update-HPOVStorageSystem
Export-ModuleMember -function Add-HPOVStorageSystem -Alias New-HPOVStorageSystem
Export-ModuleMember -function Remove-HPOVStorageSystem
Export-ModuleMember -function Show-HPOVStorageSystemPerformancePolicy
Export-ModuleMember -function Get-HPOVStoragePool
Export-ModuleMember -function Add-HPOVStoragePool -Alias New-HPOVStoragePool
Export-ModuleMember -function Set-HPOVStoragePool
Export-ModuleMember -function Update-HPOVStoragePool 
Export-ModuleMember -function Remove-HPOVStoragePool
Export-ModuleMember -function Get-HPOVStorageVolumeSet
Export-ModuleMember -function Get-HPOVStorageVolumeTemplate
Export-ModuleMember -function New-HPOVStorageVolumeTemplate
Export-ModuleMember -function Set-HPOVStorageVolumeTemplate 
Export-ModuleMember -function Remove-HPOVStorageVolumeTemplate
Export-ModuleMember -function Get-HPOVStorageVolumeTemplatePolicy
Export-ModuleMember -function Set-HPOVStorageVolumeTemplatePolicy
Export-ModuleMember -function Get-HPOVStorageVolume
Export-ModuleMember -function New-HPOVStorageVolume
Export-ModuleMember -function Add-HPOVStorageVolume
Export-ModuleMember -function Set-HPOVStorageVolume
Export-ModuleMember -function Remove-HPOVStorageVolume
Export-ModuleMember -function Get-HPOVStorageVolumeSnapshot
Export-ModuleMember -function New-HPOVStorageVolumeSnapShot
Export-ModuleMember -function Remove-HPOVStorageVolumeSnapShot
Export-ModuleMember -function ConvertTo-HPOVStorageVolume
Export-ModuleMember -function Get-HPOVSanManager
Export-ModuleMember -function Add-HPOVSanManager -Alias New-HPOVSanManager
Export-ModuleMember -function Set-HPOVSanManager
Export-ModuleMember -function Update-HPOVSanManager
Export-ModuleMember -function Remove-HPOVSanManager
Export-ModuleMember -function Get-HPOVManagedSan
Export-ModuleMember -function Set-HPOVManagedSan
Export-ModuleMember -function Get-HPOVSanZone
Export-ModuleMember -function Show-HPOVSanEndpoint
Export-ModuleMember -function Get-HPOVDriveEnclosure
Export-ModuleMember -function Get-HPOVAvailableDriveType
Export-ModuleMember -function Get-HPOVSasInterconnectType 

# Unmanaged Devices
Export-ModuleMember -function Get-HPOVUnmanagedDevice
Export-ModuleMember -function New-HPOVUnmanagedDevice 
Export-ModuleMember -function Remove-HPOVUnmanagedDevice 

# Power Devices (iPDUs):
Export-ModuleMember -function Get-HPOVPowerDevice
Export-ModuleMember -function Add-HPOVPowerDevice 
Export-ModuleMember -function Remove-HPOVPowerDevice
Export-ModuleMember -function Get-HPOVPowerPotentialDeviceConnection
Export-ModuleMember -function Get-HPOVPowerPotentialDeviceConnection
# Export-ModuleMember -function New-HPOVPowerDevice
# Export-ModuleMember -function Add-HPOVPowerDeviceConnection
        
# Networking and Connections:
Export-ModuleMember -function New-HPOVNetwork
Export-ModuleMember -function Get-HPOVNetwork
Export-ModuleMember -function Set-HPOVNetwork
Export-ModuleMember -function Remove-HPOVNetwork
Export-ModuleMember -function New-HPOVNetworkSet
Export-ModuleMember -function Get-HPOVNetworkSet
Export-ModuleMember -function Set-HPOVNetworkSet
Export-ModuleMember -function Remove-HPOVNetworkSet
Export-ModuleMember -function Get-HPOVInterconnect
Export-ModuleMember -function Get-HPOVInterconnectType
Export-ModuleMember -function Get-HPOVLogicalInterconnect
Export-ModuleMember -function Get-HPOVSasLogicalInterconnect
Export-ModuleMember -function Update-HPOVLogicalInterconnect
Export-ModuleMember -function Install-HPOVLogicalInterconnectFirmware
Export-ModuleMember -function Show-HPOVLogicalInterconnectMacTable
Export-ModuleMember -function Show-HPOVPortStatistics
Export-ModuleMember -function Reset-HPOVInterconnectNetOpPassword
Export-ModuleMember -function Get-HPOVLogicalInterconnectGroup
Export-ModuleMember -function New-HPOVLogicalInterconnectGroup
Export-ModuleMember -function Remove-HPOVLogicalInterconnectGroup
Export-ModuleMember -function New-HPOVQosConfig
Export-ModuleMember -function New-HPOVQosTrafficClass
Export-ModuleMember -function Get-HPOVUplinkSet
Export-ModuleMember -function New-HPOVUplinkSet
Export-ModuleMember -function Get-HPOVAddressPool
Export-ModuleMember -function Get-HPOVAddressPoolRange
Export-ModuleMember -function New-HPOVAddressPoolRange -Alias New-HPOVAddressRange
Export-ModuleMember -function Get-HPOVAddressPoolSubnet
Export-ModuleMember -function New-HPOVAddressPoolSubnet
Export-ModuleMember -function Set-HPOVAddressPoolSubnet
Export-ModuleMember -function Remove-HPOVAddressPoolSubnet
Export-ModuleMember -function Remove-HPOVAddressPoolRange
Export-ModuleMember -function Get-HPOVReservedVlanRange
Export-ModuleMember -function Set-HPOVReservedVlanRange
Export-ModuleMember -function New-HPOVSnmpTrapDestination
Export-ModuleMember -function New-HPOVSnmpConfiguration
Export-ModuleMember -function Get-HPOVSwitchType
Export-ModuleMember -function Get-HPOVLogicalSwitchGroup
Export-ModuleMember -function New-HPOVLogicalSwitchGroup
Export-ModuleMember -function Remove-HPOVLogicalSwitchGroup
Export-ModuleMember -function Get-HPOVLogicalSwitch
Export-ModuleMember -function New-HPOVLogicalSwitch
Export-ModuleMember -function Remove-HPOVLogicalSwitch
Export-ModuleMember -function Update-HPOVLogicalSwitch
Export-ModuleMember -function Get-HPOVSwitch
Export-ModuleMember -function Get-HPOVLogicalInterconnectPortMonitoring
Export-ModuleMember -function Enable-HPOVLogicalInterconnectPortMonitoring
Export-ModuleMember -function Disable-HPOVLogicalInterconnectPortMonitoring
Export-ModuleMember -function Get-HPOVFabricManager
Export-ModuleMember -function Add-HPOVFabricManager
Export-ModuleMember -function Remove-HPOVFabricManager

# I3S (Image Streamer) Support
Export-ModuleMember -function Get-HPOVImageStreamerAppliance
Export-ModuleMember -function Get-HPOVOSDeploymentServer
Export-ModuleMember -function New-HPOVOSDeploymentServer
Export-ModuleMember -function Remove-HPOVOSDeploymentServer
Export-ModuleMember -function Get-HPOVOSDeploymentPlan
Export-ModuleMember -function Get-HPOVOSDeploymentPlanAttribute
        
# Server Profiles and Server Profile Templates:
Export-ModuleMember -function Get-HPOVServerProfile -Alias Get-HPOVProfile
Export-ModuleMember -function New-HPOVServerProfile -Alias New-HPOVProfile
Export-ModuleMember -function Set-HPOVServerProfile
Export-ModuleMember -function New-HPOVServerProfileAssign -Alias Get-HPOVProfileAssign
Export-ModuleMember -function Copy-HPOVServerProfile -Alias Copy-HPOVProfile
Export-ModuleMember -function Remove-HPOVServerProfile -Alias Remove-HPOVProfile
Export-ModuleMember -function Update-HPOVServerProfile
Export-ModuleMember -function Convert-HPOVServerProfile
Export-ModuleMember -function Get-HPOVServerProfileConnectionList -Alias Get-HPOVProfileConnectionList
Export-ModuleMember -function Get-HPOVAvailableServerConnections
Export-ModuleMember -function New-HPOVServerProfileConnection -Alias New-HPOVProfileConnection
Export-ModuleMember -function New-HPOVServerProfileAttachVolume -Alias New-HPOVProfileAttachVolume
Export-ModuleMember -function New-HPOVServerProfileTemplate 
Export-ModuleMember -function Set-HPOVServerProfileTemplate 
Export-ModuleMember -function Get-HPOVServerProfileTemplate
Export-ModuleMember -function Join-HPOVServerProfileToTemplate
Export-ModuleMember -function ConvertTo-HPOVServerProfileTemplate
Export-ModuleMember -function Remove-HPOVServerProfileTemplate
Export-ModuleMember -function New-HPOVServerProfileLogicalDisk 
Export-ModuleMember -function New-HPOVServerProfileLogicalDiskController
Export-ModuleMember -function Save-HPOVServerProfile
Export-ModuleMember -function Save-HPOVServerProfileTemplate
Export-ModuleMember -function Convert-HPOVServerProfileTemplate

# Hypervisor Cluster Profiles
Export-ModuleMember -function Get-HPOVClusterManager -Alias Get-HPOVHypervisorManager
Export-ModuleMember -function Add-HPOVClusterManager -Alias Add-HPOVHypervisorManager
Export-ModuleMember -function Set-HPOVClusterManager -Alias Set-HPOVHypervisorManager
Export-ModuleMember -function Remove-HPOVClusterManager -Alias Remove-HPOVHypervisorManager
Export-ModuleMember -function Get-HPOVClusterProfile
Export-ModuleMember -function Get-HPOVClusterNode
Export-ModuleMember -function New-HPOVClusterProfile
Export-ModuleMember -function New-HPOVClusterProfileMember
# Not sure this is needed. A Cmdlet does not exist.
# Export-ModuleMember -function New-HPOVClusterProfileVirtualSwitchConf
Export-ModuleMember -function Import-HPOVCluster
Export-ModuleMember -function Add-HPOVClusterNode
Export-ModuleMember -function Show-HPOVHypervisorCluster
Export-ModuleMember -function Remove-HPOVClusterProfile
Export-ModuleMember -function Remove-HPOVClusterNode
Export-ModuleMember -function Update-HPOVClusterProfile
Export-ModuleMember -function Update-HPOVClusterNode
Export-ModuleMember -function Enter-HPOVClusterNodeMaintenanceMode
Export-ModuleMember -function Exit-HPOVClusterNodeMaintenanceMode

# Facilities
Export-ModuleMember -function Get-HPOVRack
Export-ModuleMember -function New-HPOVRack
Export-ModuleMember -function Add-HPOVResourceToRack
Export-ModuleMember -function Set-HPOVRackMemberLocation
Export-ModuleMember -function Get-HPOVRackMember
Export-ModuleMember -function Remove-HPOVRackMember
Export-ModuleMember -function Remove-HPOVRack
Export-ModuleMember -function Get-HPOVDatacenter
Export-ModuleMember -function New-HPOVDatacenter
Export-ModuleMember -function Add-HPOVRackToDataCenter
Export-ModuleMember -function Set-HPOVDataCenterRemoteSupport
Export-ModuleMember -function Set-HPOVDatacenter
Export-ModuleMember -function Remove-HPOVDatacenter
    
# Index:
Export-ModuleMember -function Search-HPOVIndex
Export-ModuleMember -function Search-HPOVAssociations

# Tasks:
Export-ModuleMember -function Get-HPOVTask
Export-ModuleMember -function Wait-HPOVTaskStart -Alias Wait-HPOVTaskAccepted
Export-ModuleMember -function Wait-HPOVTaskComplete

# Security:
Export-ModuleMember -function Get-HPOVUser
Export-ModuleMember -function New-HPOVUser
Export-ModuleMember -function Set-HPOVUser
Export-ModuleMember -function Set-HPOVUserPassword
Export-ModuleMember -function Remove-HPOVUser
Export-ModuleMember -function Show-HPOVUserSession
Export-ModuleMember -function Get-HPOVRole
Export-ModuleMember -function Set-HPOVUserRole -Alias Set-HPOVRole
Export-ModuleMember -function Set-HPOVInitialPassword
Export-ModuleMember -function Get-HPOVLdap
Export-ModuleMember -function Get-HPOVLdapDirectory
Export-ModuleMember -function New-HPOVLdapDirectory -Alias New-HPOVLdap
Export-ModuleMember -function Set-HPOVLdapDefaultDirectory 
Export-ModuleMember -function Enable-HPOVLdapLocalLogin
Export-ModuleMember -function Disable-HPOVLdapLocalLogin
Export-ModuleMember -function New-HPOVLdapServer
Export-ModuleMember -function Add-HPOVLdapServer
Export-ModuleMember -function Remove-HPOVLdapServer
Export-ModuleMember -function Set-HPOVLdapGroupRole
Export-ModuleMember -function Remove-HPOVLdapDirectory -Alias Remove-HPOVLdap
Export-ModuleMember -function Show-HPOVLdapGroups
Export-ModuleMember -function Get-HPOVLdapGroup
Export-ModuleMember -function New-HPOVLdapGroup
Export-ModuleMember -function Set-HPOVLdapGroup
Export-ModuleMember -function Remove-HPOVLdapGroup
Export-ModuleMember -function Get-HPOVAuditLog
Export-ModuleMember -function Get-HPOVAuditLogArchive
Export-ModuleMember -function Get-HPOVLoginMessage
Export-ModuleMember -function Set-HPOVLoginMessage
Export-ModuleMember -function Get-HPOVScope
Export-ModuleMember -function New-HPOVScope
Export-ModuleMember -function Remove-HPOVScope
Export-ModuleMember -function Add-HPOVResourceToScope
Export-ModuleMember -function Remove-HPOVResourceFromScope
Export-ModuleMember -function Get-HPOVApplianceServiceConsoleAccess
Export-ModuleMember -function Enable-HPOVApplianceServiceConsoleAccess
Export-ModuleMember -function Disable-HPOVApplianceServiceConsoleAccess
Export-ModuleMember -function Enable-HPOVApplianceComplexPasswords
Export-ModuleMember -function Disable-HPOVApplianceComplexPasswords
Export-ModuleMember -function Get-HPOVApplianceSshAccess
Export-ModuleMember -function Enable-HPOVApplianceSshAccess
Export-ModuleMember -function Disable-HPOVApplianceSshAccess
Export-ModuleMember -function Enable-HPOVCertificateValidation
Export-ModuleMember -function Disable-HPOVCertificateValidation
Export-ModuleMember -function Get-HPOVApplianceTwoFactorAuthentication
Export-ModuleMember -function Disable-HPOVApplianceTwoFactorAuthentication
Export-ModuleMember -function Set-HPOVApplianceTwoFactorAuthentication
Export-ModuleMember -function Get-HPOVApplianceAvailableSecurityMode
Export-ModuleMember -function Get-HPOVApplianceCurrentSecurityMode
Export-ModuleMember -function Set-HPOVApplianceCurrentSecurityMode
Export-ModuleMember -function Get-HPOVApplianceSecurityProtocol
Export-ModuleMember -function Set-HPOVApplianceSecurityProtocol
Export-ModuleMember -function Show-HPOVApplianceSecurityModeCompatibilityReport

# Alerts:
Export-ModuleMember -function Get-HPOVAlert
Export-ModuleMember -function Get-HPOVServiceAlert
Export-ModuleMember -function Set-HPOVAlert
Export-ModuleMember -function Set-HPOVAlertAssignToUser
Export-ModuleMember -function Clear-HPOVAlert
Export-ModuleMember -function Remove-HPOVAlert
Export-ModuleMember -function Set-HPOVSmtpConfig
Export-ModuleMember -function Get-HPOVSmtpConfig
Export-ModuleMember -function Add-HPOVSmtpAlertEmailFilter
Export-ModuleMember -function Get-HPOVServerProfileMessage
Export-ModuleMember -function Test-HPOVEmailAlert

# Licensing:
Export-ModuleMember -function Get-HPOVLicense
Export-ModuleMember -function New-HPOVLicense
Export-ModuleMember -function Remove-HPOVLicense

#######################################################
# Library Global Settings Init
#

# Needed to support non-Windows PowerShell environments
$private:IsWindows = if (-not (Get-Variable -Name IsWindows -ErrorAction SilentlyContinue)) { $True } else { $IsWindows }

if ($private:IsWindows)
{

    If (-not(Test-Path "HKCU:\Software\Hewlett-Packard\HPOneView" -ErrorAction SilentlyContinue)) 
    {
        
        New-Item "HKCU:\Software\Hewlett-Packard\HPOneView" -force | Out-Null 

    }

    # Check to see if Global Policy is set first.
    $regkeyGlobal = "HKLM:\Software\Hewlett-Packard\HPOneView"
    $regkeyUser   = "HKCU:\Software\Hewlett-Packard\HPOneView" 
    $UserUseMSDSC = [Bool](Get-ItemProperty -LiteralPath $regkeyUser -ea SilentlyContinue).'UseMSDSC'
    $PesterRun    = Get-Variable -Name PesterTest -Scope Global -ErrorAction SilentlyContinue

    Write-Verbose "$regkeyUser exists: $(Test-Path $regkeyUser)" -verbose:$script:ModuleVerbose
    Write-Verbose "UseMSDSC Enabled: $($UserUseMSDSC)" -verbose:$script:ModuleVerbose

    # Override Write-Host for MSDSC
    if ((Test-Path $regkeyUser) -and ($UserUseMSDSC)) 
    {
        
        function Write-Host 
        {
            
            [CmdletBinding ()]
            Param
            (

                [Parameter (Mandatory = $false, ValueFromPipeline)]
                [Object]$Object,

                [Parameter (Mandatory = $false)]
                [Object]$Object2,

                [Parameter (Mandatory = $false)]
                [Object]$Object3,

                [Switch]$NoNewLine,

                [ConsoleColor]$ForegroundColor,

                [ConsoleColor]$BackgroundColor
        
            )
        
            # Override default Write-Host...
            Write-Verbose $Object -verbose:$script:ModuleVerbose

        }

        function Get-Host 
        {

            [CmdletBinding ()]
            Param()

            Return [PSCustomObject]$Width = @{ UI = @{ RawUI = @{ MaxWindowSize = @{ width = 120 } } } }

        }

    }

}

if ($PesterRun)
{

    function Write-Host 
    {
        
        [CmdletBinding ()]
        Param
        (

            [Parameter (Mandatory = $false, ValueFromPipeline)]
            [Object]$Object,

            [Parameter (Mandatory = $false)]
            [Object]$Object2,

            [Parameter (Mandatory = $false)]
            [Object]$Object3,

            [Switch]$NoNewLine,

            [ConsoleColor]$ForegroundColor,

            [ConsoleColor]$BackgroundColor

        )

        # Override default Write-Host...
        Out-Null

    }

}

#######################################################
# Remove-Module Processing
#

$ExecutionContext.SessionState.Module.OnRemove = {

    "[{0}] Cleaning up" -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose -verbose:$script:ModuleVerbose

    'PesterTest','CallStack', 'ConnectedSessions','FCNetworkFabricTypeEnum','GetUplinkSetPortSpeeds','SetUplinkSetPortSpeeds','LogicalInterconnectConsistencyStatusEnum','UplinkSetNetworkTypeEnum','UplinkSetEthNetworkTypeEnum','LogicalInterconnectGroupRedundancyEnum','IgnoreCertPolicy','ResponseErrorObject' | ForEach-Object { Remove-Variable -Name $_ -Scope Global -ErrorAction SilentlyContinue }     

}



# SIG # Begin signature block
# MIIkYQYJKoZIhvcNAQcCoIIkUjCCJE4CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAVGVBX47dU2juf
# qmFVUKOXfqnXRq7NHA3iHmZhETDPnKCCHtUwggQUMIIC/KADAgECAgsEAAAAAAEv
# TuFS1zANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xv
# YmFsU2lnbiBudi1zYTEQMA4GA1UECxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFs
# U2lnbiBSb290IENBMB4XDTExMDQxMzEwMDAwMFoXDTI4MDEyODEyMDAwMFowUjEL
# MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExKDAmBgNVBAMT
# H0dsb2JhbFNpZ24gVGltZXN0YW1waW5nIENBIC0gRzIwggEiMA0GCSqGSIb3DQEB
# AQUAA4IBDwAwggEKAoIBAQCU72X4tVefoFMNNAbrCR+3Rxhqy/Bb5P8npTTR94ka
# v56xzRJBbmbUgaCFi2RaRi+ZoI13seK8XN0i12pn0LvoynTei08NsFLlkFvrRw7x
# 55+cC5BlPheWMEVybTmhFzbKuaCMG08IGfaBMa1hFqRi5rRAnsP8+5X2+7UulYGY
# 4O/F69gCWXh396rjUmtQkSnF/PfNk2XSYGEi8gb7Mt0WUfoO/Yow8BcJp7vzBK6r
# kOds33qp9O/EYidfb5ltOHSqEYva38cUTOmFsuzCfUomj+dWuqbgz5JTgHT0A+xo
# smC8hCAAgxuh7rR0BcEpjmLQR7H68FPMGPkuO/lwfrQlAgMBAAGjgeUwgeIwDgYD
# VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEbYPv/c
# 477/g+b0hZuw3WrWFKnBMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB
# FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAzBgNVHR8E
# LDAqMCigJqAkhiJodHRwOi8vY3JsLmdsb2JhbHNpZ24ubmV0L3Jvb3QuY3JsMB8G
# A1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA0GCSqGSIb3DQEBBQUAA4IB
# AQBOXlaQHka02Ukx87sXOSgbwhbd/UHcCQUEm2+yoprWmS5AmQBVteo/pSB204Y0
# 1BfMVTrHgu7vqLq82AafFVDfzRZ7UjoC1xka/a/weFzgS8UY3zokHtqsuKlYBAIH
# MNuwEl7+Mb7wBEj08HD4Ol5Wg889+w289MXtl5251NulJ4TjOJuLpzWGRCCkO22k
# aguhg/0o69rvKPbMiF37CjsAq+Ah6+IvNWwPjjRFl+ui95kzNX7Lmoq7RU3nP5/C
# 2Yr6ZbJux35l/+iS4SwxovewJzZIjyZvO+5Ndh95w+V/ljW8LQ7MAbCOf/9RgICn
# ktSzREZkjIdPFmMHMUtjsN/zMIIEnzCCA4egAwIBAgISESHWmadklz7x+EJ+6RnM
# U0EUMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
# YWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFRpbWVzdGFtcGluZyBD
# QSAtIEcyMB4XDTE2MDUyNDAwMDAwMFoXDTI3MDYyNDAwMDAwMFowYDELMAkGA1UE
# BhMCU0cxHzAdBgNVBAoTFkdNTyBHbG9iYWxTaWduIFB0ZSBMdGQxMDAuBgNVBAMT
# J0dsb2JhbFNpZ24gVFNBIGZvciBNUyBBdXRoZW50aWNvZGUgLSBHMjCCASIwDQYJ
# KoZIhvcNAQEBBQADggEPADCCAQoCggEBALAXrqLTtgQwVh5YD7HtVaTWVMvY9nM6
# 7F1eqyX9NqX6hMNhQMVGtVlSO0KiLl8TYhCpW+Zz1pIlsX0j4wazhzoOQ/DXAIlT
# ohExUihuXUByPPIJd6dJkpfUbJCgdqf9uNyznfIHYCxPWJgAa9MVVOD63f+ALF8Y
# ppj/1KvsoUVZsi5vYl3g2Rmsi1ecqCYr2RelENJHCBpwLDOLf2iAKrWhXWvdjQIC
# KQOqfDe7uylOPVOTs6b6j9JYkxVMuS2rgKOjJfuv9whksHpED1wQ119hN6pOa9PS
# UyWdgnP6LPlysKkZOSpQ+qnQPDrK6Fvv9V9R9PkK2Zc13mqF5iMEQq8CAwEAAaOC
# AV8wggFbMA4GA1UdDwEB/wQEAwIHgDBMBgNVHSAERTBDMEEGCSsGAQQBoDIBHjA0
# MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0
# b3J5LzAJBgNVHRMEAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMEIGA1UdHwQ7
# MDkwN6A1oDOGMWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3MvZ3N0aW1lc3Rh
# bXBpbmdnMi5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsGAQUFBzAChjhodHRwOi8v
# c2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9nc3RpbWVzdGFtcGluZ2cyLmNy
# dDAdBgNVHQ4EFgQU1KKESjhaGH+6TzBQvZ3VeofWCfcwHwYDVR0jBBgwFoAURtg+
# /9zjvv+D5vSFm7DdatYUqcEwDQYJKoZIhvcNAQEFBQADggEBAI+pGpFtBKY3IA6D
# lt4j02tuH27dZD1oISK1+Ec2aY7hpUXHJKIitykJzFRarsa8zWOOsz1QSOW0zK7N
# ko2eKIsTShGqvaPv07I2/LShcr9tl2N5jES8cC9+87zdglOrGvbr+hyXvLY3nKQc
# MLyrvC1HNt+SIAPoccZY9nUFmjTwC1lagkQ0qoDkL4T2R12WybbKyp23prrkUNPU
# N7i6IA7Q05IqW8RZu6Ft2zzORJ3BOCqt4429zQl3GhC+ZwoCNmSIubMbJu7nnmDE
# Rqi8YTNsz065nLlq8J83/rU9T5rTTf/eII5Ol6b9nwm8TcoYdsmwTYVQ8oDSHQb1
# WAQHsRgwggVMMIIDNKADAgECAhMzAAAANdjVWVsGcUErAAAAAAA1MA0GCSqGSIb3
# DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAn
# BgNVBAMTIE1pY3Jvc29mdCBDb2RlIFZlcmlmaWNhdGlvbiBSb290MB4XDTEzMDgx
# NTIwMjYzMFoXDTIzMDgxNTIwMzYzMFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoT
# C0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0
# d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJ
# KoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2
# zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6R
# Qa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSc
# cbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFf
# clpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl
# +mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB
# 0DCBzTATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgECMB0G
# A1UdDgQWBBStvZh6NLQm9/rEJlTvA73gJMtUGjALBgNVHQ8EBAMCAYYwHwYDVR0j
# BBgwFoAUYvsKIVt/Q24R2glUUGv10pZx8Z4wVQYDVR0fBE4wTDBKoEigRoZEaHR0
# cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljcm9zb2Z0
# Q29kZVZlcmlmUm9vdC5jcmwwDQYJKoZIhvcNAQEFBQADggIBADYrovLhMx/kk/fy
# aYXGZA7Jm2Mv5HA3mP2U7HvP+KFCRvntak6NNGk2BVV6HrutjJlClgbpJagmhL7B
# vxapfKpbBLf90cD0Ar4o7fV3x5v+OvbowXvTgqv6FE7PK8/l1bVIQLGjj4OLrSsl
# U6umNM7yQ/dPLOndHk5atrroOxCZJAC8UP149uUjqImUk/e3QTA3Sle35kTZyd+Z
# BapE/HSvgmTMB8sBtgnDLuPoMqe0n0F4x6GENlRi8uwVCsjq0IT48eBr9FYSX5Xg
# /N23dpP+KUol6QQA8bQRDsmEntsXffUepY42KRk6bWxGS9ercCQojQWj2dUk8vig
# 0TyCOdSogg5pOoEJ/Abwx1kzhDaTBkGRIywipacBK1C0KK7bRrBZG4azm4foSU45
# C20U30wDMB4fX3Su9VtZA1PsmBbg0GI1dRtIuH0T5XpIuHdSpAeYJTsGm3pOam9E
# hk8UTyd5Jz1Qc0FMnEE+3SkMc7HH+x92DBdlBOvSUBCSQUns5AZ9NhVEb4m/aX35
# TUDBOpi2oH4x0rWuyvtT1T9Qhs1ekzttXXyaPz/3qSVYhN0RSQCix8ieN913jm1x
# i+BbgTRdVLrM9ZNHiG3n71viKOSAG0DkDyrRfyMVZVqsmZRDP0ZVJtbE+oiV4pGa
# oy0Lhd6sjOD5Z3CfcXkCMfdhoinEMIIFajCCBFKgAwIBAgIRAJlKA6yt5TZSowXb
# PG+NNGAwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
# ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
# T0RPIENBIExpbWl0ZWQxIzAhBgNVBAMTGkNPTU9ETyBSU0EgQ29kZSBTaWduaW5n
# IENBMB4XDTE4MTEwODAwMDAwMFoXDTE5MTEwODIzNTk1OVowgdIxCzAJBgNVBAYT
# AlVTMQ4wDAYDVQQRDAU5NDMwNDELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVBhbG8g
# QWx0bzEcMBoGA1UECQwTMzAwMCBIYW5vdmVyIFN0cmVldDErMCkGA1UECgwiSGV3
# bGV0dCBQYWNrYXJkIEVudGVycHJpc2UgQ29tcGFueTEaMBgGA1UECwwRSFAgQ3li
# ZXIgU2VjdXJpdHkxKzApBgNVBAMMIkhld2xldHQgUGFja2FyZCBFbnRlcnByaXNl
# IENvbXBhbnkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR65IcXJ2l
# DsPHw7a+1h3f5mJZtL/muA4hWHUoLT2axMk1djSI+hsSoDBZ/TPf/pNUs8v1cuiS
# qojcxkojt8fGvzSh4YSX5Dg9puWGOH3CtT4W5Y3v0ax4oX7p44YzvyxDvwJeskfK
# HHNf2HFvpd3qGwQOwGpthVCQbQ1rqj0STQIkIedjiAUMDe+aQUG3OHzXEGQw3RQP
# hHraCahPva8wcPyam+a6QRTCpG5kUWL8H6lSNYn0BfW9B7y0U8ovYK/Y0iAlvKET
# HwZXyDaGrvmzJALgcY85CtTp+TMA/Q5rItYOfEe2kgtSaYvHnAhAMI9oElhFi3ml
# nYB0drGqBWRrAgMBAAGjggGNMIIBiTAfBgNVHSMEGDAWgBQpkWD/ik366/mmarjP
# +eZLvUnOEjAdBgNVHQ4EFgQUMFjSV146chD2hvf8srdlewYoy+MwDgYDVR0PAQH/
# BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJYIZI
# AYb4QgEBBAQDAgQQMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQMCMCswKQYIKwYB
# BQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMEMGA1UdHwQ8MDow
# OKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWdu
# aW5nQ0EuY3JsMHQGCCsGAQUFBwEBBGgwZjA+BggrBgEFBQcwAoYyaHR0cDovL2Ny
# dC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQ29kZVNpZ25pbmdDQS5jcnQwJAYIKwYB
# BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC
# AQEAWUnaMukB5LV0A5H1M6mLIC/rhv0r/HFRvdE9j2lLTQCudNqmTI23S5jHD/nV
# VAacAXBsinr343EEbHl/DNDKYwEIPhswv6MpLTlOOVYRW7jaY9vEBesDGvtpS1aq
# 3bbV+Rmd6VnmZHVoyCTDJwVNlF3lhKEgsYJFFjGiGiyGw0IqGb6/FPiDvzuTbeP/
# 13XreEDAP2J33oP1S0vXpRyp72rrz5u4Ue1ilHr0ypExSr4YShrLmcODfiXHYbpb
# SmUpcWVvzKHT/pcaIhoXtfmHR6sdQ9zJ+DdS0KTYiCY9XMBesEAqcDjNeCtxa7Q6
# TIpNsmk+/MzbdtwXEX3kNHRnmzCCBXQwggRcoAMCAQICECdm7lbrSfOOq9dwovyE
# 3iIwDQYJKoZIhvcNAQEMBQAwbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRy
# dXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEi
# MCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ4
# MzhaFw0yMDA1MzAxMDQ4MzhaMIGFMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
# YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
# RE8gQ0EgTGltaXRlZDErMCkGA1UEAxMiQ09NT0RPIFJTQSBDZXJ0aWZpY2F0aW9u
# IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJHoVJLS
# ClaxrA0k3cXPRGd0mSs3o30jcABxvFPfxPoqEo9LfxBWvZ9wcrdhf8lLDxenPeOw
# BGHu/xGXx/SGPgr6Plz5k+Y0etkUa+ecs4Wggnp2r3GQ1+z9DfqcbPrfsIL0FH75
# vsSmL09/mX+1/GdDcr0MANaJ62ss0+2PmBwUq37l42782KjkkiTaQ2tiuFX96sG8
# bLaL8w6NmuSbbGmZ+HhIMEXVreENPEVg/DKWUSe8Z8PKLrZr6kbHxyCgsR9l3kgI
# uqROqfKDRjeE6+jMgUhDZ05yKptcvUwbKIpcInu0q5jZ7uBRg8MJRk5tPpn6lRfa
# fDNXQTyNUe0LtlyvLGMa31fIP7zpXcSbr0WZ4qNaJLS6qVY9z2+q/0lYvvCo//S4
# rek3+7q49As6+ehDQh6J2ITLE/HZu+GJYLiMKFasFB2cCudx688O3T2plqFIvTz3
# r7UNIkzAEYHsVjv206LiW7eyBCJSlYCTaeiOTGXxkQMtcHQC6otnFSlpUgK7199Q
# alVGv6CjKGF/cNDDoqosIapHziicBkV2v4IYJ7TVrrTLUOZr9EyGcTDppt8WhuDY
# /0Dd+9BCiH+jMzouXB5BEYFjzhhxayvspoq3MVw6akfgw3lZ1iAar/JqmKpyvFdK
# 0kuduxD8sExB5e0dPV4onZzMv7NR2qdH5YRTAgMBAAGjgfQwgfEwHwYDVR0jBBgw
# FoAUrb2YejS0Jvf6xCZU7wO94CTLVBowHQYDVR0OBBYEFLuvfgI9+qbxPISOre44
# mOzZMjLUMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MBEGA1UdIAQK
# MAgwBgYEVR0gADBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vY3JsLnVzZXJ0cnVz
# dC5jb20vQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwNQYIKwYBBQUHAQEEKTAn
# MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3
# DQEBDAUAA4IBAQBkv4PxX5qF0M24oSlXDeha99HpPvJ2BG7xUnC7Hjz/TQ10asyB
# giXTw6AqXUz1uouhbcRUCXXH4ycOXYR5N0ATd/W0rBzQO6sXEtbvNBh+K+l506tX
# RQyvKPrQ2+VQlYi734VXaX2S2FLKc4G/HPPmuG5mEQWzHpQtf5GVklnxTM6jkXFM
# fEcMOwsZ9qGxbIY+XKrELoLL+QeWukhNkPKUyKlzousGeyOd3qLzTVWfemFFmBho
# x15AayP1eXrvjLVri7dvRvR78T1LBNiTgFla4EEkHbKPFWBYR9vvbkb9FfXZX5qz
# 29i45ECzzZc5roW7HY683Ieb0abv8TtvEDhvMIIF4DCCA8igAwIBAgIQLnyHzA6T
# SlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UEBhMCR0IxGzAZBgNV
# BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
# ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlm
# aWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5MDAwMDAwWhcNMjgwNTA4MjM1OTU5
# WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAw
# DgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEjMCEG
# A1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEB
# AQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR3elnMRHrzB79MR2zuWJXP5O8W+Of
# HiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvthe4YJs+P9omidHCydv3Lj5HWg5TUj
# jsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3e9V5kAoUGFEs5v7BEvAcP2FhCoyi
# 3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQc5hc9IVKaw+A3V7Wvf2pL8Al9fl4
# 141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPiXzjbxghdR7ODQfAuADcUuRKqeZJS
# zYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmLAgaff9ULAgMBAAGjggFRMIIBTTAf
# BgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4EFgQUKZFg/4pN
# +uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C
# AQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYDVR0gBAowCDAGBgRVHSAAMEwGA1Ud
# HwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNl
# cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEF
# BQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1c3RD
# QS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkq
# hkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4MbU2x8U6ST6/COCwEzMVjEasJY6+r
# otcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQciGlEcOtTh6Qm/5iR0rx57FjFuI+9U
# US1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHfWGshqknUfDdOvf+2dVRAGDZXZxHN
# TwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HITfK7ZU2o94VFB696aSdlkClAi997
# OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46BLqioXwfy2M6FafUFRunUkcyqfS/
# ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gbqjSm/Iz13X9ljIwxVzHQNuxHoc/L
# i6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm5LLY5TjCqO3GgZw1a6lYYUoKl7RL
# QrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQFhv/K53b0CDKieoofjKOGd97SDMe
# 12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5sL6iPDAZQ+4wns3bJ9ObXwzTijIch
# hmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55ZmjoIs2475iFTZYRPAmK0H+8KCgT
# +2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6Q++6Z2H/fUnguzB9XIDj5hY5S6cx
# ggTiMIIE3gIBATCBkjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBN
# YW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0Eg
# TGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0ECEQCZ
# SgOsreU2UqMF2zxvjTRgMA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDEC
# MAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG
# CisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEICYvS8OxdX7UsWRT5GPidI62khaZ
# eHKuUDgl9KOYdDxiMA0GCSqGSIb3DQEBAQUABIIBAFiouAcvAmCXDnnJpb/B4sae
# Ihof/QLDH8Rspp4ZZHg2dRAatfho1LyIg8S9WcHt6bu5s0PtdAtxI42WXLg0ms9N
# IfnSCS5VxhTiTA1MTEvqeam6TvO0u70bPbPWerI8NeQEROIwhmdwA+bGibAxrFSj
# tO4sXE2Y90A3l7/vEScv5YN7LcL+gLhSeBRgp+S6njckAws+QyiuhsugFoGz68vB
# bNVEA72jRIsevKFtdIJNmjR1Loj40OolhYkJ45tHIVVj3+oGLlCpv+I/HyMJdotJ
# +C69/bYNKLOgWMMe2sxgW4bGxDpJGBY7F514FTHNTIEr5Q6RxHk3Qf8Vx4XxbiCh
# ggKiMIICngYJKoZIhvcNAQkGMYICjzCCAosCAQEwaDBSMQswCQYDVQQGEwJCRTEZ
# MBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMfR2xvYmFsU2lnbiBU
# aW1lc3RhbXBpbmcgQ0EgLSBHMgISESHWmadklz7x+EJ+6RnMU0EUMAkGBSsOAwIa
# BQCggf0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN
# MTkwODIzMjMyODQ1WjAjBgkqhkiG9w0BCQQxFgQUswVtJoB+BfFb1fIqkSv0eH3v
# ZtUwgZ0GCyqGSIb3DQEJEAIMMYGNMIGKMIGHMIGEBBRjuC+rYfWDkJaVBQsAJJxQ
# KTPseTBsMFakVDBSMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu
# di1zYTEoMCYGA1UEAxMfR2xvYmFsU2lnbiBUaW1lc3RhbXBpbmcgQ0EgLSBHMgIS
# ESHWmadklz7x+EJ+6RnMU0EUMA0GCSqGSIb3DQEBAQUABIIBACeJ4YYrBcpTDMnx
# BtoqbvwEqCmws0ttYWGP2lTVbvV2Lcc1T2Xanf5AQf+n4vw7c45Zt2iHFpfSqTlq
# RMcr/lZnQ9igz5ozYjY8yq9Ded/NkXcPoROl1cB7xvp8Le0R2cEPlNL7DgTBNVaQ
# ku9sCuENpTpmTszCzmhhYq2fYxyLIZZuru+2Arf+evn1lwT08UOa7OU5Tj+VKeu8
# j85jnuDxa5Hw+YMzUgYYnRkJZbIE00FWnRdXDXT/xV/8YPi14KhKyWXCJ1NpCvWQ
# lpJQxCk9HmiHcPyE4MDZgqTTPtXbNMOnMCvjbqqmz7iJo5f+C1oKz70CHWx8rW2N
# bTS6k7w=
# SIG # End signature block