HPEGreenLake.psm1

##############################################################################
# HPE GreenLake PowerShell Library
##############################################################################
##############################################################################
## (C) Copyright 2013-2022 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.
 
#>


# Set HPE GreenLake PowerShell Library Version
[Version]$ModuleVersion = '1.1.3'


# Load format files
Get-ChildItem -path $PSScriptRoot -recurse -include *.Format.PS1XML | Foreach-Object {
    Update-FormatData -AppendPath $_.FullName
}


# ------------------------------------------------------------------------------------------------------------------------------------------------
# Validate Set (dropped as only supported with PowerShell 7)

# Application names
# Class ApplicationNameValidateSet : System.Management.Automation.IValidateSetValuesGenerator {
# [String[]] GetValidValues() {

# return 'Compute Ops Management', 'Data Services Cloud Console', 'Aruba Central', 'HPE GreenLake'
# }
# }


# Application categories
# Class ApplicationCategoryValidateSet : System.Management.Automation.IValidateSetValuesGenerator {
# [String[]] GetValidValues() {

# return 'COMPUTE', 'STORAGE', 'NETWORK'
# }
# }



# ------------------------------------------------------------------------------------------------------------------------------------------------
# Variables
# ------------------------------------------------------------------------------------------------------------------------------------------------


#------------------------------------
# HPE GreenLake Common Cloud Services
#------------------------------------
[uri]$ccsSettingsUrl = 'https://common.cloud.hpe.com/settings.json'
[uri]$ccsRedirecturi = 'https://common.cloud.hpe.com/authentication/callback'
[String]$OpenidConfiguration = '/.well-known/openid-configuration'
[String]$SessionLoadAccountUri = '/authn/v1/session/load-account/'
[String]$LoadAccountUri = '/accounts/ui/v1/user/load-account/'
[String]$AuthnUri = '/api/v1/authn'
[String]$AuthnSessionUri = '/authn/v1/session'
[String]$AuthnEndSessionUri = '/authn/v1/session/end-session'
[String]$AuditLogsUri = '/auditlogs/ui/v1/search?app_slug=CCS'


#------------------------------------
# Accounts
#------------------------------------
[String]$AccountProfileContactUri = '/accounts/ui/v1/customer/profile/contact'
[String]$NewAccountUri = '/accounts/ui/v1/customer/signup'
[String]$UserLoadAccountUri = '/accounts/ui/v1/user/load-account/'
[String]$CustomerAccountsUri = '/accounts/ui/v1/customer/accounts'


#------------------------------------
# Users
#------------------------------------
[String]$UsersUri = '/ui-doorway/ui/v1/um/users'
[string]$UsersStatsUri = '/ui-doorway/ui/v1/um/stats'
[string]$UsersRolesUri = '/ui-doorway/ui/v1/um/customers/'
[string]$AuthzUsersRolesUri = "/authorization/ui/v2/customers/users/"
[string]$AuthzUsersRolesAssignmentsUri = "/authorization/ui/v2/customers/"
[string]$InviteUserUri = '/ui-doorway/ui/v1/um/invite-user'
[string]$ReInviteUserUri = '/ui-doorway/ui/v1/um/resend-invite'
[string]$UserPreferencesUri = '/accounts/ui/v1/user/profile/preferences'

#------------------------------------
# Devices
#------------------------------------
[String]$DevicesUri = '/ui-doorway/ui/v1/devices'
[String]$DevicesStatsUri = '/ui-doorway/ui/v1/devices/stats'
[String]$DevicesApplicationInstanceUri = '/ui-doorway/ui/v1/devices/application-instance'
[String]$DevicesATagsUri = '/ui-doorway/ui/v1/devices/tags'
[String]$DevicesLocationUri = '/ui-doorway/ui/v1/locations'


#------------------------------------
# License - Subscription
#------------------------------------
[String]$LicenseDevicesUri = '/ui-doorway/ui/v1/license/devices'
[String]$AddLicenseDevicesUri = '/ui-doorway/ui/v1/customers/license'
[String]$LicenseDevicesProductTypeDeviceUri = '/ui-doorway/ui/v1/license?limit=100&offset=0&product_type=DEVICE'
[String]$ServiceSubscriptionsListUri = '/ui-doorway/ui/v1/license/service-subscriptions'
[String]$AutoLicenseDevicesUri = '/ui-doorway/ui/v1/license/autolicense'


#------------------------------------
# Applications - Assignment
#------------------------------------
# [String]$ApplicationsUri = '/ui-doorway/ui/v1/applications'
# [String]$ApplicationsCatalogPerRegionUri = '/app-catalog/ui/v1/per-region-applications'
# [String]$ApplicationsProvisioned = '/ui-doorway/ui/v1/applications/provisioned'
[String]$ApplicationsProvisionsUri = '/ui-doorway/ui/v1/applications/provisions'
[String]$ApplicationsScopeAssignmentsUri = '/ui-doorway/ui/v1/um/scope-assignments'
[String]$ApplicationsAPICredentialsUri = '/authn/v1/token-management/credentials'
[string]$ResourceRestrictionsPolicyUri = "/authorization/ui/v1/resource_restrictions"
[string]$ResourceRestrictionPolicyUri = "/authorization/ui/v1/resource_restriction/"
[string]$SetResourceRestrictionPolicyUri = "/authorization/ui/v1/customers/applications"
[string]$DeleteResourceRestrictionPolicyUri = "/authorization/ui/v1/resource_restriction/delete"
[string]$ApplicationInstancesUri = "/authorization/ui/v1/application_instances"
[string]$ApplicationProvisioningUri = "/app-provision/ui/v1/provisions"


#------------------------------------------------------------------------------------------------------------------------------------------------
# Private functions
#------------------------------------------------------------------------------------------------------------------------------------------------


function NewObject {

    [CmdletBinding ()]
    Param
    (

        [Object]$InputObject,
        [Switch]$AddComputeDevice,
        [Switch]$AddStorageDevice,
        [Switch]$AddNetworkDevice

    )

    Process {

        switch ($PSBoundParameters.Keys) {
           
            'AddComputeDevice' {

                Return [PSCustomObject]@{
                    SerialNumber = $null;
                    PartNumber   = $null;
                    Tags         = [System.Collections.Hashtable]::new()

                }

            }


            'AddStorageDevice' {

                Return [PSCustomObject]@{
                    SerialNumber    = $null;
                    SubscriptionKey = $null;

                }

            }


            'AddNetworkDevice' {

                Return [PSCustomObject]@{
                    SerialNumber       = $null;
                    MacAddress         = $null;
                    CloudActivationKey = $null;

                }

            }

        }

    }

}


function Test-HPEGLConnection {   
    [CmdletBinding()] 
    Param   (     
    )
    process {

        
        # Get progress bar actual settings
        $OriginalProgressPreference = $Global:ProgressPreference
        # Disable progress bar
        $Global:ProgressPreference = 'SilentlyContinue'


        # 1 - Test DNS resolution

        $CCServer = $ccsSettingsUrl.Authority
        
        try {
            ([System.Net.Dns]::GetHostAddresses($CCServer)) | Out-Null
            write-verbose "Able to DNS Resolve the HPE Common Cloud Server Successfully : $($CCServer)"
        }
        catch {
            
            # Return to original progress bar global settings
            $Global:ProgressPreference = $OriginalProgressPreference
            Throw "$($CCServer) is not DNS Resolvable. Fix the network environment before re-running this command."
        }


        # 1 - common.cloud.hpe.com

        if ( (New-Object System.Net.Sockets.TcpClient).ConnectAsync($CCServer, 443).Wait(1000) ) {   
            write-verbose "Able to connect to $($CCServer)"
     
        }
        else {
            # Return to original progress bar global settings
            $Global:ProgressPreference = $OriginalProgressPreference
            throw "$($CCServer) cannot be connected to. Fix the network environment before re-running this command."
        }


        # 2 - sso.common.cloud.hpe.com

        # Get HPE GreenLake Common Cloud Services Settings
        $response = Invoke-RestMethod $ccsSettingsUrl -Method 'GET' 

        "Response content of GET {0} request: {1}" -f $ccsSettingsUrl, $response | Write-Verbose

        [uri]$Global:HPEGLauthorityURL = $response.authorityURL
        "HPEGLauthorityURL variable set: {0}" -f $HPEGLauthorityURL | Write-Verbose

        New-Variable -Name HPEGLoktaURL -Scope Global -Value $response.oktaURL -Option ReadOnly -ErrorAction SilentlyContinue -Force
        "HPEGLoktaURL variable set: {0}" -f $HPEGLoktaURL | Write-Verbose
        New-Variable -Name HPEGLbaseURL -Scope Global -Value $response.baseurl -Option ReadOnly -ErrorAction SilentlyContinue -Force
        "HPEGLbaseURL variable set: {0}" -f $HPEGLbaseURL | Write-Verbose
        New-Variable -Name HPEGLclient_id -Scope Global -Value $response.client_id -Option ReadOnly -ErrorAction SilentlyContinue -Force
        "HPEGLclient_id variable set: {0}" -f $HPEGLclient_id | Write-Verbose
        $SsoServer = $HPEGLauthorityURL.Authority 

        "SsoServer: {0}" -f $SsoServer | Write-Verbose

        if (  (New-Object System.Net.Sockets.TcpClient).ConnectAsync($SsoServer, 443).Wait(1000) ) {   
            write-verbose "Able to connect to the SSO Server: $($SsoServer)"
     
        }
        else {
            # Return to original progress bar global settings
            $Global:ProgressPreference = $OriginalProgressPreference
            throw "$($SsoServer) cannot be connected to. Fix the network environment before re-running this command."
        }
      

        # 3 - auth.hpe.com

        $AuthServer = ([uri]$HPEGLoktaURL).Authority
    

        if (  (New-Object System.Net.Sockets.TcpClient).ConnectAsync($AuthServer, 443).Wait(1000)) {   
            write-verbose "Able to connect to the HPE Authorization Server: $($AuthServer)"

        }
        else {
            # Return to original progress bar global settings
            $Global:ProgressPreference = $OriginalProgressPreference
            throw  "$($AuthServer) cannot be connected to. Fix the network environment before re-running this command."
        }


        # 4 - aquila-user-api.common.cloud.hpe.com

        $AquilaServer = ([uri]$HPEGLbaseURL).Authority
        
        if (  (New-Object System.Net.Sockets.TcpClient).ConnectAsync($AquilaServer, 443).Wait(1000) ) {   
            write-verbose "Able to connect to the HPE Aquila User API Cloud Server: $($AquilaServer)"
            
        }
        else {

            # Return to original progress bar global settings
            $Global:ProgressPreference = $OriginalProgressPreference
            throw "$($AquilaServer) cannot be connected to. Fix the network environment before re-running this command."
        }

        
        # Return to original progress bar global settings
        $Global:ProgressPreference = $OriginalProgressPreference
    }   
}


function Invoke-RepackageObjectWithType {   
    Param   (   
        $RawObject,
        $ObjectName,
        [boolean]   $WhatIf = $false
    )
    process {
        if ( $RawObject ) {
            $OutputObject = @()
            if ( $WhatIf ) {
                Return 
            }
            foreach ( $RawElementObject in $RawObject ) {

                $DataSetType = "HPEGreenLake.$ObjectName"
                $RawElementObject.PSTypeNames.Insert(0, $DataSetType)
                $DataSetType = $DataSetType
                $RawElementObject.PSObject.TypeNames.Insert(0, $DataSetType)
                $OutputObject += $RawElementObject
            }
            return $OutputObject
        }
        else {
            write-verbose "Null value sent to create object type."
            return
        }
    }   
}


function Invoke-RestMethodWhatIf {   
    Param   (   
        $Uri,
        $Method,
        $Headers,
        $Websession,
        $ContentType,
        $Body
    )
    process {
        if ( -not $Body ) {
            $Body = 'No Body'
        }
        write-warning "You have selected the What-IF option, so the call will not be made to HPE GreenLake console, instead you will see a preview of the RestAPI call"
        Write-host "The URI for this call will be " 
        write-host  "$Uri" -foregroundcolor green
        Write-host "The Method of this call will be "
        write-host -foregroundcolor green $Method

        if ($headers) {
            Write-host "The Header for this call will be :"
            write-host -foregroundcolor green ($Headers | ConvertTo-JSON | Out-String)  
        }
        if ($websession) {
            Write-host "The Websession for this call will be :"
            write-host -foregroundcolor green ($websession.headers | ConvertTo-JSON | Out-String)  
        }
        if ( $ContentType ) {
            write-host "The Content-Type is set to "
            write-host -foregroundcolor green ($ContentType)
        }  
        if ( $Body ) {
            write-host "The Body of this call will be:"
            write-host -foregroundcolor green ($Body | Out-String)
        }
    }
}


Function Invoke-HPEGLAutoReconnect { 
    [CmdletBinding()]
    Param(
        # An access token is valid for 2 hours - Session idle timeout is 30 minutes by default
        # Timeout in minute,
        # Default: reconnect 60 minutes before expiration
        $Timeout = 60,
        [switch]$Force
    ) 

    # Access_token expiration date
    $AccessTokenExpirationDate = $HPEGreenLakeSession.oauth2TokenCreation.AddMinutes(120)
    
    # Number of minutes before expiration of the Access_token expiration date
    $BeforeExpirationinMinutes = [math]::Round(((New-TimeSpan -Start (Get-Date) -End ($AccessTokenExpirationDate)).TotalHours ) * 60)
    
    if ( $BeforeExpirationinMinutes -gt 0) { $Expiration = $BeforeExpirationinMinutes }
    else { $Expiration = 0 }
        
    if ( $Force ) {
            
        write-verbose "Forcing Access Token refresh ! $Expiration minute(s) before expiration - Token refresh in progress..."

        Invoke-HPEGLRefreshtoken | out-null
            
        write-verbose "Refresh token successful!"
        
        # Connect-HPEGLAccount -CompanyName $HPEGreenLakeSession.companyName | out-null
        # write-verbose "CCS user session creation successful!"

    }
    # elseif ($Expiration -eq 0) {

    # write-verbose "The access token refresh cannot be executed! Your session has been inactive for too long! You need to reconnect to HPE GreenLake..."

    # Throw "Your session has been inactive for too long! You need to reconnect to HPE GreenLake..."

    # }
    elseif ( $Expiration -le $Timeout ) {
            
        write-verbose "Access Token refresh required ! $Expiration minute(s) before expiration - Token refresh in progress..."

        Invoke-HPEGLRefreshtoken | out-null
            
        write-verbose "Refresh token successful!"
        
        # Connect-HPEGLAccount -CompanyName $HPEGreenLakeSession.companyName | out-null
        # write-verbose "CCS user session creation successful!"

    }
    else {
        
        write-verbose "No Access Token refresh required ! $Expiration minute(s) before expiration - Allowable time to refresh/reconnect is $Timeout minutes."
    }  
}


#------------------------------------------------------------------------------------------------------------------------------------------------
# Public functions
#------------------------------------------------------------------------------------------------------------------------------------------------


function Invoke-HPEGLWebRequest {  
    <#
     .SYNOPSIS
    Set user roles in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet sets users roles and permissions in the HPE GreenLake account.
    Roles are groups of permissions that grant users access to the HPE GreenLake applications.
 
    Roles are assigned to an application in all regions. If you need to further limit the scope of resources
    a user role can access, you can use the resource restriction policy feature (Set-HPEGLResourceRestrictionPolicy).
 
    .PARAMETER UriAdd
    The uri to add to $HPEGLBaseUrl global variable that identifies the required HPE GreenLake resource (eg. '/ui-doorway/ui/v1/devices').
 
    .PARAMETER Body
    Body for the request. Required if the method is POST or PUT.
 
    .PARAMETER Method
    The request HTTP Method.
 
            * "GET" (default) to get a resource from the appliance (read)
            * "POST" to create a new resource
            * "PUT" to modify a resource (write)
            * "PATCH" to modify a resource (write), with specific attributes set to values, other attributes should be set to $null.
            * "DELETE" to delete a resource
 
    .PARAMETER WebSession
    Web session object containing information about the HPE GreenLake session, including cookies and credentials.
    Default uses $HPEGreenLakeSession.session global variable.
 
    .PARAMETER WhatIfBoolean
    Switch parameter to show the user what would happen if the cmdlet was to run without actually running it.
 
    .EXAMPLE
    Invoke-HPEGLWebRequest -UriAdd '/ui-doorway/ui/v1/license/devices'
 
    Run a GET web request on 'https://aquila-user-api.common.cloud.hpe.com/ui-doorway/ui/v1/license/devices' using the web session object
    $HPEGreenLakeSession.session containing information about the HPE GreenLake session.
 
    .EXAMPLE
    Invoke-HPEGLWebRequest '/ui-doorway/ui/v1/um/users' -WhatIfBoolean $True
 
    Run a GET web request on 'https://aquila-user-api.common.cloud.hpe.com/ui-doorway/ui/v1/um/users' with the WhatIfBoolean parameter to see
    the potential effects of the command before committing to it.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    The output of the cmdlet depends upon the format of the content that is retrieved.
    If the request returns JSON strings, Invoke-HPEGLWebRequest returns a PSObject that represents the strings.
         
          
    #>

    Param   (   
        [Parameter (Mandatory)]
        [ValidateScript({ if ($_.startswith('/')) { $true } else { throw "-UriAdd must being with a '/' (eg. /ui-doorway/ui/v1/devices) in its value. Please correct the value and try again." } })]
        [String]$UriAdd,

        $Body, 

        [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",

        $WebSession = $HPEGreenLakeSession.session, 

        $WhatIfBoolean = $false

    )
    Process {

        try {

            get-item variable:HPEGLbaseURL -ErrorAction Stop | Out-Null
    
        }
        catch {
            Throw "Error - No session found! Connect-HPEGL must be executed first!"
    
        }

        try {
            Invoke-HPEGLAutoReconnect 
        }
        catch {
            Throw $_
        }

        $MyURI = $HPEGLbaseURL + $UriAdd
        
        Clear-Variable -Name InvokeReturnData -ErrorAction SilentlyContinue
        
        if ( $WhatIfBoolean ) {
            
            invoke-RestMethodWhatIf -Uri $MyUri -Method $Method -Body $Body -WebSession $WebSession -ContentType 'application/json'
        
        }
        
        else {

            write-verbose "About to make rest call to URL $MyUri."

            try {
           
                $InvokeReturnData = Invoke-WebRequest -Uri $MyUri -Method $Method -Body $Body -WebSession $WebSession -ContentType 'application/json' #-ErrorAction Stop

                if ($Body) {
                    "Request payload: {0}" -f ($Body | Out-String) | Write-Verbose

                }

                Write-verbose "Raw Response = $InvokeReturnData"

              
            }
            
            catch [System.Net.WebException] {

                Write-verbose "Exception thrown!"

                # Get Exception type
                $exception = $_.Exception
                do {
                    "Exception Type: {0}" -f $exception.GetType().Name | Write-Verbose
                    $exception = $exception.InnerException
                } while ($exception)

                # Get exception stream
                $result = $_.Exception.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($result)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd() 

                Write-verbose "Raw Response = $responseBody"
                
                if ($Body) {
                    "Request payload: `n{0}" -f ($Body | Out-String) | Write-Verbose
                }

                if ($HPEGreenLakeSession.session.headers) {
                    "Request headers: " | Write-Verbose

                    foreach ($Param in $HPEGreenLakeSession.session.headers.Keys) { 
                    
                        Write-Verbose "`t`t$Param : $($HPEGreenLakeSession.session.headers[$Param])" 
                    
                    }
                }

                $response = $responseBody | ConvertFrom-Json
                    
                $ResponseCode = $response.code
                $ResponseDetail = $response.detail
                $ResponseStatus = $Response.Status

                if ($ResponseCode) {
                    "Request failed with the following Status: `n`tHTTPS Return Code = {0} `n`tHTTPS Return Code Description = {1} `n`tHTTPS Return Code Details = {2}" -f $ResponseStatus, $ResponseCode, $ResponseDetail | write-verbose
                }  
                
                $StatusCode = [int]$_.Exception.Response.StatusCode
                $ExceptionCode = $_.Exception.Response.StatusCode.value__
                
                if ($StatusCode -and -not $ResponseCode) {
                    "HTTPS Return Code = {0}" -f $StatusCode | Write-Verbose
                }
                elseif ($ExceptionCode -and -not $ResponseCode) {
                    "HTTPS Return Code = {0}" -f $ExceptionCode | Write-Verbose
                }


                if ($ResponseStatus -and $ResponseCode -and $ResponseDetail) {
                    Throw "Error {0} - {1} : {2}" -f $ResponseCode, $ResponseStatus, $ResponseDetail
                }
                elseif ($ResponseStatus -and $ResponseCode -and -not $ResponseDetail) {
                    Throw "Error {0} - {1}" -f $ResponseCode, $ResponseStatus
                }
                elseif ($ResponseStatus -and -not $ResponseCode -and -not $ResponseDetail) {
                    Throw "Error {0}" -f $ResponseStatus
                }
                elseif ($responseBody -match "Unauthorized" ) {
           
                    Throw "Error - Session has expired or been closed! Connect-HPEGL must be executed again!"

                }
                elseif ($response.message ) {
           
                    Throw "Error - $($response.message)"

                }
                elseif ($response.detail ) {

                    if ($response.detail.msg) {

                        $Detailmsg = ($response.detail | % { $_.msg + ": " + $_.type }) -join " AND "

                        Throw "Error - $Detailmsg"
                    }
                    else {

                        Throw "Error - $($response.detail)"
                    }

                }
                else {

                    Throw "Error - $($response | Out-String)"
 
                }
                      
               
            }

            catch [System.Management.Automation.RuntimeException] {

                Write-verbose "Exception thrown!"

                # Get exception type
                $exception = $_.Exception
                do {
                    "Exception Type: {0}" -f $exception.GetType().Name | Write-Verbose
                    $exception = $exception.InnerException
                } while ($exception)

                # Get exception information

                $Response = $_.Exception.Response | convertto-json -depth 10 
                $StatusCode = [int]$_.Exception.Response.StatusCode
                $ExceptionCode = $_.Exception.Response.StatusCode.value__
                $ExceptionText = $_.Exception.Response.StatusDescription + $_.Exception.Response.ReasonPhrase 
                    
                Write-verbose "Raw Response = $Response"

                "`nRequest failed with the following Status:`r`n`tHTTPS Return Code = {0} `r`n`tHTTPS Return Code Description = {1} `n" -f $ExceptionCode, $ExceptionText | write-verbose

                
                if ($Body) {
                    "Request payload: {0}" -f ($Body | Out-String) | Write-Verbose
                }
                if ($Headers) {
                    "Request headers: {0}" -f ($headers | Out-String) | Write-Verbose
                }


                if ( $StatusCode -eq 400 ) {
                    Throw "Error status Code: 400 (Bad Request)"
                    
                } 
        
                elseif ( $StatusCode -eq 401 ) {
                    Throw "Error status Code: 401 (Unauthorized) - Your session has expired, please log in again!"
                    
                } 

                elseif ( $StatusCode -eq 403 ) {
                    Throw "Error status Code: 403 (Forbidden) - Your session has expired or you do not have sufficient rights to perform this action!"
                    
                } 

                elseif ( $StatusCode -eq 412 ) {
                    Throw "Error status Code: 412 (Precondition failed) - Please verify the content of the payload request!"
                    
                } 

                elseif ( $StatusCode -eq 408 ) {
                    Throw "Error status Code: 408 (Request Timeout) - Please try again!"
                    
                }

                else {
                    Throw "Error {0} - {1}" -f $StatusCode, $ExceptionText
                }
            }       
                
        }

    
        if ($InvokeReturnData) {

            if ($InvokeReturnData -match "doctype html") {
                    
                Write-verbose "HTML doctype response detected ! Throwing exception!"
                    
                Throw "Error - Session has expired or been closed! Connect-HPEGL must be executed again!"
                    
            }

            if ($InvokeReturnData.content) {

                Write-verbose "Response Detected with a Content property!"

                $InvokeReturnData = $InvokeReturnData.content
    
            }
            
            try {

                $InvokeReturnData = ConvertFrom-Json $InvokeReturnData -ErrorAction Stop

                if ($InvokeReturnData -eq "OK") {

                    Write-verbose "Response Detected with a 'OK' response!"
                    return           
                }   

                Write-verbose "Response Detected as JSON content!"

                return $InvokeReturnData   
            }
            catch {

                throw $InvokeReturnData
            }                    
        }
            
    }         
}


# Thanks to Darren Robinson for this function!
# https://github.com/darrenjrobinson/JWTDetails
# https://blog.darrenjrobinson.com
function Get-HPEGLJWTDetails {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
        [string]$token
    )
  
    <#
   
  .SYNOPSIS
  Decode a JWT Access Token and convert to a PowerShell Object.
  JWT Access Token updated to include the JWT Signature (sig), JWT Token Expiry (expiryDateTime) and JWT Token time to expiry (timeToExpiry).
   
  .DESCRIPTION
  Decode a JWT Access Token and convert to a PowerShell Object.
  JWT Access Token updated to include the JWT Signature (sig), JWT Token Expiry (expiryDateTime) and JWT Token time to expiry (timeToExpiry).
   
  Thanks to Darren Robinson for this function!
  https://github.com/darrenjrobinson/JWTDetails
  https://blog.darrenjrobinson.com
 
  .PARAMETER token
  The JWT Access Token to decode and update with expiry time and time to expiry
   
  .INPUTS
  Token from Pipeline
   
  .OUTPUTS
  PowerShell Object
   
  .EXAMPLE
  Get-HPEGLJWTDetails
   
  .EXAMPLE
  PS> Get-HPEGLJWTDetails($myAccessToken)
  or
  PS> $myAccessToken | Get-JWTDetails
  tenant_id : cd988f3c-710c-43eb-9e25-123456789
  internal : False
  pod : uswest2
  org : myOrd
  identity_id : 1c818084624f8babcdefgh9a4
  user_name : adminDude
  strong_auth_supported : True
  user_id : 100666
  scope : {read, write}
  exp : 1564474732
  jti : 1282411c-ffff-1111-a9d0-f9314a123c7a
  sig : SWPhCswizzleQWdM4K8A8HotX5fP/PT8kBWnaaAf2g6k=
  expiryDateTime : 30/07/2019 6:18:52 PM
  timeToExpiry : -00:57:37.4457299
   
  #>

  
    if (!$token.Contains(".") -or !$token.StartsWith("eyJ")) { Write-Error "Invalid token" -ErrorAction Stop }
  
    # Token
    foreach ($i in 0..1) {
        $data = $token.Split('.')[$i].Replace('-', '+').Replace('_', '/')
        switch ($data.Length % 4) {
            0 { break }
            2 { $data += '==' }
            3 { $data += '=' }
        }
    }
  
    $decodedToken = [System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String($data)) | ConvertFrom-Json 
    Write-Verbose "JWT Token:"
    Write-Verbose $decodedToken
  
    # Signature
    foreach ($i in 0..2) {
        $sig = $token.Split('.')[$i].Replace('-', '+').Replace('_', '/')
        switch ($sig.Length % 4) {
            0 { break }
            2 { $sig += '==' }
            3 { $sig += '=' }
        }
    }
    Write-Verbose "JWT Signature:"
    Write-Verbose $sig
    $decodedToken | Add-Member -Type NoteProperty -Name "sig" -Value $sig
  
    # Convert Expiry time to PowerShell DateTime
    $orig = (Get-Date -Year 1970 -Month 1 -Day 1 -hour 0 -Minute 0 -Second 0 -Millisecond 0)
    $timeZone = Get-TimeZone
    $utcTime = $orig.AddSeconds($decodedToken.exp)
    $offset = $timeZone.GetUtcOffset($(Get-Date)).TotalMinutes #Daylight saving needs to be calculated
    $localTime = $utcTime.AddMinutes($offset)     # Return local time,
      
    $decodedToken | Add-Member -Type NoteProperty -Name "expiryDateTime" -Value $localTime
      
    # Time to Expiry
    $timeToExpiry = ($localTime - (get-date))
    $decodedToken | Add-Member -Type NoteProperty -Name "timeToExpiry" -Value $timeToExpiry
  
    return $decodedToken
}
  
  
############################ CONNECTION ###################################


Function Connect-HPEGL { 
    <#
        .SYNOPSIS
        Initiate a connection to the HPE GreenLake platform.
 
        .DESCRIPTION
        This Cmdlet establishes a connection to the HPE GreenLake platform. When the connection is successful, the user establishes a session
        for use with subsequent Cmdlet requests. OAuth2 Access Token, Id Token, Refresh token, cookies and more are returned in the global
        variable ${Global:HPEGreenLakeSession}.
         
        Minimum required privileges: Read-only.
         
        .PARAMETER Credential
        Set of security credentials such as a username and password to establish a connection to the HPE GreenLake platform.
 
        .PARAMETER UserName
        Warning: This parameter is now obsolete. Please transition to using the -Credential parameter.
         
        username to authenticate.
 
        .PARAMETER Password
        Warning: This parameter is now obsolete. Please transition to using the -Credential parameter.
         
        Password to establish a connection to the HPE GreenLake platform. Can be either System.String or SecureString value.
 
        .PARAMETER CompanyName
        Name of a company account available on the HPE GreenLake platform (can be retrieved using Get-HPEGLAccounts). This is an optional parameter that can be used when
        you have more than one company accounts on the HPE GreenLake platform. By default, the cmdlet selects the first
        available account.
                 
        .INPUTS
        None. You cannot pipe objects to this Cmdlet.
 
        .OUTPUTS
        HPEGreenLakeSession
 
        When a valid connection is established with the HPE GreenLake platform, several properties are added to ${Global:HPEGreenLakeSession}
        connection tracker variable. The object returned will contain the following public properties:
         
             ==================================================================================================
             | Name | Type | Value |
             |-------------------------------------------------------------------------------------------------
             | session | WebrequestSession | Web request session object |
             --------------------------------------------------------------------------------------------------
             | oauth2AccessToken | String | OAuth2 access token string returned from API |
             --------------------------------------------------------------------------------------------------
             | oauth2IdToken | String | OAuth2 ID Token string returned from API |
             --------------------------------------------------------------------------------------------------
             | oauth2RefreshToken | String | OAuth2 refresh token string returned from API |
             --------------------------------------------------------------------------------------------------
             | userName | String | Name of the user used for authentication |
             --------------------------------------------------------------------------------------------------
             | customerId | String | Customer ID value |
             --------------------------------------------------------------------------------------------------
             | companyName | String | Name of the Company account |
             --------------------------------------------------------------------------------------------------
             | oauth2TokenCreation | Datetime | OAuth2 token creation datetime value |
             --------------------------------------------------------------------------------------------------
             | oauth2TokenCreationEpoch | String | Unix time since creation of the OAuth2 token |
             --------------------------------------------------------------------------------------------------
             | userSessionIdleTimeout | String | User session timeout in minutes |
             --------------------------------------------------------------------------------------------------
             | apiCredentials | ArrayList | Collection of application API credentials |
             ==================================================================================================
 
 
         .EXAMPLE
         Connect-HPEGL
 
         Connect to the default company account on the HPE GreenLake platform. The user will be prompted for username and password.
 
         .EXAMPLE
         $Username = "Sean@gmail.com"
         $Secpasswd = read-host "Please enter your HPE GreenLake password" -AsSecureString
         $Credentials = New-Object System.Management.Automation.PSCredential ($Username, $Secpasswd)
         Connect-HPEGL -Credential $Credentials
 
         Connect the user Sean@gmail.com to the default company account on the HPE GreenLake platform using a PSCredential object.
 
         .EXAMPLE
         Connect-HPEGL -Credential $Credentials -CompanyName "My_Company"
 
         Connect the user Sean@gmail.com to the company account named "My_Company" on the HPE GreenLake platform using a PSCredential object.
            
         .LINK
         Disconnect-HPEGL
         Connect-HPEGLAccount
         Get-HPEGLAccounts
         Get-HPEGLAccount
         Get-HPEGLUserPreference
         [${Global:HPEGreenLakeSession}]
         [${Global:HPEGLLibraryVersion}]
 
          
   #>

    [CmdletBinding(DefaultParameterSetName = "PSCredential" )]
    Param( 
        [Parameter (Mandatory, ParameterSetName = 'PSCredential')]
        [ValidateNotNullOrEmpty()]
        [Alias ('PSCredential')]
        [PSCredential]$Credential,

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

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

        [Parameter (Mandatory = $False, ParameterSetName = 'PSCredential')]        
        [Parameter (Mandatory = $False, ParameterSetName = 'UsernamePassword')]
        [ValidateNotNullOrEmpty()]
        [String]$CompanyName

    )


    Begin {

        # Changing default TLS to 1.2 from 1.0
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        
        # Test connectivity with HPE GreenLake servers
        
        try {
            Test-HPEGLConnection
        }
        catch {
            $PSCmdlet.ThrowTerminatingError($PSItem)
        }


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

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

        }

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

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

        }

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

            $decryptPassword = $Password

        }

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

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

        }

    }

    Process { 

      

        #-----------------------------------------------------------Authentication to HPE GreenLake Common Cloud Services-----------------------------------------------------------------------------

        ## 1-Get HPE GreenLake Common Cloud Services Authorization endpoint

        $url = $HPEGLauthorityURL.OriginalString + $OpenidConfiguration

        try {
            $response = Invoke-RestMethod $url -Method 'GET' 

            $authEndpoint = $response.authorization_endpoint 
            $tokenEndpoint = $response.token_endpoint

        }
        catch {
            $PSCmdlet.ThrowTerminatingError($PSitem)

        }

        ## 2-Generate PKCE code verifier and code challenge

        $pkceTemplate = [pscustomobject][ordered]@{  
            code_verifier  = $null  
            code_challenge = $null   
        }  

        $codeVerifier = -join (((48..57) * 4) + ((65..90) * 4) + ((97..122) * 4) | Get-Random -Count 128 | ForEach-Object { [char]$_ })

        $hashAlgo = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
        $hash = $hashAlgo.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($codeVerifier))
        $b64Hash = [System.Convert]::ToBase64String($hash)
        $code_challenge = $b64Hash.Substring(0, 43)
      
        $code_challenge = $code_challenge.Replace("/", "_")
        $code_challenge = $code_challenge.Replace("+", "-")
        $code_challenge = $code_challenge.Replace("=", "")

        $pkceChallenges = $pkceTemplate.PsObject.Copy()
        $pkceChallenges.code_challenge = $code_challenge
        $pkceChallenges.code_verifier = $codeVerifier 

        $codeChallenge = $pkceChallenges.code_challenge
        $codeVerifier = $pkceChallenges.code_verifier

        "Code verifier: {0}" -f $codeVerifier | Write-Verbose
        "Code challenge: {0}" -f $codeChallenge | write-Verbose


        ## 3-Get statetoken using code challenge to https://sso.common.cloud.hpe.com/as/authorization.oauth2
         
        $headers = @{} 
        $headers["Content-Type"] = "application/json"

        do {  
    
            $url = "{0}?client_id={1}&redirect_uri={2}&response_type=code&scope=openid%20profile%20email&code_challenge={3}&code_challenge_method=S256" -f $authEndpoint, $HPEGLclient_id, $ccsRedirecturi, $codeChallenge

            $response = Invoke-webrequest $url -Method 'GET' -Headers $headers -SessionVariable 'SsoSession' 
  
            # Capturing state token
            $stateToken = ($response.tostring() -split "[`r`n]" | select-string -Pattern '(?:"stateToken":")(.*?)(?:")').Matches | % { $_.groups[1].Value }

        } until ( -not $stateToken.Contains("\") )

        "State token: {0}" -f $stateToken | Write-Verbose

        ## 4-Authenticate and consent to https://auth.hpe.com/api/v1/authn

        $payload = @{}
        $payload["options"] = @{multiOptionalFactorEnroll = $True; warnBeforePasswordExpired = $True }
        $payload["password"] = $decryptPassword
        $payload["stateToken"] = $stateToken
        $payload["username"] = $UserName
        $payload = $payload | ConvertTo-Json

        $url = $HPEGLoktaURL + $AuthnUri 
        
        # do {
        try {
            $responseccsauthclient = Invoke-webrequest $url -Method 'POST' -Body $payload -ContentType 'application/json' -ErrorAction stop
                   
        }
        catch {
            throw "Connection error! Invalid username or password!"
             
        }

        
        $href = ($responseccsauthclient.Content | Convertfrom-Json)._links.next.href
        # href is usually like: "https://auth.hpe.com/login/token/redirect?stateToken=00kJygvJiy92zrYIXhROhpXMiF2NsC6zAT3SjF5XhF"

        "Href link: {0}" -f $href | write-Verbose


        ## 5-Acquire authorization code

        try {
            $response1 = Invoke-WebRequest $href -Method Head -MaximumRedirection 0 -ErrorAction SilentlyContinue -ErrorVariable redirected1 

            "Acquire authorization code: response1={0}" -f $response1 | write-Verbose

        }
        catch {

            $err = $_
        }
    

        If ( ($PSVersionTable.PSVersion.ToString()).Split('.')[0] -eq 5) {
            if ($response1.StatusCode -eq 302) {
                $redirecturl1 = $response1.Headers.Location

            }
        }
        else {
            if ($redirected1.ErrorRecord.Exception.Response.StatusCode.value__ -eq 302) {
                $redirecturl1 = $redirected1.ErrorRecord.Exception.Response.Headers.Location.AbsoluteUri

            }
        }

        "Redirected URL 1: {0}" -f $redirecturl1 | Write-Verbose
        # $redirecturl1 = https://sso.common.cloud.hpe.com/sp/eyJpc3MiOiJodHRwczpcL1wvYXV0aC5ocGUuY29tXC9vYXV0aDJcL2F1czQzcGYwZzhtdmg0bnR2MzU3In0/cb.openid?code=saapfsSV5QY7fAOte3pUycmuCQjBw_wMOOvAxmOdnnQ&state=UJsI5pLgrFl4EGhK0sRrfgIRNrUEqi


        try {  
            $response2 = Invoke-WebRequest $redirecturl1 -Method Get -MaximumRedirection 0 -ErrorAction SilentlyContinue -ErrorVariable redirected2 -WebSession $SsoSession 

            "Acquire authorization code: response2={0}" -f $response2 | write-Verbose

        }
        catch {
            $err = $_

        }
   

        If ( ($PSVersionTable.PSVersion.ToString()).Split('.')[0] -eq 5) {
            if ($response2.StatusCode -eq 302) {
                $redirecturl2 = $response2.Headers.Location
            }
        }
        else {
            if ($redirected2.ErrorRecord.Exception.Response.StatusCode.value__ -eq 302) {
                $redirecturl2 = $redirected2.ErrorRecord.Exception.Response.Headers.Location.AbsoluteUri

            }
        }

        "Redirected URL 2: {0}" -f $redirecturl2 | Write-Verbose
        # $redirecturl2 = "https://sso.common.cloud.hpe.com/as/LLzJ7/resume/as/authorization.ping"

        do {
  
            try {
                $response3 = Invoke-WebRequest $redirecturl2 -Method Get -MaximumRedirection 0 -ErrorAction SilentlyContinue -ErrorVariable redirected3 -WebSession $SsoSession

                "Acquire authorization code: response3={0}" -f $response3 | write-Verbose

            }
            catch {
                $err = $_

            }
   
            If ( ($PSVersionTable.PSVersion.ToString()).Split('.')[0] -eq 5) {
                if ($response3.StatusCode -eq 302) {
                    $redirecturl3 = $response3.Headers.Location

                }
            }
            else {
                if ($redirected3.ErrorRecord.Exception.Response.StatusCode.value__ -eq 302) {
                    $redirecturl3 = $redirected3.ErrorRecord.Exception.Response.Headers.Location.AbsoluteUri

                }
            }
          
        } until ($redirecturl3)
        

        "Redirected URL 3: {0}" -f $redirecturl3 | Write-Verbose
        # $redirecturl3 = https://common.cloud.hpe.com/authentication/callback?code=QgtvNW7vwcIqqXL5H_SOn3EFRqbxPTjqP8oGmXJ_

        $code = ($redirecturl3  | select-string -Pattern '(?<=code=)(.*)').Matches | % Value 
        
        "Authorization Code: {0}" -f $code | Write-Verbose


        ## 6-Post Authorization code + code verifier to https://sso.common.cloud.hpe.com/as/token.oauth2

        $tokenParams = @{
            'client_id'     = $HPEGLclient_id
            'redirect_uri'  = $ccsRedirecturi
            'code'          = $code
            'code_verifier' = $codeVerifier
            'grant_type'    = 'authorization_code'
        }

        try {
            $response4 = Invoke-WebRequest -Method Post -Uri $tokenEndpoint -Body $tokenParams -ContentType 'application/x-www-form-urlencoded' 
   
        }
        catch {
      
            "Create CCS session payload content: {0}" -f ($tokenParams | Out-String) |  Write-Verbose

            if ($_.ErrorDetails.Message) {
                Write-Warning $_.ErrorDetails
            }

            Throw $_.Exception.Message
   
        }


        ## 7-Get HPE GreenLake Common Cloud Services Access token, ID token and Refresh token

        $Oauth2AccessToken = ($response4.content | ConvertFrom-Json).access_token
        "OAuth2 Access Token: {0}" -f $oauth2AccessToken | Write-Verbose
        
        $Oauth2IdToken = ($response4.content | ConvertFrom-Json).id_token
        "OAuth2 ID Token: {0}" -f $oauth2IdToken | Write-Verbose
        
        $Oauth2RefreshToken = ($response4.content | ConvertFrom-Json).refresh_token
        "OAuth2 Refresh Token: {0}" -f $oauth2RefreshToken | Write-Verbose

        
        ## 8- Set HPEGreenLakeSession global variable
     
        $Global:HPEGreenLakeSession = [System.Collections.ArrayList]::new()
        
        $SessionInformation = [PSCustomObject]@{
            session                  = $Null
            oauth2AccessToken        = $Oauth2AccessToken
            oauth2IdToken            = $Oauth2IdToken
            oauth2RefreshToken       = $Oauth2RefreshToken
            username                 = $UserName
            customerId               = $Null
            companyName              = $Null
            oauth2TokenCreation      = [datetime]$(Get-Date)
            oauth2TokenCreationEpoch = $((New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds) 
            userSessionIdleTimeout   = $Null
            apiCredentials           = [System.Collections.ArrayList]::new()
        }

        [void]$global:HPEGreenLakeSession.add($SessionInformation)

        $Global:HPEGreenLakeSession = Invoke-RepackageObjectWithType -RawObject $HPEGreenLakeSession -ObjectName 'Connection'
        # $global:HPEGreenLakeSession.apiCredentials = [System.Collections.ArrayList]::new()

        Write-Verbose "`$HPEGreenLakeSession global variable set!" 


        ## 9-Create session with Company account

        try {

            if ($CompanyName) {
                $CCSSession = Connect-HPEGLAccount -CompanyName $CompanyName -Oauth2IdToken  $oauth2IdToken -Oauth2AccessToken $oauth2AccessToken
    
            }
            else {
                $CCSSession = Connect-HPEGLAccount -Oauth2IdToken $Oauth2IdToken -Oauth2AccessToken $Oauth2AccessToken
    
            }

    
        }
        catch {
                    
            $PSCmdlet.ThrowTerminatingError($PSitem)
                   
        }

        # ## 9-Get user session idle timeout

        Write-Verbose "About to make rest call to get user preference information"

        $UserSessionTimeout = ((Get-HPEGLUserPreference).idle_timeout) / 60
    
        $Global:HPEGreenLakeSession.userSessionIdleTimeout = $UserSessionTimeout
        
        Write-Verbose "User preference: $UserSessionTimeout minutes session idle timeout has been set in `$HPEGreenLakeSession global variable!" 
        
        Write-Verbose "Connection to HPE GreenLake successful!" 
    
        return $HPEGreenLakeSession 

    }
    
}


Function Disconnect-HPEGL { 
    <#
        .SYNOPSIS
        Logoff from the HPE GreenLake platform.
 
        .DESCRIPTION
        This Cmdlet logs out the current user, ending the user's session with HPE GreenLake platform.
 
        .EXAMPLE
        Disconnect-HPEGL
 
        Disconnect the session with HPE GreenLake platform.
 
        .INPUTS
        None. You cannot pipe objects to this Cmdlet.
 
        .OUTPUTS
        System.String
            Returns "<email address> session disconnected!"
 
        .LINK
        Connect-HPEGL
        Connect-HPEGLAccount
        Get-HPEGLAccounts
        Get-HPEGLAccount
        [${Global:HPEGreenLakeSession}]
          
   #>

    [CmdletBinding()]
    Param() 


    Process { 

        if (-not $HPEGreenLakeSession) {
            Throw "Error - No HPE GreenLake session found!"
    
        }
        else {       

            # 1 - Remove HPE GreenLake Platform Company account session

            $url = $HPEGLbaseURL + $AuthnEndSessionUri

       
            try {

                "About to make rest call to URL $url to remove HPE GreenLake Company account session" | Write-Verbose

                $InvokeReturnData = Invoke-WebRequest -Method GET -Uri $url -WebSession $HPEGreenLakeSession.session -ContentType 'application/json' 
            
                "{0}: company account session removed successfully!" -f $HPEGreenLakeSession.companyName | Write-Verbose

                # Write-verbose "Raw Response = $InvokeReturnData"

            }
            catch {

                $Response = $_.Exception.Response | convertto-json -depth 10 

                $ExceptionCode = $_.Exception.Response.StatusCode.value__
                $ExceptionText = $_.Exception.Response.StatusDescription + $_.Exception.Response.ReasonPhrase 
            
                "Request payload: {0}" -f ($Payload | Out-String) | Write-Verbose

                "`nRequest failed with the following Status:`r`n`tHTTPS Return Code = {0} `r`n`tHTTPS Return Code Description = {1} `n" -f $ExceptionCode, $ExceptionText | write-verbose

                # "`nRaw Response = {0}" -f $Response | Write-verbose

                $PSCmdlet.ThrowTerminatingError($PSitem)
           
            }


            # 2-Revoke CCS OAuth2 token

            $url = $HPEGLauthorityURL.OriginalString + $OpenidConfiguration
        
            $response = Invoke-RestMethod $url -Method 'GET' 

            $RevocationEndpoint = $response.revocation_endpoint


            $payload = @{
                'client_id'       = 'aquila-user-auth'
                'token'           = $HPEGreenLakeSession.oauth2AccessToken
                'token_type_hint' = 'access_token'

            } 

            write-verbose "About to make rest call to URL $RevocationEndpoint to revoke CCS OAuth2 token."

            try {
                $InvokeReturnData = Invoke-webrequest -Uri $RevocationEndpoint -Method 'POST' -Body $payload -ContentType "application/x-www-form-urlencoded" -ErrorAction stop -WebSession $HPEGreenLakeSession.session
           
                "{0}: CCS OAuth2 token revoked!" -f $HPEGreenLakeSession.username | Write-Verbose

                $_username = $HPEGreenLakeSession.username
                 
                # Clear $HPEGreenLakeSession global variable
                Clear-Variable HPEGreenLakeSession -Scope Global

                # Remove $HPEGLbaseURL global variable
                Remove-Variable HPEGLbaseURL -Scope Global -Force

                return ("{0} session disconnected!" -f $_username )
            }
        
            catch {

                Write-verbose "Exception thrown!"

                # Get Exception type
                $exception = $_.Exception
                do {
                    "Exception Type: {0}" -f $exception.GetType().Name | Write-Verbose
                    $exception = $exception.InnerException
                } while ($exception)

                # Get exception stream
                $result = $_.Exception.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($result)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd() 


                Write-verbose "Raw Response = $responseBody"
            
                $response = $responseBody | ConvertFrom-Json

                    
                    
                if ($Body) {
                    "Request payload: {0}" -f ($Body | Out-String) | Write-Verbose
                }
                if ($Headers) {
                    "Request headers: {0}" -f ($headers | Out-String) | Write-Verbose
                }

                Throw "Error - $responseBody"          
            }
        }
    }
    
}
    

Function Invoke-HPEGLRefreshtoken { 
    [CmdletBinding()]
    Param() 

    Process {
        
        if (-not $HPEGreenLakeSession) {

            Throw "Error - No HPE GreenLake session found!"
    
        }
        else {   

            $url = $HPEGLauthorityURL.OriginalString + $OpenidConfiguration

            try {
                $response = Invoke-RestMethod $url -Method 'GET' 

                $tokenEndpoint = $response.token_endpoint
        
            }
            catch {
                $PSCmdlet.ThrowTerminatingError($PSitem)
            }
    
    
            $Body = @{
                'grant_type'    = 'refresh_token'
                'client_id'     = 'aquila-user-auth'
                'refresh_token' = $HPEGreenLakeSession.oauth2RefreshToken
            } 
    

            write-verbose "About to make rest call to URL $tokenEndpoint"
    
            try {

                $InvokeReturnData = Invoke-webrequest -Uri $tokenEndpoint -Method 'POST' -ContentType "application/x-www-form-urlencoded" -Body $Body -WebSession $HPEGreenLakeSession.session
         
                "`nRaw Response = {0}" -f $InvokeReturnData | Write-verbose
             
                $NewAccessToken = ($InvokeReturnData | ConvertFrom-Json).access_token
                "New access token = {0}" -f $NewAccessToken | Write-verbose

                $NewRefreshToken = ($InvokeReturnData | ConvertFrom-Json).refresh_token
                "New refresh token = {0}" -f $NewRefreshToken | Write-verbose

                $NewIdToken = ($InvokeReturnData | ConvertFrom-Json).id_token
                "New ID token = {0}" -f $NewIdToken | Write-verbose


                # Set new global variables
                $global:HPEGreenLakeSession.oauth2AccessToken = $NewAccessToken 
                Write-Verbose "`$HPEGreenLakeSession has been updated with new access_token!"

                $global:HPEGreenLakeSession.oauth2RefreshToken = $NewRefreshToken
                Write-Verbose "`$HPEGreenLakeSession has been updated with new refresh_token!"

                $global:HPEGreenLakeSession.oauth2IdToken = $NewIdToken 
                Write-Verbose "`$HPEGreenLakeSession has been updated with new id_token!"

                $global:HPEGreenLakeSession.oauth2TokenCreation = [datetime]$( Get-Date -Format g )
                Write-Verbose "`$HPEGreenLakeSession has been updated with new token creation date!"

                $global:HPEGreenLakeSession.oauth2TokenCreationEpoch = $( (New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds ) 
                Write-Verbose "`$HPEGreenLakeSession has been updated with new token creation epoch!"

    
                Write-Verbose "`$HPEGreenLakeSession has been updated with new access_token/refresh_token/id_token!"

                return $HPEGreenLakeSession

            }
            
            catch {

                Write-verbose "Exception thrown!"

                # Get Exception type
                $exception = $_.Exception
                do {
                    "Exception Type: {0}" -f $exception.GetType().Name | Write-Verbose
                    $exception = $exception.InnerException
                } while ($exception)

                # Get exception stream
                $result = $_.Exception.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($result)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd() 


                Write-verbose "Raw Response = $responseBody"
            
                $response = $responseBody | ConvertFrom-Json

                    
                    
                if ($Body) {
                    "Request payload: {0}" -f ($Body | Out-String) | Write-Verbose
                }
                if ($Headers) {
                    "Request headers: {0}" -f ($headers | Out-String) | Write-Verbose
                }

                Throw "Error - $responseBody"          
             
            }    
        }
    }

} 
  

Function Connect-HPEGLAccount { 
    <#
        .SYNOPSIS
        Create a session with a company account.
 
        .DESCRIPTION
        This Cmdlet create a session with a company account on the HPE GreenLake platform.
 
        .PARAMETER Oauth2IdToken
        OAuth2 access token value
         
        .PARAMETER Oauth2AccessToken
        OAuth2 access token value
 
        .PARAMETER CompanyName
        Name of your company account on the HPE GreenLake platform.
        This is an optional parameter that can be used when you have more than one company accounts on the HPE GreenLake platform.
        By default, the cmdlet uses the first available account linked to your email address.
 
        .EXAMPLE
        Connect-HPEGLAccount
 
        Create a session with the first available company account on the HPE GreenLake platform using $HPEGreenLakeSession global variable.
 
        .EXAMPLE
        Connect-HPEGLAccount -CompanyName 'DreamCompany'
 
        Create a session with the company account named 'DreamCompany' on the HPE GreenLake platform using $HPEGreenLakeSession global variable.
 
        .INPUTS
        None. You cannot pipe objects to this Cmdlet.
 
        .OUTPUTS
        HPEGreenLakeSession
         
        When a new valid connection is established with a new company account, ${Global:HPEGreenLakeSession} connection tracker variable is
        updated with the new customer id and company name properties and is returned by the cmdlet.
 
        .LINK
        Connect-HPEGL
        Disconnect-HPEGL
        Get-HPEGLAccounts
        Get-HPEGLAccount
        [${Global:HPEGreenLakeSession}]
          
   #>

    [CmdletBinding()]
    Param(

        [Parameter (Mandatory = $False, ParameterSetName = 'Params')]
        [ValidateNotNullOrEmpty()]
        [String]$Oauth2IdToken = $HPEGreenLakeSession.oauth2IdToken,  

        [Parameter (Mandatory = $False, ParameterSetName = 'Params')]
        [ValidateNotNullOrEmpty()]
        [String]$Oauth2AccessToken = $HPEGreenLakeSession.oauth2AccessToken,

        [Parameter (Mandatory = $False, ParameterSetName = 'Params')]
        [ValidateNotNullOrEmpty()]
        [String]$CompanyName
        
    ) 

    Process { 

        if (-not $HPEGreenLakeSession.customerId) {

            $url = $HPEGLbaseURL + $AuthnSessionUri

            $headers = @{} 
            $headers["Accept"] = "application/json"
            $headers["Content-Type"] = "application/json"
            $headers["Authorization"] = "Bearer $Oauth2AccessToken"

            $tokenParams = @{
                'id_token' = $Oauth2IdToken
            } | ConvertTo-Json

       
            try {
                # Create CCS user session
                "Create CCS user session" | Write-Verbose
                "About to make rest call to URL $url" | Write-Verbose

                $account = ((Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body $tokenParams -SessionVariable CCSSession).content | ConvertFrom-Json).accounts

                $account | Write-Verbose

                "CCS user session creation - Cookies content:" | Write-Verbose
           
                $cookies = $CCSSession.Cookies.GetCookies($url)
                foreach ($cookie in $cookies) { 
                    Write-Verbose "$($cookie.name) = $($cookie.value)"
                }

                "CCS user session creation successful!" | Write-Verbose
            
            }
            catch {

                $result = $_.Exception.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($result)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd() 

                Write-verbose "Raw Response = $responseBody"

                $response = $responseBody | ConvertFrom-Json

                $ResponseCode = $response.code
                $ResponseDetail = $response.detail
                $ResponseStatus = $Response.Status

                if ($ResponseCode) { 
                    "Request failed with the following Status: `n`tHTTPS Return Code = {0} `n`tHTTPS Return Code Description = {1} `n`tHTTPS Return Code Details = {2}" -f $ResponseStatus, $ResponseCode, $ResponseDetail | write-verbose
                }  
            
                $StatusCode = [int]$_.Exception.Response.StatusCode
                $ExceptionCode = $_.Exception.Response.StatusCode.value__
            
                if ($StatusCode -and -not $ResponseCode) {
                    "HTTPS Return Code = {0}" -f $StatusCode | Write-Verbose
                }
                elseif ($ExceptionCode -and -not $ResponseCode) {
                    "HTTPS Return Code = {0}" -f $ExceptionCode | Write-Verbose
                }


                if ($_.ErrorDetails.Message) {
                    if ($_.ErrorDetails -match "JWT token is older than") {
                        $ErrorMsg = "Session has expired or been closed! Connect-HPEGL must be executed again!" -f $_.Exception.Message 

                    }
                    else {
                        $ErrorMsg = "Error: {0} - Error details: {1}" -f $_.Exception.Message, $_.ErrorDetails 
                    }
                }
                else {
                    $ErrorMsg = "Error: {0}" -f $_.Exception.Message 

                }


                "CCS user session creation: " | Write-Verbose
                "Request payload: `n{0}" -f ($tokenParams | Out-String) | Write-Verbose
                "Request headers: " | Write-Verbose

                foreach ($Param in $headers.Keys) { 
                
                    Write-Verbose "`t`t$Param : $($headers[$Param])" 
                
                }


                Throw $ErrorMsg 
            
           
            }

            if ($CompanyName) {

                $MyAccount = $account | ? company_name -eq $CompanyName
                $Global:HPEGreenLakeSession.customerId = $MyAccount.platform_customer_id
                $Global:HPEGreenLakeSession.companyName = $CompanyName

            }
            else {

                $MyCompanyName = $account[0].company_name
                $Global:HPEGreenLakeSession.customerId = $account[0].platform_customer_id
                $Global:HPEGreenLakeSession.companyName = $MyCompanyName 

            }
        
            "HPE GreenLake CCS Customer ID: {0}" -f $Global:HPEGreenLakeSession.customerId | Write-Verbose
            "HPE GreenLake CCS Company name: {0}" -f $Global:HPEGreenLakeSession.companyName | Write-Verbose

        


            # Load company account to get cookies session values for CCS API authentication

            $url = $HPEGLbaseURL + $SessionLoadAccountUri + $HPEGreenLakeSession.customerId
 

            try {         

                "Load CCS user account" | Write-Verbose
                "About to make rest call to URL $url" | Write-Verbose

                $useraccount = Invoke-WebRequest -Method Get -Uri $url -Headers $headers -WebSession $CCSSession 

                $useraccount | Write-Verbose

                "CCS user account session - Cookies content:" | Write-Verbose
           
                $cookies = $CCSSession.Cookies.GetCookies($url)
                foreach ($cookie in $cookies) { 
                    Write-Verbose "$($cookie.name) = $($cookie.value)"
                }

                # Set HPEGreenLakeSession.session global variable

                $Global:HPEGreenLakeSession.session = $CCSSession

                return $global:HPEGreenLakeSession

            
            }
            catch {

            

                if ($_.ErrorDetails.Message) {
                    $ErrorMsg = "Error: {0} - Error details: {1}" -f $_.Exception.Message, $_.ErrorDetails 
 
                }
                else {
                    $ErrorMsg = "Error: {0}" -f $_.Exception.Message 
 
                }

                throw $ErrorMsg 
                # $PSCmdlet.ThrowTerminatingError($PSitem)
            }
        }
        else {

            # Load company account to get cookies session values for CCS API authentication

            $account = Get-HPEGLAccounts -Name $CompanyName

            if (-not $account) {
                throw "Company name not found!"
            }
            else {
                
                $CustomerId = $account.platform_customer_id

                $url = $HPEGLbaseURL + $LoadAccountUri + $CustomerId
 
                try {         

                    "Load CCS user account" | Write-Verbose
                    "About to make rest call to URL $url" | Write-Verbose

                    $useraccount = Invoke-WebRequest -Method Get -Uri $url -Headers $headers -WebSession $HPEGreenLakeSession.session

                    $useraccount | Write-Verbose
    
                    $Global:HPEGreenLakeSession.customerId = $CustomerId
                    $Global:HPEGreenLakeSession.companyName = $CompanyName
               
                    "HPE GreenLake CCS Customer ID: {0}" -f $Global:HPEGreenLakeSession.customerId | Write-Verbose
                    "HPE GreenLake CCS Company name: {0}" -f $Global:HPEGreenLakeSession.companyName | Write-Verbose
    
                    return $HPEGreenLakeSession

            
                }
                catch {

                    if ($_.ErrorDetails.Message) {
                        $ErrorMsg = "Error: {0} - Error details: {1}" -f $_.Exception.Message, $_.ErrorDetails 
 
                    }
                    else {
                        $ErrorMsg = "Error: {0}" -f $_.Exception.Message 
 
                    }

                    throw $ErrorMsg 
                    # $PSCmdlet.ThrowTerminatingError($PSitem)
                }
            }
        }

    }
}


############################ DEVICE ###################################


Function Get-HPEGLdevice {
    <#
    .SYNOPSIS
    Retrieve device resource(s).
 
    .DESCRIPTION
    This Cmdlet returns a collection of device resources, or device statistics or a specific device with the specified serial number or a collection of device
    resources with the specified parameter(s). A maximum of 100 devices are displayed by default.
     
    To list all devices, you can use the NoLimit parameter or change the maximum using the Limit parameter.
     
    .PARAMETER PartNumber
    Specifies the part number associated with resources.
 
    .PARAMETER SerialNumber
    Specifies the serial number associated with resources.
    
    .PARAMETER RequireAssignment
    Optional parameter that can be used to display devices without an application assignment.
 
    .PARAMETER RequireSubscription
    Optional parameter that can be used to display devices without a subscription tier.
 
    .PARAMETER Archived
    Optional parameter that can be used to display archived devices only.
 
    .PARAMETER NotArchived
    Optional parameter that can be used to hide archived devices.
 
    .PARAMETER SearchString
    Specifies a search string for devices search.
 
    .PARAMETER SubscriptionTier
    Specifies a matching device subscription tier name such as 'enhanced', 'enhanced_proliant', 'standard', 'standard_proliant', 'Foundation-Switch-64xx/54xx', 'Foundation-Switch-8xxx', etc.
     
    .PARAMETER DeviceType
    Specifies a device type such as STORAGE, COMPUTE or SWITCH.
 
    .PARAMETER Location
    Specifies a location name.
 
    .PARAMETER ContactName
    Specifies a service delivery contact name.
 
    .PARAMETER Tags
    Optional parameter that can be used to display device tags.
 
    .PARAMETER Limit
    This parameter allows you to define the number of devices to be displayed. The default limit is 100 devices.
 
    .PARAMETER NoLimit
    Parameter to view all devices available in HPE GreenLake without any limit.
    Beyond thousands of devices, the execution of the command may take some time.
 
    .PARAMETER Stats
    Optional parameter that can be used to display device statistics.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLdevice -Limit 200
 
    Return the first 200 device resources.
 
    .EXAMPLE
    Get-HPEGLdevice -Nolimit
 
    Return all device resources.
 
    .EXAMPLE
    Get-HPEGLdevice -SerialNumber CN70490RXP
 
    Return the device resource with serial number "CN70490RXP".
 
    .EXAMPLE
    Get-HPEGLdevice -PartNumber "P38471-B21"
 
    Return all device resources with part number "P38471-B21".
 
    .EXAMPLE
    Get-HPEGLdevice -Stats
 
    Return device statistics.
 
    .EXAMPLE
    Get-HPEGLdevice | ? part_number -eq HF20
 
    Return a device resource with part number "HF20"
 
    .EXAMPLE
    Get-HPEGLdevice -DeviceType STORAGE
 
    Return all device resources with a device type "STORAGE".
 
    .EXAMPLE
    Get-HPEGLdevice -RequireAssignment -SearchString DL360
 
    Return all DL360 device resources that require an application assignment.
 
    .EXAMPLE
    Get-HPEGLdevice -RequireSubscription -RequireAssignment
 
    Return all device resources that require a subscription and an application assignment.
 
    .EXAMPLE
    Get-HPEGLdevice -SubscriptionTier Enhanced_Proliant
 
    Return all device resources with an Enhanced_Proliant subscription tier.
 
    .EXAMPLE
    Get-HPEGLdevice -Tags -Nolimit
 
    Return all device resources with tags information
 
    .EXAMPLE
    Get-HPEGLDevice -Archived
 
    Return all archived devices.
 
    .EXAMPLE
    "J12345605X", "J13134413T", "J21233335W", "J2123333S" | Get-HPEGLdevice
 
    Return all devices that match the serial numbers given in the pipeline.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device serial number(s).
 
    .LINK
    Add-HPEGLDeviceCompute
    Add-HPEGLDeviceTag
    Remove-HPEGLDeviceTag
    Set-HPEGLDeviceApplication
    Remove-HPEGLDeviceApplication
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Params')]
    Param( 
    
        [Parameter (Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Archived')]
        [ValidateNotNullOrEmpty()]
        [String]$PartNumber, 
    
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = 'NotArchived')]
        [Parameter (Mandatory = $false, ValueFromPipeline, ParameterSetName = 'Archived')]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,  
    
        [Parameter (Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Switch]$RequireAssignment,

        [Parameter (Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Switch]$RequireSubscription,

        [Parameter(Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [ValidateNotNullOrEmpty()]
        [String]$SubscriptionTier,

        [Parameter (Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory, ParameterSetName = 'Archived')]
        [Switch]$Archived,

        [Parameter (Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory, ParameterSetName = 'NotArchived')]
        [Switch]$NotArchived,

        [Parameter(Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Archived')]
        [ValidateNotNullOrEmpty()]
        [String]$SearchString,

        [Parameter(Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('ACCESS POINT', 'GATEWAY', 'SERVER', 'STORAGE', 'SWITCH')]
        [String]$DeviceType,

        [Parameter(Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [ValidateNotNullOrEmpty()]
        [String]$Location,

        [Parameter(Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [ValidateNotNullOrEmpty()]
        [String]$ContactName,

        [Parameter(Mandatory = $False, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [String]$Limit = 100,

        [Parameter(Mandatory = $False, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Switch]$NoLimit,

        [Parameter(Mandatory = $False, ParameterSetName = 'Params')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Switch]$Tags,

        [Parameter(Mandatory, ParameterSetName = 'Stats')]
        [Switch]$Stats,

        [Parameter (Mandatory = $false, ParameterSetName = 'Params')]
        [Parameter(Mandatory = $False, ParameterSetName = 'Stats')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotArchived')]
        [Switch]$Whatif
       
    ) 

    Process {

        if ($Nolimit) {

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

            # Get 500 devices pagination
            $limit = 500

            $UriAdd = $DevicesUri + "/filter?limit=$limit&offset=0"

            if ($SearchString) {

                $body = @{
                    unassigned_only    = $false
                    archive_visibility = "ALL"
                    search_string      = $SearchString
                } | ConvertTo-Json

            }
            else {
                
                $body = @{
                    unassigned_only    = $false
                    archive_visibility = "ALL"
                } | ConvertTo-Json 
    
            }
            

            try {

                [Array]$Collection = Invoke-HPEGLWebRequest -Method POST -UriAdd $UriAdd -Body $Body -WhatIfBoolean $Whatif 
                
            }
            catch {
           
                Throw $_
               
            }

 
            # "Request URI: {0}" -f $UriAdd
            $AllCollection = $collection
            # $AllCollection.devices.count

            $Numberofpages = [System.Math]::Ceiling(($Collection.pagination.total_count / $Collection.pagination.count_per_page))

            if ($Numberofpages -gt 1) {

                for ($i = 1; $i -lt $Numberofpages; $i++) {
                    
                    $Offset += $limit
               
                    $UriAdd = $DevicesUri + "/filter?limit=$limit&offset=$Offset"
                    
                    "Request URI: {0}" -f $UriAdd
                    
                    try {
                        [Array]$Collection = Invoke-HPEGLWebRequest -Method POST -UriAdd $UriAdd -Body $Body -WhatIfBoolean $Whatif
                        $AllCollection += $Collection
    
                    }
                    catch {    
                        Throw $_
                        
                    }

                }

            }
            else {
                $AllCollection = $Collection
            }
            

        }
        else {
            
            if ($SearchString) {
                $UriAdd = $DevicesUri + "?search_string=$SearchString&limit=$Limit"

            }
            else {
                $UriAdd = $DevicesUri + "?limit=$Limit"
            }

            try {
                [Array]$AllCollection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -WhatIfBoolean $Whatif
    
            }
            catch {
                Throw $_
                   
            }

           
        }           


        $ReturnData = @()
       
        if ($Stats) {
            
            $UriAdd = $DevicesStatsUri
            
            try {
                [Array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -WhatIfBoolean $Whatif
                
                $ReturnData = Invoke-RepackageObjectWithType -RawObject $Collection -ObjectName "Device.stat"         
                return $ReturnData 

            }
            catch {
                
            }
                       
        }
       
        else {        

            if ($Null -ne $AllCollection.devices) {     

                $CollectionList = $AllCollection.devices 
                
                if ($SubscriptionTier) {

                    $CollectionList = $CollectionList | ? subscription_tier -match $SubscriptionTier

                }     
                
                if ($SerialNumber) {

                    $CollectionList = $CollectionList | ? serial_number -eq $SerialNumber

                }   

                if ($PartNumber) {

                    $CollectionList = $CollectionList | ? part_number -eq $PartNumber

                }   

                if ($RequireAssignment) {

                    $CollectionList = $CollectionList | ? { -not $_.application_instance_id }

                }   

                if ($RequireSubscription) {

                    $CollectionList = $CollectionList | ? { -not $_.subscription_key }

                }   

                if ($Archived) {

                    $CollectionList = $CollectionList | ? { $_.archived }

                }   

                if ($NotArchived) {

                    $CollectionList = $CollectionList | ? { -not $_.archived }

                }   
          
                if ($Location) {

                    $CollectionList = $CollectionList | ? location_name -eq $Location

                }   

                if ($ContactName) {

                    $CollectionList = $CollectionList | ? contact_name -eq $ContactName

                }   

                # if ($SearchString) {

                # $CollectionList = $CollectionList | ? model -match $SearchString

                # }

                if ($DeviceType) {

                    if ($DeviceType -eq "ACCESS POINT") {
                        $_DeviceType = "AP"
                    }
                        
                    if ($DeviceType -eq "GATEWAY") {
                        $_DeviceType = "GATEWAY"
                    }
            
                    if ($DeviceType -eq "SERVER") {
                        $_DeviceType = "COMPUTE"
                    }
            
                    if ($DeviceType -eq "STORAGE") {
                        $_DeviceType = "STORAGE"
                    }
            
                    if ($DeviceType -eq "SWITCH") {
                        $_DeviceType = "SWITCH"
                    }

                    $CollectionList = $CollectionList | ? device_type -match $_DeviceType

                }

                if ($Tags) {
       
                    $CollectionList = $CollectionList | ? tags
       
                    $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Device.Tag"         
                    $ReturnData = $ReturnData | Sort-Object { $_.serial_number }
                
                    return $ReturnData 
            
                }

                $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Device"    
    
                $ReturnData = $ReturnData | Sort-Object { $_.serial_number }
        
                return $ReturnData 
                
            }
            else {

                return
                
            }     

        }
    
    }
}


Function New-HPEGLDeviceComputeObject {
    <#
    .SYNOPSIS
    Create a Compute object for Add-HPEGLDeviceCompute.
 
    .DESCRIPTION
    This cmdlet creates a Compute PSCustomObject to be used with Add-HPEGLDeviceCompute as a pipeline input.
     
    Three objects are supported
    Compute: serial_number part_number tag:name1 tag:name2
                serial_number part_number entitlement_id tag:name1 tag:name2
 
    Storage: serial_number tag:name1 tag:name2
                serial_number entitlement_id tag:name1 tag:name2
                serial_number entitlement_id cloud_activation_key tag:name1 tag:name2
 
    Network: serial_number mac_address tag:name1 tag:name2
                serial_number mac_address part_number tag:name1 tag:name2
                mac_address cloud_activation_key tag:name1 tag:name2
 
    .PARAMETER PartNumber
    Part number of the device.
             
    .PARAMETER SerialNumber
    Serial number of the device.
 
    .PARAMETER Tags
    Tags of the device to be added.
    Tags must meet the following string format <Name>=<Value> <Name>=<Value> such as "Country=US State=TX App=Grafana" or "Country=US"
 
    .OUTPUTS
    Output the generated PSCustomObject.
 
    .EXAMPLE
    New-HPEGLDeviceComputeObject -SerialNumber "121341123" -PartNumber "879991-B21" -Tags "Country=US App=ESXi Department=HR"
 
    Create a Compute device PSCustomObject with the specified serial number, part number and tags.
 
    .EXAMPLE
    $ComputeDevicesToAdd = @()
    ForEach ($Device in $Device_Collection) {
        $SerialNumber = $Device.SerialNumber
        $PartNumber = $Device.PartNumber
        $Tags = $Device.Tags
        $ComputeDevicesToAdd += New-HPEGLDeviceComputeObject -SerialNumber $SerialNumber -PartNumber $PartNumber -Tags $Tags
    }
 
    Sample script to create a list of devices using New-HPEGLDeviceComputeObject. This list can then be used as a pipeline input to Add-HPEGLDeviceCompute.
 
    $ComputeDevicesToAdd | Add-HPEGLDeviceCompute
 
    .LINK
    Add-HPEGLDeviceCompute
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'default')]
    Param( 
 
        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$PartNumber,
    
        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,

        [Parameter (Mandatory = $false, ParameterSetName = "default")]
        [String]$Tags
    ) 
  

    Process {     

        $_ComputeObj = NewObject -AddComputeDevice
        
        $_ComputeObj.SerialNumber = $SerialNumber
        $_ComputeObj.PartNumber = $PartNumber
        

        if ($Tags) {
            $_ComputeObj.Tags = $Tags
        }
        else {
            $_ComputeObj.Tags = $Null
        }
   
    }
 


    end {

        return    $_ComputeObj
    }

}


Function Add-HPEGLDeviceCompute {
    <#
    .SYNOPSIS
    Add Compute device(s) to the HPE GreenLake console.
 
    .DESCRIPTION
    This Cmdlet adds Compute device(s) to the HPE GreenLake console.
    Can optionally add tags during the onboarding process.
    Devices must be on the Compute Ops Management supported servers list.
 
    .PARAMETER PartNumber
    Part number of the device to be added.
    This value can be retrieved from the HPE iLO RedFish API.
 
    .PARAMETER SerialNumber
    Serial number of the device to be added.
    This value can be retrieved from the HPE iLO RedFish API.
 
    .PARAMETER Tags
    Optional parameter that can be used to add tags to the device.
    Tags must meet the following string format <Name>=<Value> <Name>=<Value> such as "Country=US State=TX App=Grafana" or "Country=US"
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Add-HPEGLDeviceCompute -SerialNumber "123456789012" -PartNumber "879991-B21" -Tags "Country=US App=ESXi Department=HR"
 
    Add a compute device using a serial number and a part number and assign three tags.
 
    .EXAMPLE
    Add-HPEGLDeviceCompute -SerialNumber "123456789012" -PartNumber "879991-B21" -SubscriptionKey ABCDEFGHIJ
 
    Add a compute device using a serial number and a part number and assign a subscription key to the device but do not assign any tags.
 
    .EXAMPLE
    Import-Csv Compute_Devices.csv | Add-HPEGLDeviceCompute
 
    Add all compute devices listed in a Compute_Devices.csv file to the HPE GreenLake platform.
 
    The content of the csv file must use the following format:
 
        SerialNumber, PartNumber, Tags
        WGX2380BLC, P55181-B21, Country=US State=PACA App=RH
        AZX2380BLD, P55182-B21, State=Texas Role=production
        7LKY23D9LM, P54277-B21
 
    Note that for 7LKY23D9LM, we assign no tags in this example.
     
    .EXAMPLE
    $iLO_collection = import-csv Tests\iLOs.csv
    Import-Module HPEiLOCmdlets
 
    $ComputeDevicesToAdd = @()
 
    ForEach ($iLO in $iLO_Collection) {
 
        try {
 
            $session = Connect-HPEiLO -Address $iLO.IP -username $iLO.Username -password $iLO.Password -DisableCertificateAuthentication
            $HPEiLOSystemInfo = Get-HPEiLOSystemInfo -Connection $session
 
            $SerialNumber = $HPEiLOSystemInfo.SerialNumber
            $PartNumber = $HPEiLOSystemInfo.sku
            $Tags = $iLO.Tags
             
            $ComputeDevicesToAdd += New-HPEGLDeviceComputeObject -SerialNumber $SerialNumber -PartNumber $PartNumber -Tags $Tags
 
            Disconnect-HPEiLO -Connection $session
 
        }
        catch {
            "iLO {0} cannot be added ! Check your IP or credentials !" -f $iLO.IP
            continue
        }
    }
 
    $ComputeDevicesToAdd | Add-HPEGLDeviceCompute
 
    Sample script to add all compute devices listed in an iLOs.csv file to the HPE GreenLake platform. Device information (part number and serial number) is retrieved
    using the HPEiLOCmdlets module using the IP and credentials of each iLO provided in the csv file. Optionally, tags can also be provided.
     
    The content of the csv file must use the following format:
 
        IP, Username, Password, Tags
        192.168.1.44, demopaq, password, Country=FR State=PACA App=RH
        192.168.0.40, Administrator, P@ssw0rd, State=Texas Role=production
        192.168.3.194, Admin, Password!
     
    Note that for 192.168.3.194, we assign no tags in this example.
     
    .EXAMPLE
    $ComputeDevicesToAdd | Add-HPEGLDeviceCompute -Tags "Country=US App=ESXi Department=HR"
 
    Add all devices listed in $DevicesToAdd by forcing tags values.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = '123456789012'; PartNumber = 'P55181-B21'},
        [PSCustomObject]@{SerialNumber = '123432356789'; PartNumber = 'P54277-B21'}
    )
     
    $devices | Add-HPEGLDeviceCompute -Tags "Country=US Department=Marketing"
 
    Add all compute devices (2) listed in $devices with the specified serial numbers and part numbers and assign them two identical tags.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = '123456789012'; PartNumber = 'P55181-B21'; Tags = 'Country=US State=PACA App=RH' },
        [PSCustomObject]@{SerialNumber = '123432356789'; PartNumber = 'P54277-B21'; Tags = 'State=Texas Role=production' }
    )
 
    $devices | Add-HPEGLDeviceCompute
 
    Add all compute devices (2) listed in $devices with the specified serial numbers and part numbers and assign them different tags.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) with partnumber, serialnumber and tags properties.
        New-HPEGLDeviceComputeObject can be used to create this object.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be added
        * PartNumber - Part number of the device attempted to be added
        * Tags - Tags to assign to the device
        * Status - Status of the onboarding attempt (Failed for http error return; Complete if onboarding is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice
    New-HPEGLDeviceComputeObject
    Add-HPEGLDeviceTag
    Remove-HPEGLDeviceTag
    Set-HPEGLDeviceApplication
    Remove-HPEGLDeviceApplication
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('part_number')]
        [String]$PartNumber,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [String]$Tags,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri  
        $AddDevicesStatus = [System.Collections.ArrayList]::new()
    }

    Process {

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

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            PartNumber   = $PartNumber
            Tags         = $Tags
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }

        if ($Tags) {
       
            # Remove space at the end of the string if any
            $Tags = $Tags.TrimEnd()

            # Split tags using spaces
            $splittedtags = $Tags.split(" ")

            # Check tag format, if format is not <tagname>=<value>, return error
            foreach ($splittedtag in $splittedtags) {

                if ($splittedtag -notmatch "^[A-Za-z0-9]+=[A-Za-z0-9][^=]*$") {

                    "Tag '$splittedtag' format not supported! Expected format is <tagname>=<value>" | write-Verbose
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Tag format not supported! Expected format is <tagname>=<value>"
                    [void] $AddDevicesStatus.add($objStatus)
                    return  
                }
            }

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

            foreach ($tag in $splittedtags) {
        
                $tagname = $tag.split('=')[0]
                $tagvalue = $tag.split('=')[1]
            
                $TagsList += [PSCustomObject]@{
                    name  = $tagname
                    value = $tagvalue 
                }
            } 
        }

        # Build DeviceList object

        # If tags
        if ($Tags) {
            
            $DeviceList += [PSCustomObject]@{
                serial_number      = $SerialNumber
                part_number        = $PartNumber 
                app_category       = 'COMPUTE'
                tag_change_request = @{ create_tags = $TagsList } 
            }
        }
        # If no tags
        else {
            
            $DeviceList += [PSCustomObject]@{
                serial_number = $SerialNumber
                part_number   = $PartNumber 
                app_category  = 'COMPUTE'
            }
        }

        # Build payload
        $payload = [PSCustomObject]@{
            devices = $DeviceList 
        } | ConvertTo-Json -Depth 5
          

        # Test if device present
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue 
    
        }
        catch {
            Throw $_
        }
       
        if ( $device) {
            # Must return a message if device is found
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device already present on the HPE GreenLake platform"
            
        }
        else {       

            # Add device
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully added to the HPE GreenLake platform"
                    
                }
                
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device was not added to the HPE GreenLake platform"
                    $objStatus.Exception = $_.Exception.message 
                }
            
            }       
        }

        [void] $AddDevicesStatus.add($objStatus)

      
    }

    end {

        if (-not $Whatif) {

            if ($AddDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the onboarding attempt!"
          
            }
         
        }

        Return $AddDevicesStatus

    }
        
}


Function Add-HPEGLDeviceComputeFullService {
    <#
    .SYNOPSIS
    Complete process of adding a server in HPE GreenLake and connecting it with a HPE Compute Ops Management instance.
   
    .DESCRIPTION
    This Cmdlet can add one or multiple compute devices defined in a CSV file to the HPE GreenLake platform.
   
    To correctly run the cmdlet, it is essential that the system has access to both the Internet (for accessing the HPE GreenLake platform)
    and the iLO network (which is typically a private network).
 
    Actions performed during the onboarding process:
      1/ Connect to HPE GreenLake using the default account or the one provided using the GLCompanyName parameter.
      2/ Set the automatic assignment of subscriptions with the first Compute Enhanced subscription found that has not expired and has available subscription seats.
      3/ Onboard each device to the HPE GreenLake platform account.
      4/ Set optional server tags if defined with the Tags parameter.
      5/ Associate each device with the defined application instance (subscription is automatically assigned to each device as per auto assignment configuration).
      6/ Set each iLO to use a web proxy if defined via the different web proxy parameters.
      7/ Connect each iLO to the HPE Compute Ops Management instance.
   
    If provided as a pipeline input, the content of the csv file must use the following format:
   
        IP, Username, Password, Tags
        192.168.3.193, Administrator, password, Country=FR City=Mougins App=InfluxDB Owner=LJ
        192.168.3.191, Administrator, password, Country=US State=Texas Role=Production Owner=LJ
        192.168.3.205, demo, password
 
    Note that for 192.168.3.205, no tag is assigned in this example.
 
    .PARAMETER IloIP
    Specifies iLO IP/Hostname of the device to be added. IP can be either IPv4 address or IPv6 address.
     
    .PARAMETER IloUserName
    Username of the iLO of the device to be added. IloUserName needs to be given as input along with IloPassword. Username cannot be null or empty string.
     
    .PARAMETER IloPassword
    Password of the iLO of the device to be added. IloPassword needs to be given along with IloUserName. Password cannot be null or an empty string.
     
    .PARAMETER GLCredential
    PSCredential object of a HPE GreenLake account represented by a username (email address) and a password.
     
    .PARAMETER GLCompanyName
    Name of your company account on the HPE GreenLake platform. This is an optional parameter that can be used when you have more than one
    company accounts on the HPE GreenLake platform. By default, the cmdlet selects the first available account.
     
    .PARAMETER Tags
    Optional parameter that can be used to add tags to the device during the onboarding.
    The existing tags for devices already on the platform are retained.
    Tags must meet the following string format <Name>=<Value> <Name>=<Value> such as "Country=US State=TX App=Grafana" or "Country=US"
 
    .PARAMETER Application
    Specifies the name of the compute application (Compute Ops Management by default).
 
    .PARAMETER Region
    Specifies the Compute Ops Management region instance where to onboard the Compute device(s).
   
    .PARAMETER IloProxyServer
    (Optional) Enables iLO web proxy.
    Indicates the hostname or IP address of web proxy server.
   
    .PARAMETER IloProxyPort
    Specifies the iLO web proxy port number. The range of valid port values in iLO is from 1–65535.
   
    .PARAMETER IloProxyUserName
    Indicates iLO web proxy username (if any).
   
    .PARAMETER IloProxyPassword
    Indicates iLO web proxy password (if any).
   
    .PARAMETER ComputeSubscriptionTier
    Specifies the Compute subscription tier to use for automatic assignment of subscriptions. Supported values are ENHANCED and STANDARD.
    Automatic subscription assignment is enabled by default with the first Compute Enhanced subscription found that has not expired and has available subscription seats.
    If no subscription tier with available subscription seats is found, the script stops and returns an error message.
   
    .PARAMETER DisconnectiLOfromOneView
    If the DisconnectiLOfromOneView switch parameter is present, a system that is managed by HPE OneView will be disconnected from OneView to connect to Compute Ops Management.
    If this parameter is not present, a system that is managed by HPE OneView will stay connected to OneView and the connection to Compute Ops Management will fail.
   
    .EXAMPLE
    $Response = import-csv .\Tests\Compute_Devices.csv | Add-HPEGLDeviceComputeFullService -GLCredential $GLCredential -Region eu-central -GLCompanyName HPE_Mougins
   
    Connect to HPE GreenLake using the "HPE_Mougins" account.
    Onboard each compute device listed in iLOs.csv to the HPE GreenLake platform "HPE_Mougins" account.
    Associate each compute device with the Compute Ops Management application located in the Central European region.
    Assign an enhanced subscription key found in the account to each device and set tags.
    Connect each iLO to the HPE Compute Ops Management instance.
    $Response returns an overall onboarding status of all devices.
    $Response[0] returns the onboarding status of the first device.
    $Response[0].SubTasksStatus returns the subtask status of the first device.
   
    .EXAMPLE
    $Response = Add-HPEGLDeviceComputeFullService -GLCredential $GLCredential -Region us-west -IloIP 192.168.1.44 -IloUserName Administrator -IloPassword P@ssw0rd -Tags "Country=US City=Houston App=CentOS"
   
    Connect to HPE GreenLake using the default company account.
    Onboard the compute with the iLO IP address 192.168.1.44 to the HPE GreenLake platform default company account.
    Associate the compute device with the Compute Ops Management application located in the western US region.
    Assign to the device an enhanced subscription key found in the account and set 3 tags.
    Connect the iLO to the HPE Compute Ops Management instance.
    $Response returns the onboarding status of the device.
    $Response.SubTasksStatus returns the onboarding status of the device's subtasks.
   
    .EXAMPLE
    $Response = Add-HPEGLDeviceComputeFullService -GLCredential $GLCredential -GLCompanyName DreamCompany -Region us-west -IloIP 192.168.1.72 -IloUserName Administrator -IloPassword P@ssw0rd -Tags "Country=FR City=Mougins App=CentOS" -IloProxyServer "webproxy.com" -IloProxyPort 8088 -IloProxyUserName demopaq -IloProxyPassword "P@ssw0rd"
     
    Connect to HPE GreenLake using the "DreamCompany" account.
    Onboard the compute with the iLO IP address 192.168.1.72 to the HPE GreenLake platform "DreamCompany" account.
    Associate the compute device with the Compute Ops Management application located in the western US region.
    Assign to the device an enhanced subscription key found in the account and set 3 tags.
    Set the iLO to use a web proxy with user credentials.
    Connect the iLO to the HPE Compute Ops Management instance.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) to be added with iLO information and Tags to be assigned.
        The list must contain the following fields: IP, Username, Password and Tags.
   
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - iLO IP address of the device
        * SerialNumber - Serial number of the device attempted to be added
        * PartNumber - Part number of the device attempted to be added
        * Tags - Tags added to the device attempted to be added
        * Status - Status of the full onboarding attempt (Failed for http error return; Complete if full onboarding is successful)
        * SubTasksStatus - Hashtable object of subtasks
                * ApplicationAssignmentStatus - Status of the application assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * ApplicationAssignmentDetail - More information about the application assignment status
                * OnboardingStatus - Status of the onboarding attempt (Failed for http error return; Complete if onboarding is successful; Warning if no action is needed)
                * OnboardingDetails - More information about the onboarding attempt status
                * SubscriptionStatus - Status of the subscription attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * SubscriptionDetail - More information about the subscription status
                * TagAssignmentStatus - Status of the tag(s) assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * TagAssignmentDetails - More information about the tag(s) assignment status
                * iLOConnectionStatus - Status of the iLO connection attempt to HPE Compute Ops Management (Failed for http error return; Complete if successful)
                * iLOConnectionDetails - More information about the iLO connection attempt status
                * ProxySettingsStatus - Status of the iLO Proxy configuration attempt (Failed for http error return; Complete if successful)
                * ProxySettingsDetails - More information about the iLO Proxy configuration status
        * Exception - Exception returns during one of the operations
     
   #>

  
    [CmdletBinding()]
    Param( 
  
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateScript({ [String]::IsNullOrEmpty($_) -or
                $_ -match [Net.IPAddress]$_ })]
        [Alias ('IP')]
        [IPAddress]$IloIP,
  
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('username')]
        [String]$IloUserName,
  
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('password')]
        [String]$IloPassword,
  
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$GLCredential,
  
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [String]$GLCompanyName,
  
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [String]$Tags,

        [Parameter (ParameterSetName = "Default")]
        [String]$Application = "Compute Ops Management",
  
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [String]$Region,
  
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [String]$IloProxyServer,
  
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Int]$IloProxyPort,
  
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [String]$IloProxyUserName,
  
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [String]$IloProxyPassword,
      
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateSet('ENHANCED', 'STANDARD')]
        [String]$ComputeSubscriptionTier = "ENHANCED",
  
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$DisconnectiLOfromOneView
  
    ) 
  
  
    Begin {
  
        $OnboardingDevicesStatus = [System.Collections.ArrayList]::new()
        
  
        #----------------------------------------------------------Connection to HPE GreenLake -----------------------------------------------------------------------------
  
        try {
  
            if ($GLCompanyName) {
  
                if ( $PSBoundParameters['Verbose']) {
  
                    Connect-HPEGL -Credential $GLCredential -CompanyName $GLCompanyName -Verbose | Out-Null
                }
                else {
  
                    Connect-HPEGL -Credential $GLCredential -CompanyName $GLCompanyName | Out-Null
  
                }
  
            }
            else {
  
                if ( $PSBoundParameters['Verbose']) {
  
                    Connect-HPEGL -Credential $GLCredential -Verbose | Out-Null
                }
                else {
                    Connect-HPEGL -Credential $GLCredential | Out-Null
  
                }
            }
        }
        catch {
            Throw "Connection to HPE GreenLake platform failed!" 
  
        }
  
        # HPE GreenLake account ID kwnown as the activation key in iLO and used during the iLO connection to COM.
        $ActivationKey = $HPEGreenLakeSession.customerId
  
  
        # Check if application instance is present
        "Checking if application instance is present in {0}" -f $Region | Write-Verbose
  
        $_Application = Get-HPEGLApplication -Provisioned -Name $Application -Region $Region
   
        if ($_Application) {
    
            $ApplicationInstanceId = $_Application.application_instance_id
  
            "Application ID is: {0}" -f $ApplicationInstanceId | Write-Verbose
  
        }
        else {
            Throw "Error! There is no COM instance in '$Region'!"
            
        }   


        #-----------------------------------------------------------Set Auto device subscription to Compute -----------------------------------------------------------------------------
        
        "Setting Device Auto Subscription with {0}" -f $ComputeSubscriptionTier | Write-Verbose
  
        $Response = Set-HPEGLDeviceAutoSubscription -ComputeSubscriptionTier $ComputeSubscriptionTier -ErrorAction SilentlyContinue
                
        "Attempt to set Device Auto Subscription - Response: {0} - Details: {1}" -f $Response.status, $response.Details | Write-Verbose

        if ($Response.Details -match "Automatic assignment of subscriptions to COMPUTE cannot be set!") {
            Throw "Automatic assignment of subscriptions to COMPUTE cannot be set!"
            
        }

    }
  
    Process {
  
        #----------------------------------------------------------Onboard device(s) to the HPE GreenLake platform -----------------------------------------------------------------------------
  
        # Create object for the output
        $objStatus = [pscustomobject]@{
  
            Name           = $IloIP
            SerialNumber   = $Null
            PartNumber     = $Null
            Tags           = $Tags
            Status         = $Null
            SubTasksStatus = @{
                OnboardingStatus            = $Null
                OnboardingDetails           = $Null
                TagAssignmentStatus         = $Null
                TagAssignmentDetails        = $Null
                ApplicationAssignmentStatus = $Null
                ApplicationAssignmentDetail = $Null
                SubscriptionStatus          = $Null
                SubscriptionDetail          = $Null
                iLOConnectionStatus         = $Null
                iLOConnectionDetails        = $Null
                ProxySettingsStatus         = $Null
                ProxySettingsDetails        = $Null
            }
            Exception      = $Null
        }
  
  
        # Check if a COM subscription key is available
        "Checking if a COM subscription key is available!" | Write-Verbose
  
        $SubscriptionKey = (Get-HPEGLDeviceSubscription -Available -NotExpired -DeviceType SERVER).subscription_key | select -First 1
  
        if (-not $SubscriptionKey) {
        
            "No subscription key can be found on the HPE GreenLake platform that has both not expired and still has licenses available!" | Write-Verbose
            $objStatus.SubTasksStatus.SubscriptionStatus = "Failed"
            $objStatus.SubTasksStatus.SubscriptionDetail = "No subscription key with licenses available can be found!"
            $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
            $objStatus.Status = "Failed"
            [void] $OnboardingDevicesStatus.add($objStatus)
            return
        }
        else {

            "{0}: Valid COM subscription key found!" -f $SubscriptionKey | Write-Verbose

        }
      
        # Connection to iLO
  
        # To avoid error with self-signed certificate
        add-type -TypeDefinition  @"
          using System.Net;
          using System.Security.Cryptography.X509Certificates;
          public class TrustAllCertsPolicy : ICertificatePolicy {
              public bool CheckValidationResult(
                  ServicePoint srvPoint, X509Certificate certificate,
                  WebRequest request, int certificateProblem) {
                  return true;
              }
          }
"@

     
        [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
  
  
        $iLOBaseURL = "https://$IloIP"
                  
        $AddURI = "/redfish/v1/SessionService/Sessions/"
                  
        $url = $iLOBaseURL + $AddURI
                  
        $Body = [System.Collections.Hashtable]@{
            UserName = $IloUserName
            Password = $IloPassword
        } | ConvertTo-Json 
                  
        # Create iLO session
        "{0} -- Attempting an iLO session creation!" -f $iLOIP  | Write-Verbose
        "{0} -- Method: POST - URI: {1}" -f $IloIP, $url | Write-Verbose

        "{0} -- Body content: {1}" -f $IloIP, $Body | Write-Verbose
      
  
        try {
            $response = Invoke-WebRequest -Method POST -Uri $url -Body $Body -Headers $Headers -ContentType "Application/json"
            $XAuthToken = (($response.RawContent -split "[`r`n]" | select-string -Pattern 'X-Auth-Token' ) -split " ")[1]
  
            "{0} -- Raw response: {1}" -f $IloIP, $response | Write-Verbose

            "{0} -- iLO session created successfully!" -f $iLOIP  | Write-Verbose
        
        }
        catch {
            $objStatus.SubTasksStatus.iLOConnectionStatus = "Failed"
            $objStatus.SubTasksStatus.iLOConnectionDetails = "iLO connection error! Check your iLO IP or credential!"
            $objStatus.Exception = $_.Exception.message 
  
            "{0} -- iLO session cannot be created!" -f $iLOIP  | Write-Verbose
            $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
            $objStatus.Status = "Failed"
            [void] $OnboardingDevicesStatus.add($objStatus)
            return
        }
  
        # Get System information
                    
        $Headers = [System.Collections.Hashtable]@{
            'X-Auth-Token'  = $XAuthToken
            'Content-Type'  = 'application/json'
            'OData-Version' = '4.0'    
        }
      
        "{0} -- Getting system information " -f $iLOIP  | Write-Verbose
                
        $AddURI = "/redfish/v1/Systems/1/"
        $HPEiLOSystemInfo = Invoke-RestMethod -Method GET -Uri ($iLObaseURL + $AddURI) -Headers $Headers 
        $AddURI = "/redfish/v1/Managers/1/"
        $iLOGeneration = (Invoke-RestMethod -Method GET -Uri ($iLObaseURL + $AddURI) -Headers $Headers).model
   
  
        if ($iLOGeneration -eq "iLO 5" -or $iLOGeneration -eq "iLO 6") {
  
            $SerialNumber = $HPEiLOSystemInfo.SerialNumber
            $objStatus.SerialNumber = $SerialNumber
      
            $PartNumber = $HPEiLOSystemInfo.sku
            $objStatus.PartNumber = $PartNumber
        
  
            #-----------------------------------------------------------Enable iLO Proxy settings if needed-----------------------------------------------------------------------------
  
            if ($IloProxyServer) {
  
                "{0} -- iLO {1} attempting iLO proxy server settings" -f $SerialNumber, $IloIP | Write-Verbose
  
                $AddURI = "/redfish/v1/Managers/1/NetworkProtocol/"

                $url = ( $iLObaseURL + $AddURI)

  
                if ($IloProxyUserName -and $IloProxyPassword) {
  
                    $Body = [System.Collections.Hashtable]@{
                        Oem = @{
                            Hpe = @{
                                WebProxyConfiguration = @{
                                    ProxyServer   = $IloProxyServer
                                    ProxyPort     = $IloProxyPort
                                    ProxyUserName = $IloProxyUserName
                                    ProxyPassword = $IloProxyPassword
                                }
                            }
                        }
                    }  | ConvertTo-Json -d 9
  
                }
                else {
  
                    $Body = [System.Collections.Hashtable]@{
                        Oem = @{
                            Hpe = @{
                                WebProxyConfiguration = @{
                                    ProxyServer = $IloProxyServer
                                    ProxyPort   = $IloProxyPort
                                }
                            }
                        }
                    }  | ConvertTo-Json -d 9
  
                }

                "{0} -- iLO {1} - Method: POST - URI: {2}" -f $SerialNumber, $IloIP, $url | Write-Verbose
                "{0} -- iLO {1} - Hearders content: {2}" -f $SerialNumber, $IloIP, ($Headers | Out-String) | Write-Verbose
                "{0} -- iLO {1} - Body content: `n{2}" -f $SerialNumber, $IloIP, $Body | Write-Verbose
  
                try {
                    $Response = Invoke-RestMethod -Method PATCH -Uri $url -Headers $Headers -Body $Body -ErrorAction Stop
        
                    "{0} -- iLO {1} - Raw Response: {2}" -f $SerialNumber, $IloIP, ($Response | Out-String) | Write-Verbose

                    $msg = $response.error.'@Message.ExtendedInfo'.MessageId
                    
                    "{0} -- iLO {1} - Response: {2}" -f $SerialNumber, $IloIP, $msg | Write-Verbose
         
                    if ($msg -match "Success") {
                        "{0} -- iLO {1} proxy server settings modified successfully!" -f $SerialNumber, $IloIP | Write-Verbose
                        $objStatus.SubTasksStatus.ProxySettingsStatus = "Complete"
                        $objStatus.SubTasksStatus.ProxySettingsDetails = "iLO proxy server settings modified successfully!"
                    }
                   
    
                }
                catch {
  
                    $err = (New-Object System.IO.StreamReader( $_.Exception.Response.GetResponseStream() )).ReadToEnd() 
                    $msg = $err.error.'@Message.ExtendedInfo'.MessageId
  
                    "{0} -- iLO {1} proxy server settings cannot be configured! Error: {2}" -f $SerialNumber, $IloIP, $msg | Write-Verbose

  
                    $objStatus.SubTasksStatus.ProxySettingsStatus = "Failed"
                    $objStatus.SubTasksStatus.ProxySettingsDetails = $_.Exception.message 
  
                }
            }
      
        
            #------------------------------------------------------Add device to the HPE GreenLake platform with Tag values------------------------------------------------------------------
       
            "{0} -- Adding Device to GLCP - iLO={1} - PartNumber={2} - Tags='{3}'" -f $SerialNumber, $iLOIP, $PartNumber, $Tags | Write-Verbose
  
            $Response = Add-HPEGLDeviceCompute -PartNumber $PartNumber -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
    
            "{0} -- Attempt to add Compute device - Response: {1} - Details: {2}" -f $SerialNumber, $Response.status, $response.Details | Write-Verbose
  
            if ($Response.Details -match "Device already present") {
                $objStatus.SubTasksStatus.OnboardingStatus = "Warning"
                $objStatus.SubTasksStatus.OnboardingDetails = "Device is already present on the HPE GreenLake platform!"

            }     
            elseif ($Response.Status -eq "Failed") {
                $objStatus.SubTasksStatus.OnboardingStatus = "Failed"
                $objStatus.SubTasksStatus.OnboardingDetails = "Device cannot be added to the HPE GreenLake platform!"
                $objStatus.Exception = $Response.Exception 
                $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
                $objStatus.SubTasksStatus.TagAssignmentStatus = "Failed"
                $objStatus.SubTasksStatus.TagAssignmentDetails = "Device Tags cannot be set as device cannot be added!"
                $objStatus.Status = "Failed"
                [void] $OnboardingDevicesStatus.add($objStatus)
                return
            }
            elseif ($Response.Status -eq "Complete") {
                $objStatus.SubTasksStatus.OnboardingStatus = "Complete"
                $objStatus.SubTasksStatus.OnboardingDetails = "Device successfully added to the HPE GreenLake platform!"

            }


            #------------------------------------------------------Add tags to compute device------------------------------------------------------------------


            if ($Tags) {

                "{0} -- Adding Tags to Compute device - Tags='{1}'" -f $SerialNumber, $Tags | Write-Verbose
            
                $Response = Add-HPEGLDeviceTag -SerialNumber $SerialNumber -Tags $Tags -ErrorAction SilentlyContinue
                "{0} -- Attempt to add Compute device tags - Response: {1} - Details: {2}" -f $SerialNumber, $Response.status, $response.Details | Write-Verbose
  
                if ($Response.Status -eq "Failed") {
                    $objStatus.SubTasksStatus.TagAssignmentStatus = "Failed"
                    $objStatus.SubTasksStatus.TagAssignmentDetails = $response.Details
                }
                elseif ($Response.Status -eq "Warning") {
                    $objStatus.SubTasksStatus.TagAssignmentStatus = "Warning"
                    $objStatus.SubTasksStatus.TagAssignmentDetails = $response.Details
                }
                elseif ($Response.Status -eq "Complete") {
                    $objStatus.SubTasksStatus.TagAssignmentStatus = "Complete"
                    $objStatus.SubTasksStatus.TagAssignmentDetails = "Tags successfully assigned!"
                }
  
            }
            else {
                "{0} -- No tag to add to Compute device" -f $SerialNumber | Write-Verbose
            }

  
            #-----------------------------------------------------------Assign device to application instance-----------------------------------------------------------------------------
          
            "{0} -- Assigning Device to COM application in {1}" -f $SerialNumber, $Region | Write-Verbose
            
            $Response = Set-HPEGLDeviceApplication -ApplicationName $Application -Region $Region -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
  
            "{0} -- Attempt to assign Compute device to application - Response: {1} - Details: {2}" -f $SerialNumber, $Response.status, $response.Details | Write-Verbose
        
            if ($Response.Details -match "Device already assigned") {
                $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Warning"
                $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device is already assigned to the Compute Ops Management application in the $Region region!"
                $objStatus.SubTasksStatus.SubscriptionStatus = "Complete"
                $objStatus.SubTasksStatus.SubscriptionDetail = "Device successfully attached to subscription key $SubscriptionKey!"
            }     
            elseif ($Response.Status -eq "Failed") {
                $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Failed"
                $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device cannot be assigned to the Compute Ops Management application in the $Region region!"
                $objStatus.SubTasksStatus.SubscriptionStatus = "Failed"
                $objStatus.SubTasksStatus.SubscriptionDetail = "Device cannot be attached to subscription key as the device could not be assigned to application instance!"
                $objStatus.Exception = $Response.Exception 
                $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
                $objStatus.Status = "Failed"
                [void] $OnboardingDevicesStatus.add($objStatus)
                return
            }
            elseif ($Response.Status -eq "Complete") {
                $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Complete"
                $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device successfully assigned to the Compute Ops Management application in the $Region region!"
                $objStatus.SubTasksStatus.SubscriptionStatus = "Complete"
                $objStatus.SubTasksStatus._SubscriptionDetail = "Device successfully attached to subscription key $SubscriptionKey!"
            }
  
  
            #-----------------------------------------------------------Assign subscription key to device-----------------------------------------------------------------------------
            # Not required as auto subscription is enabled ! Auto subscription assigns a license key as soon as a device is assigned to an application instance
            # This section can be uncommented if you don't want to activate the automatic subscription of devices to Compute (in this case the section 'Set Auto device subscription to Compute' must be commented).
            #--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  
            # "{0} -- Assigning subscription key to device" -f $iLOIP | Write-Verbose

            # $Response = Set-HPEGLDeviceSubscription -SubscriptionKey $SubscriptionKey -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
      
            # "{0} -- Attempt to assign subscription key to device - Response: {1} - Details: {2}" -f $iLOIP, $Response.status, $response.Details | Write-Verbose
  
            # if ($Response.Details -match "Device already licensed") {
            # $objStatus._SubscriptionStatus = "Warning"
            # $objStatus._SubscriptionDetail = "Device already attached to subscription key $SubscriptionKey!"
            # }
            # elseif ($Response.Status -eq "Failed") {
            # $objStatus._SubscriptionStatus = "Failed"
            # $objStatus._SubscriptionDetail = "Device cannot be attached to subscription key $SubscriptionKey!"
            # $objStatus.Exception = $_.Exception.message
            # [void] $OnboardingDevicesStatus.add($objStatus)
            # return
            # }
            # elseif ($Response.Status -eq "Complete") {
            # $objStatus._SubscriptionStatus = "Complete"
            # $objStatus._SubscriptionDetail = "Device successfully attached to subscription key $SubscriptionKey!"
            # }
    
      
            #----------------------------------------------------------Connect iLOs to Compute Ops Management -----------------------------------------------------------------------------

            "{0} -- Attempting to connect iLO {1} to HPE Compute Ops Management!" -f $SerialNumber, $IloIP | Write-Verbose
            
            # If -DisconnectiLOfromOneView switch used: disconnect iLO from Oneview
            if ($DisconnectiLOfromOneView) { 
                $OverrideManager = $True 
            } 
            else {
                $OverrideManager = $False
            }
  
  
            $Body = [System.Collections.Hashtable]@{
                ActivationKey   = $ActivationKey
                OverrideManager = $OverrideManager
            } | ConvertTo-Json 
                        
                        
            $AddURI = "/redfish/v1/Managers/1/Actions/Oem/Hpe/HpeiLO.EnableCloudConnect"

            $url = ( $iLObaseURL + $AddURI)
        
            
            "{0} -- iLO {1} - Method: POST - URI: {2}" -f $SerialNumber, $IloIP, $url | Write-Verbose
            "{0} -- iLO {1} - Hearders content: {2}" -f $SerialNumber, $IloIP, ($Headers | Out-String) | Write-Verbose
            "{0} -- iLO {1} - Body content: `n{2}" -f $SerialNumber, $IloIP, $Body | Write-Verbose
       
            try {
  
                $response = Invoke-RestMethod -Method POST -Uri $url -Body $Body -Headers $Headers -ErrorAction Stop

                "{0} -- iLO {1} - Raw Response: {2}" -f $SerialNumber, $IloIP, ($Response | Out-String) | Write-Verbose

                $msg = $response.error.'@Message.ExtendedInfo'.MessageId
                    
                "{0} -- iLO {1} - Response: {2}" -f $SerialNumber, $IloIP, $msg | Write-Verbose

                if ($msg -match "Success") {
                    "{0} -- iLO {1} successfully connected to HPE Compute Ops Management!" -f $SerialNumber, $IloIP | Write-Verbose
                    $objStatus.SubTasksStatus.iLOConnectionStatus = "Complete"
                    $objStatus.SubTasksStatus.iLOConnectionDetails = "iLO successfully connected to HPE Compute Ops Management!"
                }


            }
            catch {
                                
                $err = (New-Object System.IO.StreamReader( $_.Exception.Response.GetResponseStream() )).ReadToEnd() 
                $msg = $err.error.'@Message.ExtendedInfo'.MessageId

                "{0} -- iLO {1} cannot be connected to HPE Compute Ops Management! Error: {2}" -f $SerialNumber, $IloIP, $msg | Write-Verbose
                
                $objStatus.SubTasksStatus.iLOConnectionStatus = "Failed"
                $objStatus.SubTasksStatus.iLOConnectionDetails = "iLO cannot be connected to HPE Compute Ops Management! iLO seems to be under the control of HPE Oneview! To force the connection, use -DisconnectiLOfromOneView switch"
                $objStatus.Exception = "Error: {0}" -f $msg
                $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
                $objStatus.Status = "Failed"
                [void] $OnboardingDevicesStatus.add($objStatus)
                return
            }
        }
            
        else {
  
            "{0} -- iLO is not supported by HPE GreenLake Platform! Skipping server..." -f $iLOIP | Write-Verbose
  
            $objStatus.SubTasksStatus.OnboardingStatus = "Error" 
            $objStatus.SubTasksStatus.OnboardingDetails = "Only iLO5 and iLO6 are supported by HPE GreenLake"
        }       
         
        if ($objStatus.SubTasksStatus.ContainsValue("Failed")) {
  
            $objStatus.Status = "Failed"
      
        }
        else {
            $objStatus.Status = "Complete"

        }

        $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
  
        [void] $OnboardingDevicesStatus.add($objStatus)
  
    }
  
    End {
  
        #----------------------------------------------------------Disconnect from HPE GreenLake-----------------------------------------------------------------------------
  
        "{0} -- Disconnecting from the HPE GreenLake platform..." -f $HPEGreenLakeSession.username | Write-Verbose

        $response = Disconnect-HPEGL 
  
  
        if ($OnboardingDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
            write-error "One or more devices failed the full onboarding attempt!"
      
        }   
  
        Return $OnboardingDevicesStatus
  
    }
}


Function New-HPEGLDeviceStorageObject {
    <#
    .SYNOPSIS
    Create a Storage object for Add-HPEGLDeviceStorage.
 
    .DESCRIPTION
    This cmdlet creates a Storage PSCustomObject to be used with Add-HPEGLDeviceStorage as a pipeline input.
     
    .PARAMETER SerialNumber
    Serial number of the device.
             
    .PARAMETER SubscriptionKey
    Subscription Key of the device.
 
    .OUTPUTS
    Output the generated PSCustomObject.
 
    .EXAMPLE
    New-HPEGLDeviceStorageObject -SerialNumber "121341123" -SubscriptionKey "FED5342F3DA45DW2WSD5HT56"
 
    Create a Storage device PSCustomObject with the specified serial number and subscription key.
 
    .EXAMPLE
    $StorageDevicesToAdd = @()
    ForEach ($Device in $Device_Collection) {
        $SerialNumber = $Device.SerialNumber
        $SubscriptionKey = $Device.subscription
        $StorageDevicesToAdd += New-HPEGLDeviceStorageObject -SerialNumber $SerialNumber -SubscriptionKey $SubscriptionKey
    }
 
    Sample script to create a list of devices using New-HPEGLDeviceStorageObject. This list can then be used as a pipeline input to Add-HPEGLDeviceStorage.
 
    $StorageDevicesToAdd | Add-HPEGLDeviceStorage
 
    .LINK
    Add-HPEGLDeviceStorage
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'default')]
    Param( 
 
        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,
    
        [Parameter (Mandatory, ParameterSetName = "default")]
        [ValidateNotNullOrEmpty()]
        [String]$SubscriptionKey

    ) 
  

    Process {     

        $_StorageObj = NewObject -AddStorageDevice
        
        $_StorageObj.SerialNumber = $SerialNumber
        $_StorageObj.SubscriptionKey = $SubscriptionKey
        
   
    }
 
    end {

        return    $_StorageObj
    }

}


Function Add-HPEGLDeviceStorage {
    <#
    .SYNOPSIS
    Add Storage device(s) to the HPE GreenLake console.
 
    .DESCRIPTION
    This Cmdlet adds Storage device(s) to the HPE GreenLake console.
    Can optionally add tags during the onboarding process.
    Devices must meet the requirements of the Data Services Cloud Console and be on the list of supported systems.
 
    For Infrastructure as a service, only the serial number must be provided.
    For purchase or lease, serial number and subscription key must be provided.
     
    .PARAMETER SerialNumber
    Serial number of the storage device to be added.
    The serial number can be found in the order confirmation email or in the email received after you activate the storage device software.
    For Nimble devices, it can be retrieved from the Storage System UI or the pull-out tab.
 
    .PARAMETER SubscriptionKey
    Subscription Key of the device to be added.
    This value can be found in the email received after you activate the storage device software.
    For Nimble devices, it can be retrieved from the Storage System UI.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Add-HPEGLDeviceStorage -SerialNumber AF-22233322 -SubscriptionKey FED5342F3DA45DW2WSD5HT56
     
    Add a storage device using a serial number and subscription key.
 
    .EXAMPLE
    Import-Csv Storage_Devices.csv | Add-HPEGLDeviceStorage
 
    Add all storage devices listed in a Storage_Devices.csv file to the HPE GrenLake Cloud console.
 
    The content of the csv file must use the following format:
 
        SerialNumber, SubscriptionKey
        AF-23454852, FED5342F3DA45DW2WSD5HT56
        AF-32331565, 4WS5SW48SA5D4S5W46A24F8D
        AF-32331597, 8SA5D4S5W432FDFGDGF342DJ
  
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'AF-23454852'; SubscriptionKey = 'FED5342F3DA45DW2WSD5HT56' },
        [PSCustomObject]@{SerialNumber = 'AF-32331565'; SubscriptionKey = '4WS5SW48SA5D4S5W46A24F8D' }
    )
 
    $devices | Add-HPEGLDeviceStorage
     
    Add all storage devices (2) listed in $devices with the specified serial numbers and subscription keys.
     
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) with serialnumber and SubscriptionKey properties.
        New-HPEGLDeviceStorageObject can be used to create this object.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be added
        * SubscriptionKey - Subscription key for the device attempted to be added (if provided)
        * Status - Status of the onboarding attempt (Failed for http error return; Complete if onboarding is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice
    New-HPEGLDeviceStorageObject
    Add-HPEGLDeviceTag
    Remove-HPEGLDeviceTag
    Set-HPEGLDeviceApplication
    Remove-HPEGLDeviceApplication
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $false, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Subscription_Key')]
        [String]$SubscriptionKey,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri  
        $AddDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber    = $SerialNumber
            SubscriptionKey = $SubscriptionKey
            Status          = $Null
            Details         = $Null
            Exception       = $Null
                  
        }

        # Build DeviceList object

        if ($SubscriptionKey) {

            $DeviceList += [PSCustomObject]@{
                serial_number  = $SerialNumber
                entitlement_id = $SubscriptionKey 
                app_category   = 'STORAGE'
            }
        }
        else {

            $DeviceList += [PSCustomObject]@{
                serial_number = $SerialNumber
                app_category  = 'STORAGE'
            }
        }
       

        # Build payload
        $payload = [PSCustomObject]@{
            devices = $DeviceList 
        } | ConvertTo-Json -Depth 5
          

        # Test if device present
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
       
        }
        catch {
            Throw $_
        }
        
        if ( $device) {
            # Must return a message if device is found
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device already present on the HPE GreenLake platform"

        }
        else {

            # Add device
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully added to the HPE GreenLake platform"
                    
                }
                
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device was not added to the HPE GreenLake platform"
                    $objStatus.Exception = $_.Exception.message 
                }
            
            }    
      
        }

        [void] $AddDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($AddDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the onboarding attempt!"
          
            }
        }

        Return $AddDevicesStatus

    }
}


Function Add-HPEGLDeviceStorageFullService {
    <#
    .SYNOPSIS
    Complete process of adding a storage system in HPE GreenLake and connecting it with a HPE Compute Ops Management instance.
   
    .DESCRIPTION
    This Cmdlet can add one or multiple storage devices defined in a CSV file to the HPE GreenLake platform.
 
    To correctly run the cmdlet, it is essential that the system has access to both the Internet (for accessing the HPE GreenLake platform)
    and the iLO network (which is typically a private network).
   
    Actions performed during the onboarding process:
 
        1/ Connect to HPE GreenLake using the default account or the one provided using the GLCompanyName parameter.
        2/ Onboard each device to the HPE GreenLake platform account.
        3/ Set optional server tags if defined with the Tags parameter.
        4/ Associate each device with the defined application instance.
   
    If provided as a pipeline input, the content of the csv file must use the following format:
   
        SerialNumber, SubscriptionKey, Tags
        AF-87654321, R3E34DSF32DSS42DWM7S, Country=US City=Houston
        AF-12345678, R6GZQRSK2OKBESEPQCW2, Country=FR City=Mougins
        AF-01020304, EW3D2W1WZ8B4G9OFF34D
 
    Note that for AF-01020304, no tag is assigned in this example.
 
    .PARAMETER GLCredential
    PSCredential object of a HPE GreenLake account represented by a username (email address) and a password.
     
    .PARAMETER GLCompanyName
    Name of your company account on the HPE GreenLake platform. This is an optional parameter that can be used when you have more than one
    company accounts on the HPE GreenLake platform. By default, the cmdlet selects the first available account.
   
    .PARAMETER SerialNumber
    Serial number of the storage device to be added.
    The serial number can be found in the order confirmation email or in the email received after you activate the storage device software.
    For Nimble devices, it can be retrieved from the Storage System UI or the pull-out tab.
 
    .PARAMETER SubscriptionKey
    Subscription Key of the device to be added.
    This value can be found in the email received after you activate the storage device software.
    For Nimble devices, it can be retrieved from the Storage System UI.
  
    .PARAMETER Tags
    Optional parameter that can be used to add tags to the device during the onboarding.
    The existing tags for devices already on the platform are retained.
    Tags must meet the following string format <Name>=<Value> <Name>=<Value> such as "Country=US State=TX App=Grafana" or "Country=US"
   
    .PARAMETER Application
    Specifies the name of the storage application (Data Services Cloud Console by default).
 
    .PARAMETER Region
    Specifies the Compute Ops Management region instance where to onboard the storage device(s).
 
    .EXAMPLE
    $Response = import-csv .\Storage_Devices.csv | Add-HPEGLDeviceStorageFullService -GLCredential $GLCredential -GLCompanyName HPE_Mougins -Region eu-central
   
    Connect to HPE GreenLake using the "HPE_Mougins" account.
    Onboard each storage device listed in a Storage_Devices.csv file to the HPE GreenLake platform "HPE_Mougins" account.
    Associate each storage device with the Data Services Cloud Console application in the Central European region.
    Assign each storage device with the provided subscription key and tags.
    $Response returns an overall onboarding status of all devices.
    $Response[0] returns the onboarding status of the first device.
    $Response[0].SubTasksStatus returns the subtask status of the first device.
 
    .EXAMPLE
    $Response = Add-HPEGLDeviceStorageFullService -GLCredential $GLCredential -Region eu-central -GLCompanyName DreamCompany -SerialNumber AF-12345678 -SubscriptionKey 4WS5SW48SA5D4S5W46A24F8D -Tags Country=US State=Texas City=Austin
 
    Connect to HPE GreenLake using the "DreamCompany" account.
    Onboard the storage device "AF-12345678" to the HPE GreenLake platform "DreamCompany" account.
    Associate the storage device with the Data Services Cloud Console application in the Central European region.
    Assign to the Storage device a subscription key "4WS5SW48SA5D4S5W46A24F8D" and three tags.
    $Response returns the onboarding status of the device.
    $Response.SubTasksStatus returns the onboarding status of the device's subtasks.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) to be added with storage system information and Tags to be assigned.
        The list must contain the following fields: SerialNumber, SubscriptionKey and Tags.
   
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be added
        * PartNumber - Part number of the device attempted to be added
        * Tags - Tags of the device attempted to be added
        * Status - Status of the full onboarding attempt (Failed for http error return; Complete if full onboarding is successful)
        * SubTasksStatus - Hashtable object of subtasks
                * ApplicationAssignmentStatus - Status of the application assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * ApplicationAssignmentDetail - More information about the application assignment status
                * OnboardingStatus - Status of the onboarding attempt (Failed for http error return; Complete if onboarding is successful; Warning if no action is needed)
                * OnboardingDetails - More information about the onboarding attempt status
                * SubscriptionStatus - Status of the subscription attempt (Failed for http error return; Complete if successful)
                * SubscriptionDetail - More information about the subscription status
                * TagAssignmentDetails - Status of the tag(s) assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * TagAssignmentStatus - More information about the tag(s) assignment status
        * Exception - Exception returns during one of the operations
     
   #>

  
    [CmdletBinding()]
    Param( 
  
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$GLCredential,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [String]$GLCompanyName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Serial_Number')]
        [String]$SerialNumber,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('Subscription_Key')]
        [String]$SubscriptionKey,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [String]$Tags,

        [Parameter (ParameterSetName = "Default")]
        [String]$Application = "Data Services Cloud Console",

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [String]$Region

      

    ) 
  
  
    Begin {
  
        $OnboardingDevicesStatus = [System.Collections.ArrayList]::new()
        
  
        #----------------------------------------------------------Connection to HPE GreenLake -----------------------------------------------------------------------------
  
        try {
  
            if ($GLCompanyName) {
  
                if ( $PSBoundParameters['Verbose']) {
  
                    Connect-HPEGL -Credential $GLCredential -CompanyName $GLCompanyName -Verbose | Out-Null
                }
                else {
  
                    Connect-HPEGL -Credential $GLCredential -CompanyName $GLCompanyName | Out-Null
  
                }
  
            }
            else {
  
                if ( $PSBoundParameters['Verbose']) {
  
                    Connect-HPEGL -Credential $GLCredential -Verbose | Out-Null
                }
                else {
                    Connect-HPEGL -Credential $GLCredential | Out-Null
  
                }
            }
        }
        catch {
            Throw "Connection to HPE GreenLake platform failed!" 
  
        }
  
  
        # Check if application instance is present
        "Checking if application instance is present in {0}" -f $Region | Write-Verbose
  
        $_Application = Get-HPEGLApplication -Provisioned -Name $Application -Region $Region
   
        if ($_Application) {
    
            $ApplicationInstanceId = $_Application.application_instance_id
  
            "Application ID is: {0}" -f $ApplicationInstanceId | Write-Verbose
  
        }
        else {
            Throw "Error! There is no Data Services Cloud Console instance in '$Region'!"
            
        }   


    }
  
    Process {
  
        #----------------------------------------------------------Onboard device(s) to the HPE GreenLake platform -----------------------------------------------------------------------------
  
        # Create object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber    = $SerialNumber
            SubscriptionKey = $SubscriptionKey
            Tags            = $Tags
            Status          = $Null
            SubTasksStatus  = @{
                OnboardingStatus            = $Null
                OnboardingDetails           = $Null
                TagAssignmentStatus         = $Null
                TagAssignmentDetails        = $Null
                ApplicationAssignmentStatus = $Null
                ApplicationAssignmentDetail = $Null
                SubscriptionStatus          = $Null
                SubscriptionDetail          = $Null
            }
            Exception       = $Null
        }
  
        # Display pipeline input
        "SN: {0}" -f $SerialNumber |  Write-Verbose
        "SubscriptionKey: {0}" -f $SubscriptionKey |  Write-Verbose
        "Tags: {0}" -f $Tags |  Write-Verbose
        "Region: {0}" -f $Region |  Write-Verbose
      
        
        #------------------------------------------------------Add device to the HPE GreenLake platform with Tag values------------------------------------------------------------------
       
        "{0} -- Adding Device to GLCP - SubscriptionKey={1} - Tags='{2}'" -f $SerialNumber, $SubscriptionKey, $Tags | Write-Verbose
  
        $Response = Add-HPEGLDeviceStorage -SerialNumber $SerialNumber -SubscriptionKey $SubscriptionKey -ErrorAction SilentlyContinue

            
        "{0} -- Attempt to add Storage device - Response: {1} - Details: {2}" -f $SerialNumber, $Response.status, $response.Details | Write-Verbose
  
        if ($Response.Details -match "Device already present") {
            $objStatus.SubTasksStatus.OnboardingStatus = "Warning"
            $objStatus.SubTasksStatus.OnboardingDetails = "Device is already present on the HPE GreenLake platform!"
        }     
        elseif ($Response.Status -eq "Failed") {
            $objStatus.SubTasksStatus.OnboardingStatus = "Failed"
            $objStatus.SubTasksStatus.OnboardingDetails = "Device cannot be added to the HPE GreenLake platform!"
            $objStatus.Exception = $Response.Exception 
            $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
            $objStatus.Status = "Failed"
            [void] $OnboardingDevicesStatus.add($objStatus)
            return
        }
        elseif ($Response.Status -eq "Complete") {
            $objStatus.SubTasksStatus.OnboardingStatus = "Complete"
            $objStatus.SubTasksStatus.OnboardingDetails = "Device successfully added to the HPE GreenLake platform!"
        }
    
      
        #------------------------------------------------------Add tags to storage device------------------------------------------------------------------


        if ($Tags) {

            "{0} -- Adding Tags to Storage device - Tags='{1}'" -f $SerialNumber, $Tags | Write-Verbose

            $Response = Add-HPEGLDeviceTag -SerialNumber $SerialNumber -Tags $Tags -ErrorAction SilentlyContinue
            "{0} -- Attempt to add Storage device tags - Response: {1} - Details: {2}" -f $SerialNumber, $Response.status, $response.Details | Write-Verbose

            if ($Response.Status -eq "Failed") {
                $objStatus.SubTasksStatus.TagAssignmentStatus = "Failed"
                $objStatus.SubTasksStatus.TagAssignmentDetails = $response.Details
            }
            elseif ($Response.Status -eq "Warning") {
                $objStatus.SubTasksStatus.TagAssignmentStatus = "Warning"
                $objStatus.SubTasksStatus.TagAssignmentDetails = $response.Details
            }
            elseif ($Response.Status -eq "Complete") {
                $objStatus.SubTasksStatus.TagAssignmentStatus = "Complete"
                $objStatus.SubTasksStatus.TagAssignmentDetails = "Tags successfully assigned!"
            }

        }
        else {
            "{0} -- No tag to add to Storage device" -f $SerialNumber | Write-Verbose
        }
      
        #-----------------------------------------------------------Assign storage device to application instance-----------------------------------------------------------------------------
          

        "{0} -- Assigning Device to DSCC application in {1}" -f $SerialNumber, $Region | Write-Verbose
            
        $Response = Set-HPEGLDeviceApplication -ApplicationName $Application -Region $Region -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
  
        "{0} -- Attempt to assign device to application - Response: {1} - Details: {2}" -f $SerialNumber, $Response.status, $response.Details | Write-Verbose
        
        if ($Response.Details -match "Device already assigned") {
            $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Warning"
            $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device is already assigned to the Data Services Cloud Console application in the $Region region!"
            $objStatus.SubTasksStatus.SubscriptionStatus = "Complete"
            $objStatus.SubTasksStatus.SubscriptionDetail = "Device successfully attached to subscription key $SubscriptionKey!"
        }     
        elseif ($Response.Status -eq "Failed") {
            $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Failed"
            $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device cannot be assigned to the Data Services Cloud Console application in the $Region region!"
            $objStatus.Exception = $Response.Exception 
            $objStatus.SubTasksStatus.SubscriptionStatus = "Failed"
            $objStatus.SubTasksStatus.SubscriptionDetail = "The subscription key cannot be applied because the application assignment failed!"
            $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
            $objStatus.Status = "Failed"
            [void] $OnboardingDevicesStatus.add($objStatus)
            return
        }
        elseif ($Response.Status -eq "Complete") {
            $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Complete"
            $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device successfully assigned to the Data Services Cloud Console application in the $Region region!"
            $objStatus.SubTasksStatus.SubscriptionStatus = "Complete"
            $objStatus.SubTasksStatus.SubscriptionDetail = "Device successfully attached to subscription key $SubscriptionKey!"
        }
  
        if ($objStatus.SubTasksStatus.ContainsValue("Failed")) {
  
            $objStatus.Status = "Failed"
      
        }
        else {
            $objStatus.Status = "Complete"

        }

        $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
  
  
        [void] $OnboardingDevicesStatus.add($objStatus)
  
    }
  
    End {
  
        #----------------------------------------------------------Disconnect from HPE GreenLake-----------------------------------------------------------------------------
  
        "{0} -- Disconnecting from the HPE GreenLake platform..." -f $HPEGreenLakeSession.username | Write-Verbose

        Disconnect-HPEGL | out-Null
  
        if ($OnboardingDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
            write-error "One or more devices failed the full onboarding attempt!"
      
        }   
  
        Return $OnboardingDevicesStatus
  
    }
}


Function New-HPEGLDeviceNetworkObject {
    <#
    .SYNOPSIS
    Create a Network object for Add-HPEGLDeviceNetwork.
 
    .DESCRIPTION
    This cmdlet creates a Network PSCustomObject to be used with Add-HPEGLDeviceNetwork as a pipeline input.
     
    .PARAMETER SerialNumber
    Serial number of the device.
             
    .PARAMETER MacAddress
    Mac address of the device.
 
    .PARAMETER CloudActivationKey
    Cloud Activation Key of the device.
 
    .OUTPUTS
    Output the generated PSCustomObject.
 
    .EXAMPLE
    New-HPEGLDeviceNetworkObject -SerialNumber "121341123" -MacAddress "aa:bb:cc:dd:ee:ff"
 
    Create a Storage device PSCustomObject with the specified serial number and mac address.
 
    .EXAMPLE
    $NetworkDevicesToAdd = @()
    ForEach ($Device in $Device_Collection) {
        $CloudActivationKey = $Device.CloudActivationKey
        $MacAddress = $Device.MacAddress
        $NetworkDevicesToAdd += New-HPEGLDeviceNetworkObject -CloudActivationKey $CloudActivationKey -MacAddress $MacAddress
    }
 
    Sample script to create a list of devices using New-HPEGLDeviceNetworkObject. This list can then be used as a pipeline input to Add-HPEGLDeviceNetwork.
 
    $NetworkDevicesToAdd | Add-HPEGLDeviceNetwork
 
    .LINK
    Add-HPEGLDeviceNetwork
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Evaluation')]
    Param( 
 
        [Parameter (Mandatory, ParameterSetName = "Evaluation")]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,
    
        [Parameter (Mandatory, ParameterSetName = "Evaluation")]
        [Parameter (Mandatory, ParameterSetName = "Subscription")]
        [ValidateNotNullOrEmpty()]
        [String]$MACAddress,

        [Parameter (Mandatory, ParameterSetName = "Subscription")]
        [ValidateNotNullOrEmpty()]
        [String]$CloudActivationKey

    ) 
  

    Process {     

        $_NetworkObj = NewObject -AddNetworkDevice
        
        if ($SerialNumber) {
            $_NetworkObj.SerialNumber = $SerialNumber

        }
        else {
            $_NetworkObj.SerialNumber = $Null
        }
   
        
        if ($CloudActivationKey) {
            $_NetworkObj.CloudActivationKey = $CloudActivationKey
            
        }
        else {
            $_NetworkObj.CloudActivationKey = $Null
        }


        if ($MACAddress) {
            $_NetworkObj.MACAddress = $MACAddress
            
        }

        
   
    }
 
    end {

        return    $_NetworkObj
    }

}


Function Add-HPEGLDeviceNetwork {
    <#
    .SYNOPSIS
    Add Network device(s) to the HPE GreenLake console.
 
    .DESCRIPTION
    This Cmdlet adds Network device(s) to the HPE GreenLake console.
    Can optionally add tags during the onboarding process.
     
    Devices must meet the requirements of Aruba Central and be on the list of supported devices.
 
    Aruba Central supports the following options for adding devices.
    - Adding Devices (Evaluation Account): Serial number + MAC address
    - Adding Devices (Paid Subscription): MAC address + Cloud Activation Key
 
    You can find the serial number and MAC address of Aruba devices on the front or back of the hardware.
 
    .PARAMETER SerialNumber
    Serial number of the device to be added.
    Most Aruba devices have the serial number on the front or back of the hardware.
     
    .PARAMETER MACAddress
    MAC address of the device to be added.
    Most Aruba devices have MAC address on the front or back of the hardware.
 
    .PARAMETER CloudActivationKey
    Cloud activation key of your device to be added.
    You can find the cloud activation key in the WebUI, UI (in Maintenance > About) or CLI (show about or show system) of your Aruba device.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Add-HPEGLDeviceNetwork -SerialNumber A-23434324 -MACAddress aa:bb:cc:dd:ee:ff
        
    Add a network device using a serial number and a MAC address.
  
    .EXAMPLE
    Add-HPEGLDeviceNetwork -CloudActivationKey 1a2b3cd5e6f -MACAddress aa:bb:cc:dd:ee:ff
 
    Add a network device using a cloud activation key and a MAC address.
     
    .EXAMPLE
    Import-Csv Network_Devices.csv | Add-HPEGLDeviceNetwork
 
    Add all network devices listed in a Network_Devices.csv file to the HPE GrenLake Cloud console.
 
    The content of the csv file must use the following format:
 
        SerialNumber, MACAddress
        A-23434324, aa:bb:cc:dd:ee:ff
        A-53234730, 11:bb:22:dd:33:78
        A-58976464, ff:bb:e3:d2:34:23
 
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'A-23434324'; MACAddress = 'aa:bb:cc:dd:ee:ff' },
        [PSCustomObject]@{SerialNumber = 'A-53234730'; MACAddress = '11:bb:22:dd:33:ff' }
    )
 
    $devices | Add-HPEGLDeviceNetwork
     
    Add all network devices (2) listed in $devices with the specified serial numbers and MAC addresses.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) with MACAddress, SerialNumber and CloudActivationKey properties.
        New-HPEGLDeviceNetworkObject can be used to create this object.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * MACAddress - MAC address of the device attempted to be added
        * CloudActivationKey - Cloud activation key for the device attempted to be added (if provided)
        * SerialNumber - Serial number of the device attempted to be added (if provided)
        * Status - Status of the onboarding attempt (Failed for http error return; Complete if onboarding is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice
    Add-HPEGLDeviceTag
    Remove-HPEGLDeviceTag
    Set-HPEGLDeviceApplication
    Remove-HPEGLDeviceApplication
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>


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

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Subscription")]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Evaluation")]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") })]
        [Alias ('mac_address')]
        [String]$MACAddress,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Subscription")]
        [ValidateNotNullOrEmpty()]
        [Alias ('CloudActivation_Key', 'Cloud_Activation_Key', 'Cloud_ActivationKey', 'CloudActivation', 'Cloud_Activation')]
        [String]$CloudActivationKey,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Evaluation")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Subscription")]
        [Parameter (Mandatory = $False, ParameterSetName = "Evaluation")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri  
        $AddDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        # Build object for the output
        $objStatus = [pscustomobject]@{
            MACAddress         = $MACAddress
            CloudActivationKey = $CloudActivationKey
            SerialNumber       = $SerialNumber
            Status             = $Null
            Details            = $Null
            Exception          = $Null
                  
        }        

        # Build DeviceList object

        if ($CloudActivationKey) {

            $DeviceList += [PSCustomObject]@{
                mac_address          = $MACAddress 
                cloud_activation_key = $CloudActivationKey 
                app_category         = 'NETWORK'
            }
        
        }
        else {

            $DeviceList += [PSCustomObject]@{
                serial_number = $SerialNumber
                mac_address   = $MACAddress 
                app_category  = 'NETWORK'
            }
        }

        # Build payload
        $payload = [PSCustomObject]@{
            devices = $DeviceList 
        } | ConvertTo-Json -Depth 5

        
        # Test if device present using MAC address
        try {
            $device = (Get-HPEGLdevice -DeviceType SWITCH -NoLimit -ErrorAction SilentlyContinue ) | ? mac_address -eq $MACAddress  
        }
        catch {
            Throw $_
        }
       

        if ( $device) {
            # Must return a message if device is found
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device already present on the HPE GreenLake platform"

        }
        else {

            # Add device
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully added to the HPE GreenLake platform"
                    
                }
                
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device was not added to the HPE GreenLake platform"
                    $objStatus.Exception = $_.Exception.message 
                }
            
            }    
      
        }

        [void] $AddDevicesStatus.add($objStatus)
    }

    
    end {

        if (-not $Whatif) {

            if ($AddDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the onboarding attempt!"
          
            }
        }

        Return $AddDevicesStatus

    }
}


Function Add-HPEGLDeviceNetworkFullService {
    <#
    .SYNOPSIS
    Complete process of adding a Network system in HPE GreenLake and connecting it with a HPE Compute Ops Management instance.
   
    .DESCRIPTION
    This Cmdlet can add one or multiple Network devices defined in a CSV file to the HPE GreenLake platform.
 
    To correctly run the cmdlet, it is essential that the system has access to both the Internet (for accessing the HPE GreenLake platform)
    and the iLO network (which is typically a private network).
   
    Actions performed during the onboarding process:
 
        1/ Connect to HPE GreenLake using the default account or the one provided using the GLCompanyName parameter.
        2/ Onboard each device to the HPE GreenLake platform account.
        3/ Set optional server tags if defined with the Tags parameter.
        4/ Associate each device with the defined application instance.
   
    If provided as a pipeline input, the content of the csv file must use the following format:
 
      MACAddress, CloudActivationKey, Tags
      38:10:F0:00:00:00, FED5342F3DA45DW2WSD5HT56, Country=FR City=Mougins
      38:10:F0:00:00:0A, 4WS5SW48SA5D4S5W46A24F8D, Country=US State=Texas City=Austin
      38:10:F0:00:00:0F, 8SA5D4S5W432FDFGDGF342DJ
 
      or
 
      MACAddress, SerialNumber, Tags
      38:10:F0:00:00:00, TW12345678, Country=FR City=Mougins
      38:10:F0:00:00:0A, TW87654321, Country=FR City=Mougins
      38:10:F0:00:00:0F, TW00000000
   
    Note that for 38:10:F0:00:00:0F, no tag is assigned in this example.
 
    .PARAMETER GLCredential
    PSCredential object of a HPE GreenLake account represented by a username (email address) and a password.
     
    .PARAMETER GLCompanyName
    Name of your company account on the HPE GreenLake platform. This is an optional parameter that can be used when you have more than one
    company accounts on the HPE GreenLake platform. By default, the cmdlet selects the first available account.
     
    .PARAMETER Tags
    Optional parameter that can be used to add tags to the device during the onboarding.
    The existing tags for devices already on the platform are retained.
    Tags must meet the following string format <Name>=<Value> <Name>=<Value> such as "Country=US State=TX App=Grafana" or "Country=US"
 
    .PARAMETER Application
    Specifies the name of the network application (Aruba Central by default).
 
    .PARAMETER Region
    Specifies the Compute Ops Management region instance where to onboard the Network device(s).
   
    .PARAMETER NetworkSerialNumber
    Serial number of the Network device to be added.
    The serial number can be found in the order confirmation email or in the email received after you activate the Network device software.
    For Nimble devices, it can be retrieved from the Network System UI or the pull-out tab.
 
    .PARAMETER NetworkMACAddress
    MAC Address of the device to be added.
    This value can be found in the email received after you activate the Network device software.
    For Nimble devices, it can be retrieved from the Network System UI.
 
    .EXAMPLE
    $Response = import-csv .\Network_Devices.csv | Add-HPEGLDeviceNetworkFullService -GLCredential $GLCredential -GLCompanyName HPE_Mougins -Region eu-central
   
    Connect to HPE GreenLake using the "HPE_Mougins" account.
    Onboard each Network device listed in a Network_Devices.csv file to the HPE GreenLake platform "HPE_Mougins" account.
    Associate each Network device with the Aruba Central application in the Central European region.
    Assign each Network device with the provided cloud activation key and tags.
    $Response returns an overall onboarding status of all devices.
    $Response[0] returns the onboarding status of the first device.
    $Response[0].SubTasksStatus returns the subtask status of the first device.
 
    .EXAMPLE
    $Response = Add-HPEGLDeviceNetworkFullService -GLCredential $GLCredential -Region eu-central -GLCompanyName "DreamCompany" -MACAddress "38:10:F0:00:00:00" -SerialNumber TW12345678 -Tags "Location=Texas City=Houston Country=US"
 
    Connect to HPE GreenLake using the "HPE TechEnablement Labs" account.
    Onboard the Network device with the MAC address 38:10:F0:00:00:00 and the serial number TW12345678 to the HPE GreenLake platform "DreamCompany" account.
    Associate the Network device with the Aruba Central application in the Central European region.
    Assign to the device an subscription key found in the account and set 3 tags.
    $Response returns the onboarding status of the device.
    $Response.SubTasksStatus returns the onboarding status of the device's subtasks.
     
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) to be added with Network system information and Tags to be assigned.
        The list must contain the following fields:
            - MACAddress, CloudActivationKey and Tags (optional)
            - MACAddress, SerialNumber and Tags (optional)
   
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * MACAddress - MAC Address of the device attempted to be added
        * CloudActivationKey - Cloud activation key to assign to the device
        * SerialNumber - Serial number of the device attempted to be added
        * Tags - Tags of the device attempted to be added
        * Status - Status of the full onboarding attempt (Failed for http error return; Complete if full onboarding is successful)
        * SubTasksStatus - Hashtable object of subtasks
                * ApplicationAssignmentStatus - Status of the application assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * ApplicationAssignmentDetail - More information about the application assignment status
                * OnboardingStatus - Status of the onboarding attempt (Failed for http error return; Complete if onboarding is successful; Warning if no action is needed)
                * OnboardingDetails - More information about the onboarding attempt status
                * SubscriptionStatus - Status of the subscription attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * SubscriptionDetail - More information about the subscription status
                * TagAssignmentDetails - Status of the tag(s) assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
                * TagAssignmentStatus - More information about the tag(s) assignment status
        * Exception - Exception returns during one of the operations
     
   #>


    [CmdletBinding()]
    Param( 
  
        [Parameter (Mandatory, ParameterSetName = "MAC_CloudActivationKey")]
        [Parameter (Mandatory, ParameterSetName = "MAC_SerialNumber")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$GLCredential,

        [Parameter (Mandatory = $False, ParameterSetName = "MAC_CloudActivationKey")]
        [Parameter (Mandatory = $False, ParameterSetName = "MAC_SerialNumber")]
        [String]$GLCompanyName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "MAC_CloudActivationKey")]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "MAC_SerialNumber")]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") })]
        [Alias ('mac_address')]
        [String]$MACAddress,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "MAC_CloudActivationKey")]
        [ValidateNotNullOrEmpty()]
        [Alias ('CloudActivation_Key', 'Cloud_Activation_Key', 'Cloud_ActivationKey', 'CloudActivation', 'Cloud_Activation')]
        [String]$CloudActivationKey,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "MAC_SerialNumber")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "MAC_CloudActivationKey")]
        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = "MAC_SerialNumber")]
        [String]$Tags,

        [Parameter (ParameterSetName = "MAC_CloudActivationKey")]
        [Parameter (ParameterSetName = "MAC_SerialNumber")]
        [String]$Application = "Aruba Central",

        [Parameter (Mandatory, ParameterSetName = "MAC_CloudActivationKey")]
        [Parameter (Mandatory, ParameterSetName = "MAC_SerialNumber")]
        [String]$Region
          
    ) 
  
  
    Begin {
  
        $OnboardingDevicesStatus = [System.Collections.ArrayList]::new()
        
  
        #----------------------------------------------------------Connection to HPE GreenLake -----------------------------------------------------------------------------
  
        try {
  
            if ($GLCompanyName) {
  
                if ( $PSBoundParameters['Verbose']) {
  
                    Connect-HPEGL -Credential $GLCredential -CompanyName $GLCompanyName -Verbose | Out-Null
                }
                else {
  
                    Connect-HPEGL -Credential $GLCredential -CompanyName $GLCompanyName | Out-Null
  
                }
  
            }
            else {
  
                if ( $PSBoundParameters['Verbose']) {
  
                    Connect-HPEGL -Credential $GLCredential -Verbose | Out-Null
                }
                else {
                    Connect-HPEGL -Credential $GLCredential | Out-Null
  
                }
            }
        }
        catch {
            Throw "Connection to HPE GreenLake platform failed!" 
  
        }
  
  
        # Check if application instance is present
        "Checking if application {0} is present in {1}" -f $Application, $Region | Write-Verbose
  
        $_Application = Get-HPEGLApplication -Provisioned -Name $Application -Region $Region
   
        if ($_Application) {
    
            $ApplicationInstanceId = $_Application.application_instance_id
  
            "Application ID is: {0}" -f $ApplicationInstanceId | Write-Verbose
  
        }
        else {
            Throw "Error! There is no '$Application' instance in '$Region'!"
            
        }   


    }
  
    Process {
  
        #----------------------------------------------------------Onboard device(s) to the HPE GreenLake platform -----------------------------------------------------------------------------
  
        # Create object for the output
        $objStatus = [pscustomobject]@{
  
            MACAddress         = $MACAddress
            CloudActivationKey = $CloudActivationKey
            SerialNumber       = $SerialNumber
            Tags               = $Tags
            Status             = $Null
            SubTasksStatus     = @{
                OnboardingStatus            = $Null
                OnboardingDetails           = $Null
                TagAssignmentStatus         = $Null
                TagAssignmentDetails        = $Null
                ApplicationAssignmentStatus = $Null
                ApplicationAssignmentDetail = $Null
                SubscriptionStatus          = $Null
                SubscriptionDetail          = $Null
            }
            Exception          = $Null
        }
  
        # Display pipeline input
        "MACAddress: {0}" -f $MACAddress |  Write-Verbose
        "CloudActivationKey: {0}" -f $CloudActivationKey |  Write-Verbose
        "SerialNumber: {0}" -f $SerialNumber |  Write-Verbose
        "Tags: {0}" -f $Tags |  Write-Verbose
        "Region: {0}" -f $Region |  Write-Verbose
      
            
        
        #------------------------------------------------------Add device to the HPE GreenLake platform with Tag values------------------------------------------------------------------
       
        "{0} -- Adding Device to GLCP - CloudActivationKey={1} - Tags='{2}'" -f $MACAddress, $CloudActivationKey, $Tags | Write-Verbose
  
        if ($CloudActivationKey) {
            $Response = Add-HPEGLDeviceNetwork -MACAddress $MACAddress -CloudActivationKey $CloudActivationKey -ErrorAction SilentlyContinue
        }
        else {
            $Response = Add-HPEGLDeviceNetwork -MACAddress $MACAddress -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
            
        }
                    
            
        "{0} -- Attempt to add Network device - Response: {1} - Details: {2}" -f $MACAddress, $Response.status, $response.Details | Write-Verbose
  
        if ($Response.Details -match "Device already present") {
            $objStatus.SubTasksStatus.OnboardingStatus = "Warning"
            $objStatus.SubTasksStatus.OnboardingDetails = "Device is already present on the HPE GreenLake platform!"
        }     
        elseif ($Response.Status -eq "Failed") {
            $objStatus.SubTasksStatus.OnboardingStatus = "Failed"
            $objStatus.SubTasksStatus.OnboardingDetails = "Device cannot be added to the HPE GreenLake platform!"
            $objStatus.Exception = $Response.Exception 
            $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
            $objStatus.Status = "Failed"
            [void] $OnboardingDevicesStatus.add($objStatus)
            return
        }
        elseif ($Response.Status -eq "Complete") {
            $objStatus.SubTasksStatus.OnboardingStatus = "Complete"
            $objStatus.SubTasksStatus.OnboardingDetails = "Device successfully added to the HPE GreenLake platform!"
        }
    
      
        #------------------------------------------------------Add tags to Network device------------------------------------------------------------------
        
        $NetworkingDevice = Get-HPEGLdevice -SearchString $MACAddress 

        if (-not $NetworkingDevice) {
    
            "{0} -- Device cannot be found in GLCP!" -f $MACAddress | Write-Verbose
            $objStatus.SubTasksStatus.OnboardingStatus = "Failed"
            $objStatus.SubTasksStatus.OnboardingDetails = "Onboarded device cannot be found!"           
            
        }
        else {

            if (! $SerialNumber) {

                $SerialNumber = $NetworkingDevice.serial_number
            }

            if ($Tags) {

                "{0} -- Adding Tags to Network device - Tags='{1}'" -f $MACAddress, $Tags | Write-Verbose

                $Response = Add-HPEGLDeviceTag -SerialNumber $SerialNumber -Tags $Tags -ErrorAction SilentlyContinue
                "{0} -- Attempt to add Network device tags - Response: {1} - Details: {2}" -f $MACAddress, $Response.status, $response.Details | Write-Verbose
                
                if ($Response.Status -eq "Failed") {
                    $objStatus.SubTasksStatus.TagAssignmentStatus = "Failed"
                    $objStatus.SubTasksStatus.TagAssignmentDetails = $response.Details
                }
                elseif ($Response.Status -eq "Warning") {
                    $objStatus.SubTasksStatus.TagAssignmentStatus = "Warning"
                    $objStatus.SubTasksStatus.TagAssignmentDetails = $response.Details
                }
                elseif ($Response.Status -eq "Complete") {
                    $objStatus.SubTasksStatus.TagAssignmentStatus = "Complete"
                    $objStatus.SubTasksStatus.TagAssignmentDetails = "Tags successfully assigned!"
                }

            }
            else {
                "{0} -- No tag to add to Network device" -f $MACAddress | Write-Verbose
            }
        

            #-----------------------------------------------------------Assign Network device to application instance-----------------------------------------------------------------------------
          

            "{0} -- Assigning Device to Aruba Central application in {1}" -f $MACAddress, $Region | Write-Verbose
            
            $Response = Set-HPEGLDeviceApplication -ApplicationName $Application -Region $Region -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
  
            "{0} -- Attempt to assign device to application - Response: {1} - Details: {2}" -f $MACAddress, $Response.status, $response.Details | Write-Verbose
        
            if ($Response.Details -match "Device already assigned") {
                $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Warning"
                $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device is already assigned to the Aruba Central application in the $Region region!"
            }     
            elseif ($Response.Status -eq "Failed") {
                $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Failed"
                $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device cannot be assigned to the Aruba Central application in the $Region region!"
                $objStatus.Exception = $Response.Exception 
                $objStatus.SubTasksStatus.SubscriptionStatus = "Failed"
                $objStatus.SubTasksStatus.SubscriptionDetail = "The subscription key cannot be applied because the application assignment failed!"
                $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
                $objStatus.Status = "Failed"
                [void] $OnboardingDevicesStatus.add($objStatus)
                return
            }
            elseif ($Response.Status -eq "Complete") {
                $objStatus.SubTasksStatus.ApplicationAssignmentStatus = "Complete"
                $objStatus.SubTasksStatus.ApplicationAssignmentDetail = "Device successfully assigned to the Aruba Central application in the $Region region!"
            }
  

  
            #-----------------------------------------------------------Assign subscription key to device-----------------------------------------------------------------------------

            # Check if a network subscription key is available
            "Checking if a network subscription key is available!" | Write-Verbose
  
            $DeviceType = $NetworkingDevice.device_type 
    
            $SubscriptionKey = (Get-HPEGLDeviceSubscription -Available -NotExpired -DeviceType $DeviceType).subscription_key | select -First 1

            if (-not $SubscriptionKey) {
    
                "{0} -- No subscription key for '{1}' device type can be found that has both not expired and still has licenses available!" -f $MACAddress, $DeviceType | Write-Verbose
                $objStatus.SubTasksStatus.SubscriptionStatus = "Failed"
                $objStatus.SubTasksStatus.SubscriptionDetail = "No subscription key with licenses available can be found!"
            
            }
            else {

                "{0} -- Valid subscription key found for this device type: {0}" -f $MACAddress, $SubscriptionKey | Write-Verbose       

                "{0} -- Assigning subscription key to device" -f $MACAddress | Write-Verbose

                $Response = Set-HPEGLDeviceSubscription -SubscriptionKey $SubscriptionKey -SerialNumber $SerialNumber -ErrorAction SilentlyContinue
  
                "{0} -- Attempt to assign subscription key to device - Response: {1} - Details: {2}" -f $MACAddress, $Response.status, $response.Details | Write-Verbose
  
                if ($Response.Details -match "Device already licensed") {
                    $objStatus.SubTasksStatus.SubscriptionStatus = "Warning"
                    $objStatus.SubTasksStatus.SubscriptionDetail = "Device already attached to subscription key $SubscriptionKey!"
                }     
                elseif ($Response.Status -eq "Failed") {
                    $objStatus.SubTasksStatus.SubscriptionStatus = "Failed"
                    $objStatus.SubTasksStatus.SubscriptionDetail = "Device cannot be attached to subscription key $SubscriptionKey!"
                    $objStatus.Exception = $_.Exception.message 
                
                }
                elseif ($Response.Status -eq "Complete") {
                    $objStatus.SubTasksStatus.SubscriptionStatus = "Complete"
                    $objStatus.SubTasksStatus.SubscriptionDetail = "Device successfully attached to subscription key $SubscriptionKey!"
                }
            }

            if ($objStatus.SubTasksStatus.ContainsValue("Failed")) {
  
                $objStatus.Status = "Failed"
          
            }
            else {
                $objStatus.Status = "Complete"

            }

         
        }
  
        $objStatus.SubTasksStatus = $objStatus.SubTasksStatus.GetEnumerator() | sort-Object name
        
        [void] $OnboardingDevicesStatus.add($objStatus)
  
    }
  
    End {
  
        #----------------------------------------------------------Disconnect from HPE GreenLake-----------------------------------------------------------------------------
  
        "{0} -- Disconnecting from the HPE GreenLake platform..." -f $HPEGreenLakeSession.username | Write-Verbose

        Disconnect-HPEGL | out-Null
  
        if ($OnboardingDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
            write-error "One or more devices failed the full onboarding attempt!"
      
        }   
  
        Return $OnboardingDevicesStatus
  
    }
}


# (not supported at this time!)
Function Remove-HPEGLDevice {
    <#
 
    .SYNOPSIS
    Remove device(s) from the HPE GreenLake console (not supported at this time!).
 
    .DESCRIPTION
    This Cmdlet deletes device(s) from HPE GreenLake console.
    API returns 'Method Not Allowed - error 405' (request method is known by the server but is not supported by the target resource)
     
    .PARAMETER SerialNumber
    Serial number of the device to be removed.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Remove-HPEGLDevice -SerialNumber MXQ73301YN
 
    Delete a device from the HPE GrenLake console using a serial number.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = '123456789012'},
        [PSCustomObject]@{SerialNumber = '123432356789'}
    )
 
    $devices | Remove-HPEGLDevice
     
    Delete all devices available in $devices from the HPE GrenLake console.
 
    .EXAMPLE
    Get-HPEGLDevice -SerialNumber MXQ73301YN | Remove-HPEGLDevice
 
    Delete a device from the HPE GrenLake console using the pipeline device information.
     
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) from Get-HPEGLDevice.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be removed
        * Status - Status of the removing attempt (Failed for http error return; Complete if removing is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice
    Add-HPEGLDeviceCompute
    Add-HPEGLDeviceTag
    Remove-HPEGLDeviceTag
    Set-HPEGLDeviceApplication
    Remove-HPEGLDeviceApplication
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'SN')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "SN")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "MAC")]
        [ValidateNotNullOrEmpty()]
        [Alias ('mac_address')]
        [String]$MACAddress,

        [Parameter (Mandatory = $False, ParameterSetName = "SN")]
        [Parameter (Mandatory = $False, ParameterSetName = "MAC")]
        [Switch]$Whatif
    ) 

    Begin {
        
        throw "Removing device is not supported at this time!"

        $UriAdd = $DevicesUri  
        $RemoveDevicesStatus = [System.Collections.ArrayList]::new()
        
    }

    Process {

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

        if ($SerialNumber) {

            # Test if device present using Serial number
            try {
                $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
           
            }
            catch {
                Throw $_
            }
            

            # Build object for the output
            $objStatus = [pscustomobject]@{
  
                SerialNumber = $SerialNumber
                Status       = $Null
                Details      = $Null
                Exception    = $Null
          
            }

        }
        elseif ($MACAddress) {

            # Test if device present using MAC address
            try {
                $device = (Get-HPEGLdevice -DeviceType SWITCH -NoLimit -ErrorAction SilentlyContinue ) | ? mac_address -eq $MACAddress  
            }
            catch {
                Throw $_
            }

            # Build object for the output
            $objStatus = [pscustomobject]@{
                MACAddress = $MACAddress
                Status     = $Null
                Details    = $Null
                Exception  = $Null
          
            }


        }
         
        if (-not $device) {
            # Must return a message if device is found
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device not found on the HPE GreenLake platform"

        }
        else {

            $PartNumber = $device | % part_number
            $DeviceType = $device | % device_type
       
            if ($device.mac_address) {
                $MacAddress = $device | % mac_address
            }
       
            # Create the object to remove a device
            if ($MacAddress) {
                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber
                    device_type   = $DeviceType
                    mac_address   = $MacAddress
                }
            }
            else {
                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber
                    device_type   = $DeviceType
                }
            }

            # Building payload
            $payload = [PSCustomObject]@{
                devices = $DeviceList 
            } | ConvertTo-Json -Depth 5    
        
                

            # Delete Device

            Try {
            
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'DELETE' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully removed from the HPE GreenLake platform"
                    
                }
            }
            catch {
            
                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device was not removed from the HPE GreenLake platform"
                    $objStatus.Exception = $_.Exception.message 
                }
            
            }      

        }

        [void] $RemoveDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($RemoveDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the removal attempt!"
          
            }
        }

        Return $RemoveDevicesStatus

    }
}


Function Disable-HPEGLDevice {
    <#
    .SYNOPSIS
    Archive device(s) on the HPE GreenLake platform.
 
    .DESCRIPTION
    This Cmdlet archives device(s) in HPE GreenLake console.
    Archiving devices will remove all application assignments and will remove them from your inventory list
 
    .PARAMETER SerialNumber
    Serial number of the device to be archived.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Disable-HPEGLDevice -SerialNumber CNX2380BLC
 
    Archive the device with the serial number CNX2380BLC.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'CNX2380BLC' }
        [PSCustomObject]@{SerialNumber = '7CE244P9LM' }
    )
 
    $devices | Disable-HPEGLDevice
 
    Archive the list of devices.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) from Get-HPEGLDevice.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be archived
        * Status - Status of the archiving attempt (Failed for http error return; Complete if archiving is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice -NotArchived
    Enable-HPEGLDevice
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri  
        $ArchivedDevicesStatus = [System.Collections.ArrayList]::new()
        
    }

    Process {

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

        # Test if device present using Serial number
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
           
        }
        catch {
            Throw $_
        }
            

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
          
        }

        if ( -not $device) {
            # Must return a message if device not found
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif ( $device.archived ) {
            # Must return a message if device already archived
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device already disabled (archived)!"
        }
        else {
        

            $PartNumber = $device | % part_number

            $DeviceType = $device | % device_type

            if ($device.mac_address) {

                $DeviceMacAddress = $device | % mac_address

                # Create the object to remove a device

                $DeviceList += [PSCustomObject]@{
                    archive       = $True
                    serial_number = $SerialNumber
                    part_number   = $PartNumber
                    device_type   = $DeviceType
                    mac_address   = $DeviceMacAddress
                }
            }
            else {

                # Create the object to remove a device

                $DeviceList += [PSCustomObject]@{
                    archive       = $True
                    serial_number = $SerialNumber
                    part_number   = $PartNumber
                    device_type   = $DeviceType
                    # mac_address = ''
                }
            }

            # Building payload
            $payload = [PSCustomObject]@{
                devices = $DeviceList 
            } | ConvertTo-Json -Depth 5    

     

            # Archive Device

            try {

                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PATCH' -body $payload -WhatIfBoolean $WhatIf | Out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully archived"
                    
                }
                
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device was not archived!"
                    $objStatus.Exception = $_.Exception.message 
                }
            
            }    

        }

        [void] $ArchivedDevicesStatus.add($objStatus)
   
    }

    end {

        if (-not $Whatif) {

            if ($ArchivedDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the archiving attempt!"
          
            }
        }

        Return $ArchivedDevicesStatus

    }
}


Function Enable-HPEGLDevice {
    <#
    .SYNOPSIS
    Unarchive device(s) on the HPE GreenLake platform.
 
    .DESCRIPTION
    This Cmdlet unarchives device(s) in HPE GreenLake console.
    Unarchiving devices will make devices available for assignment and subscription.
 
    .PARAMETER SerialNumber
    Serial number of the device to be unarchived.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Enable-HPEGLDevice -SerialNumber CNX2380BLC
 
    Unarchive the device with the serial number CNX2380BLC.
     
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'CNX2380BLC' }
        [PSCustomObject]@{SerialNumber = '7CE244P9LM' }
    )
 
    $devices | Enable-HPEGLDevice
 
    Unarchive the list of devices.
 
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) from Get-HPEGLDevice.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be unarchived
        * Status - Status of the unarchiving attempt (Failed for http error return; Complete if unarchiving is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice -archived
    Disable-HPEGLDevice
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri  
        $UnarchivedDevicesStatus = [System.Collections.ArrayList]::new()
        
    }

    Process {

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

        # Test if device present using Serial number
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
   
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }
    
   
        if (-not $device) {
            # Must return a message if device not found
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif (-not $device.archived ) {
            # Must return a message if device is not archived
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device is already enabled (unarchived)!"
        }
        else {
        

            $PartNumber = $device | % part_number

            $DeviceType = $device | % device_type
    
            if ($device.mac_address) {

                $DeviceMacAddress = $device | % mac_address

                # Create the object to remove a device

                $DeviceList += [PSCustomObject]@{
                    archive       = $False
                    serial_number = $SerialNumber
                    part_number   = $PartNumber
                    device_type   = $DeviceType
                    mac_address   = $DeviceMacAddress
                }
            }
            else {

                # Create the object to remove a device

                $DeviceList += [PSCustomObject]@{
                    archive       = $False
                    serial_number = $SerialNumber
                    part_number   = $PartNumber
                    device_type   = $DeviceType
                    # mac_address = ''
                }
            }

            # Building payload
            $payload = [PSCustomObject]@{
                devices = $DeviceList 
            } | ConvertTo-Json -Depth 5    

     

            # Unarchive Device


            try {

                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PATCH' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully unarchived"
                    
                }
                
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device was not archived!"
                    $objStatus.Exception = $_.Exception.message 
                }
            
            }    

        }

        [void] $UnarchivedDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($UnarchivedDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the unarchiving attempt!"
          
            }
        }

        Return $UnarchivedDevicesStatus

    }
   
}


Function Add-HPEGLDeviceTag {
    <#
    .SYNOPSIS
    Add tag(s) to a device(s).
 
    .DESCRIPTION
    This Cmdlet adds one or more tags to device(s).
 
    .PARAMETER SerialNumber
    Serial number of the device to which tags must be added.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER Tags
    Tags to be added to the device.
    Tags must meet the following string format <Name>=<Value> <Name>=<Value> such as "Country=US State=TX App=Grafana" or "Country=US"
 
    HPE GreenLake supports the following specification for all services across the platform and applications.
    https://support.hpe.com/hpesc/public/docDisplay?docId=a00120892en_us&docLocale=en_US&page=GUID-1E4DDAEA-E799-418F-90C8-30CE6A2873AB.html
    - Resources that support tagging can support up to 25 tags per resource.
    - Tag keys and values are case-insensitive.
    - There can be only one value for a particular tag key for a given resource.
    - Null is not allowed as a possible value for a tag key. Instead, an empty string ("") will be supported to enable customers to use tag key-value pairs for a label use case.
    - System-defined tags are allowed and start with the prefix "hpe:." User-defined tags cannot start with this prefix.
    - Tag key must have 1-128 characters.
    - Tag value can have a maximum of 256 characters.
    - Allowed characters are letters, numbers, spaces representable in UTF-8, and the following characters: _ . : = + - @.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
  
    .EXAMPLE
    Add-HPEGLDeviceTag -SerialNumber CWERX2380BLC -Tags "Departement=HR"
     
    Add tag 'Departement=HR' to the device CWERX2380BLC.
 
    .EXAMPLE
    Add-HPEGLDeviceTag -SerialNumber CWERX2380BLC -Tags "Country=US App=VMware"
     
    Add tags 'Country=US' and 'App=VMware' to the device CWERX2380BLC.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'CWERX2380BLC' },
        [PSCustomObject]@{SerialNumber = 'CWERX238DEXS' }
    )
 
    $devices | Add-HPEGLDeviceTag "Departement=HR Apps=RHEL"
 
    Add tags 'Departement=HR' and 'Apps=RHEL' to the list of devices defined in the $devices array.
 
    .EXAMPLE
    Import-Csv Tests/Network_Devices.csv | Add-HPEGLDeviceTag "Country=US City=Houston"
 
    Add two tags to all devices listed in a csv file containing at least a SerialNumber column.
     
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) from Get-HPEGLDevice.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be tagged
        * Status - Status of the tagging attempt (Failed for http error return; Warning if untagging is incomplete, Complete if tagging is successful; Warning if no action is needed)
        * TagsAdded - List of tags that have been successfully added
        * TagsNotAdded - List of tags that could not be added
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Remove-HPEGLDeviceTag
    Get-HPEGLDevice -tags
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory, Position = 1, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Tags,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesATagsUri  
        $AddTagsDevicesStatus = [System.Collections.ArrayList]::new()


    }

    Process {

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

        # Remove space at the end of the string if any
        $Tags = $Tags.TrimEnd()
    
        $splittedtags = $Tags.split(" ")

        # Check tag format, if format is not <tagname>=<value>, return error
        foreach ($splittedtag in $splittedtags) {

            if ($splittedtag -notmatch "^[A-Za-z0-9]+=[A-Za-z0-9][^=]*$") {
                write-warning "Tag '$splittedtag' format not supported! Expected format is <tagname>=<value>"
                return  
            }
        }

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

        foreach ($tag in $splittedtags) {
        
            $tagname = $tag.split('=')[0]
            $tagvalue = $tag.split('=')[1]
        
            $TagsList += [PSCustomObject]@{
                name  = $tagname
                value = $tagvalue 
            }
        } 
                

        # Test if device present using Serial number
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
                   
        }
        catch {
            Throw $_
        }
                    
        
        # Build object for the output
        $objStatus = [pscustomobject]@{
          
            SerialNumber = $SerialNumber
            TagsAdded    = $Null
            TagsNotAdded = $Null
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }
        
        if ( -not $device) {
            # Must return a message if device not found
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        else {

            # Capturing Tags that already exist
            $ExistingTags = $device.tags

            $AlreadyExistList = @()
            $TagsToBeAdded = @()
   
            foreach ($name in $TagsList.name) {
               
                "Tag to add: {0} - Tag present: {1} " -f $name, ($ExistingTags | ? name -eq $name).name | write-verbose

                If ($name -eq (($ExistingTags | ? name -eq $name).name)) {
                    $AlreadyExistList += $name
                }
                else {
                    $TagsToBeAdded += $name
                }

            }
           
            $PartNumber = $device | % part_number
            $AppCategory = $device | % device_type


            # Build DeviceList object
       
            $DeviceList += [PSCustomObject]@{
                serial_number = $SerialNumber
                part_number   = $PartNumber 
                app_category  = $AppCategory
           
            }

            # Build payload
            $payload = [PSCustomObject]@{
                devices     = $DeviceList 
                create_tags = $TagsList
            } | ConvertTo-Json -Depth 5
   

            # Add tags
            try {

                $Response = Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PUT' -body $payload -WhatIfBoolean $WhatIf           

                if ($response.psobject.properties.name -eq "failed_devices" ) {

                    if ($TagsList.Count -eq 1) {

                        "{0}: Tag '{1}' already present." -f $SerialNumber, $TagsList.name | Write-Verbose

                        if (-not $Whatif) {

                            $objStatus.Status = "Warning"
                            $objStatus.TagsNotAdded = [System.Collections.ArrayList]@($TagsList.name)

                            $objStatus.Details = "Tag already present"
                            
                        }


                    }
                    else {

                        "Nb of tags to add: {0}" -f $TagsToBeAdded.count | write-verbose
                        "Nb of tags already present: {0}" -f $AlreadyExistList.count | write-verbose

                        if (-not $Whatif) {

                            if ( $TagsToBeAdded -and $AlreadyExistList) {
                                # if ($TagsToBeAdded.count -eq 1 -and $AlreadyExistList.count -eq 1) {
                                "{0}: Tags added: '{1}' - Tags not added as already present: '{2}'" -f $SerialNumber, (($TagsToBeAdded) -join "' and '"), (($AlreadyExistList) -join "' and '") | Write-Verbose

                                $objStatus.Status = "Warning"
                                $objStatus.TagsAdded = [System.Collections.ArrayList]@("{0}" -f (($TagsToBeAdded) -join ", "))
                                    
                                $objStatus.TagsNotAdded = [System.Collections.ArrayList]@("{0}" -f (($AlreadyExistList) -join ", "))

                                $objStatus.Details = "{0} tag(s) added and {1} tag(s) already present" -f $TagsToBeAdded.count, $AlreadyExistList.count

                                # }
                                # if ($TagsToBeAdded.count -eq 1 -and $AlreadyExistList.count -gt 1) {
                                # "{0}: Tag added: '{1}' - Tags not added as already present: '{2}'" -f $SerialNumber, (($TagsToBeAdded) -join "' and '"), (($AlreadyExistList) -join "' and '") | Write-Verbose

                                # $objStatus.Status = "Warning"
                                # $objStatus.TagsAdded = "{0}" -f (($TagsToBeAdded) -join ", ")
                                # $objStatus.TagsNotAdded = "{1}" -f (($AlreadyExistList) -join ", ")
        
                                # $objStatus.Details = "1 tag added and {0} tags already present" -f $AlreadyExistList.count

                                # }
                                # if ($TagsToBeAdded.count -gt 1 -and $AlreadyExistList.count -gt 1) {
                                # "{0}: Tags added: '{1}' - Tags not added as already present: '{2}'" -f $SerialNumber, (($TagsToBeAdded) -join "' and '"), (($AlreadyExistList) -join "' and '") | Write-Verbose

                                # $objStatus.Status = "Warning"
                                # $objStatus.TagsAdded = "Tags added: '{0}' - Tags not added as already present: '{1}'" -f (($TagsToBeAdded) -join "' and '"), (($AlreadyExistList) -join "' and '")
        
                                # $objStatus.Details = "{0} tags added and {1} tags already present" -f $TagsToBeAdded.count, $AlreadyExistList.count

                                # }
                                # if ($TagsToBeAdded.count -gt 1 -and $AlreadyExistList.count -eq 1) {
                                # "{0}: Tags added: '{1}' - Tag not added as already present: '{2}'" -f $SerialNumber, (($TagsToBeAdded) -join "' and '"), (($AlreadyExistList) -join "' and '") | Write-Verbose

                                # $objStatus.Status = "Warning"
                                # $objStatus.TagsAdded = "Tags added: '{0}' - Tag not added as already present: '{1}'" -f (($TagsToBeAdded) -join "' and '"), (($AlreadyExistList) -join "' and '")
        
                                # $objStatus.Details = "{0} tags added and 1 tag already present" -f $TagsToBeAdded.count

                                # }

                            }
                
                            if ( $TagsToBeAdded -and -not $AlreadyExistList) {

                                if ($TagsToBeAdded.count -eq 1) {
                                    "{0}: Tag added: '{1}'" -f $SerialNumber, $TagsToBeAdded | Write-Verbose

                                    $objStatus.Status = "Complete"
                                    $objStatus.TagsAdded = [System.Collections.ArrayList]@($TagsToBeAdded)
   
                                    $objStatus.Details = "1 tag added"  

                                }  
                                else {
                                    "{0}: Tags added: '{1}'" -f $SerialNumber, (($TagsToBeAdded) -join "' and '") | Write-Verbose

                                    $objStatus.Status = "Complete"
                                    $objStatus.TagsAdded = [System.Collections.ArrayList]@("{0}" -f (($TagsToBeAdded) -join ", "))
    
                                    $objStatus.Details = "{0} tags added" -f $TagsToBeAdded.count

                                }
                            }

                            if ( -not $TagsToBeAdded -and $AlreadyExistList) {

                                if ($AlreadyExistList.count -eq 1) {
                                    "{0}: Tag not added as already present: '{1}'" -f $SerialNumber, $AlreadyExistList | Write-Verbose

                                    $objStatus.Status = "Warning"
                                    $objStatus.TagsNotAdded = [System.Collections.ArrayList]@($AlreadyExistList)
        
                                    $objStatus.Details = "1 tag already present"

                                }
                                else {
                                    "{0}: Tags not added as already present: '{1}'" -f $SerialNumber, (($AlreadyExistList) -join "' and '") | Write-Verbose

                                    $objStatus.Status = "Warning"
                                    $objStatus.TagsNotAdded = [System.Collections.ArrayList]@( "{0}" -f (($AlreadyExistList) -join ", "))

                                    $objStatus.Details = "{0} tags already present" -f $AlreadyExistList.count

                                }
                            }
                        }
                    }
                }
                elseif (($response | % response) -eq "success" ) {

                    if ($TagsList.Count -eq 1) {
                        "{0}: Tag '{1}' successfully added." -f $SerialNumber, $TagsList.name | Write-Verbose
                        
                        $objStatus.Status = "Complete"
                        $objStatus.TagsAdded = [System.Collections.ArrayList]@($TagsList.name)

                        $objStatus.Details = "1 tag added" 

                    }
                    else {
                        "{0}: Tags '{1}' successfully added." -f $SerialNumber, (($TagsList | % name) -join "' and '") | Write-Verbose

                        $objStatus.Status = "Complete"
                        $objStatus.TagsAdded = [System.Collections.ArrayList]@( "{0}" -f (($TagsList | % name) -join ", "))

                        $objStatus.Details = "{0} tags added" -f $TagsList.count
                    }

           
                }

            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device tagging error!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
        }  

        [void] $AddTagsDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($AddTagsDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the tagging attempt!"
          
            }
        }

        Return $AddTagsDevicesStatus

    }
}


Function Remove-HPEGLDeviceTag {
    <#
    .SYNOPSIS
    Remove tag(s) from a device(s).
 
    .DESCRIPTION
    This Cmdlet removes one or more tags from device(s).
 
    .PARAMETER SerialNumber
    Serial number of the device on which the tags must be removed.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER Tags
    Tag names to be removed from the device.
    Tag names must meet the following string format <Name> <Name> such as "Country State App" or "Country"
 
    .PARAMETER All
    Optional property that can be used to remove all existing tags.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Remove-HPEGLDeviceTag -SerialNumber CWERX2380BLC -Tags Country
 
    Remove tag 'Country' from the device CWERX2380BLC.
 
    .EXAMPLE
    Remove-HPEGLDeviceTag -SerialNumber CWERX2380BLC -Tags "Country Apps"
 
    Remove tags 'Country' and 'Apps' from the device CWERX2380BLC.
     
    .EXAMPLE
    Remove-HPEGLDeviceTag -SerialNumber CWERX2380BLC -All
 
    Remove all tags from the device CWERX2380BLC.
     
    .INPUTS
    System.Collections.ArrayList
        List of Device(s) from Get-HPEGLDevice.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device attempted to be untagged
        * Status - Status of the untagging attempt (Failed for http error return; Warning if untagging is incomplete; Complete if untagging is successful)
        * TagsRemoved - List of tags that have been successfully removed
        * TagsNotRemoved - List of tags that could not be removed
        * Details - More information about the status
        * Exception - Exception information of the error generated
     
    .LINK
    Add-HPEGLDeviceTag
    Get-HPEGLDevice -tags
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'SerialNumberAndTags')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "SerialNumberAndTags")]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "SerialNumberAndAll")]
        [ValidateNotNullOrEmpty()]
        [Alias ('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory, ParameterSetName = "SerialNumberAndTags")]
        [ValidateNotNullOrEmpty()]
        [String]$Tags,

        [Parameter (Mandatory = $false, ParameterSetName = "SerialNumberAndAll")]
        [Switch]$All,

        [Parameter (Mandatory = $False, ParameterSetName = "SerialNumberAndTags")]
        [Parameter (Mandatory = $False, ParameterSetName = "SerialNumberAndAll")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesATagsUri  
        $RemoveTagsDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        if ($Tags) {
            
            $splittedtags = $Tags.split(" ")

            # Check tag format, if format is not <tagname>=<value>, return error
            foreach ($splittedtag in $splittedtags) {

                if ($splittedtag -notmatch "^[A-Za-z0-9][^=]*$") {
                    write-warning "Tag '$splittedtag' format not supported! Expected format is <tagname>"
                    return  
                }
            }

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

            foreach ($tag in $splittedtags) {
        
                $TagsList += [PSCustomObject]@{
                    name = $tag
                }
            } 
        }
   

        # Test if device present using Serial number
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
                       
        }
        catch {
            Throw $_
        }
                        
            
        # Build object for the output
        $objStatus = [pscustomobject]@{
              
            SerialNumber   = $SerialNumber
            TagsRemoved    = $Null
            TagsNotRemoved = $Null
            Status         = $Null
            Details        = $Null
            Exception      = $Null
                      
        }      
       
       
       
        if (-not $device) {
            # Must return a message if device not found
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif (-not $device.tags) {
            # Must return a message if no tags found
            $objStatus.Status = "Failed"
            $objStatus.Details = "No tag exists on this device"
        }
        else {

            # Capturing Tags that already exist
            $ExistingTags = $device.tags

            $TagNotfoundList = @()
            $TagsToBeRemoved = @()
   
            foreach ($name in $TagsList.name) {
               
                "Tag to remove: {0} - Tag present: {1} " -f $name, ($ExistingTags | ? name -eq $name).name | write-verbose

                If (($ExistingTags | ? name -eq $name).name) {
                    $TagsToBeRemoved += $name

                }
                else {
                    $TagNotfoundList += $name

                }

            }
     
            $PartNumber = $device | % part_number
            $AppCategory = $device | % device_type


            # Build DeviceList object
       
            $DeviceList += [PSCustomObject]@{
                serial_number = $SerialNumber
                part_number   = $PartNumber 
                app_category  = $AppCategory
           
            }

            if ($All) {

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

                $TagsList += ($device.tags | select name)
          
            }

            # Build payload
            $payload = [PSCustomObject]@{
                devices     = $DeviceList 
                delete_tags = $TagsList
            } | ConvertTo-Json -Depth 5
          

            # Remove tags
            try {

                $Response = Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PUT' -body $payload -WhatIfBoolean $WhatIf

                if ($response.psobject.properties.name -eq "failed_devices" ) {
            
                    if ($TagsList.Count -eq 1) {

                        "{0}: Tag '{1}' cannot be found." -f $SerialNumber, $TagsList.name | Write-Verbose

                        $objStatus.Status = "Failed"

                        $objStatus.TagsNotRemoved = [System.Collections.ArrayList]@($TagsList.name)
                        $objStatus.Details = "Tag cannot be found" -f $TagsToBeAdded.count, $AlreadyExistList.count


                    }
                    else {

                        "Nb of tags to remove: {0}" -f $TagsToBeRemoved.count | write-verbose
                        "Nb of tags not found: {0}" -f $TagNotfoundList.count | write-verbose
                
                        if ( $TagsToBeRemoved -and $TagNotfoundList) {

                            # if ($TagsToBeRemoved.count -eq 1 -and $TagNotfoundList.count -eq 1) {
                            "{0}: Tag removed: '{1}' - Tag not removed as not present: '{2}'" -f $SerialNumber, (($TagsToBeRemoved) -join "' and '"), (($TagNotfoundList) -join "' and '") | Write-Verbose

                            $objStatus.Status = "Warning"
                            $objStatus.TagsRemoved = [System.Collections.ArrayList]@("{0}" -f (($TagsToBeRemoved) -join ", "))
                            $objStatus.TagsNotRemoved = [System.Collections.ArrayList]@("{0}" -f (($TagNotfoundList) -join ", "))
                            $objStatus.Details = "{0} tag(s) removed and {1} tag(s) not found" -f $TagsToBeRemoved.count, $TagNotfoundList.count
        

                            # }
                            # if ($TagsToBeRemoved.count -eq 1 -and $TagNotfoundList.count -gt 1) {
                            # "{0}: Tag removed: '{1}' - Tags not removed as not present: '{2}'" -f $SerialNumber, (($TagsToBeRemoved) -join "' and '"), (($TagNotfoundList) -join "' and '")| Write-Verbose

                            # }
                            # if ($TagsToBeRemoved.count -gt 1 -and $TagNotfoundList.count -gt 1) {
                            # "{0}: Tags removed: '{1}' - Tags not removed as not present: '{2}'" -f $SerialNumber, (($TagsToBeRemoved) -join "' and '"), (($TagNotfoundList) -join "' and '")| Write-Verbose

                            # }
                            # if ($TagsToBeRemoved.count -gt 1 -and $TagNotfoundList.count -eq 1) {
                            # "{0}: Tags removed: '{1}' - Tag not removed as not present: '{2}'" -f $SerialNumber, (($TagsToBeRemoved) -join "' and '"), (($TagNotfoundList) -join "' and '")| Write-Verbose

                            # }

                        }

                
                        if ( $TagsToBeRemoved -and -not $TagNotfoundList) {

                            if ($TagsToBeRemoved.count -eq 1) {
                                "{0}: Tag removed: '{1}'" -f $SerialNumber, $TagsToBeRemoved | Write-Verbose
                                
                                $objStatus.Status = "Complete"
                                $objStatus.TagsRemoved = [System.Collections.ArrayList]@($TagsToBeRemoved)
                                $objStatus.Details = "1 tag removed" 

                            }  
                            else {
                                "{0}: Tags removed: '{1}'" -f $SerialNumber, (($TagsToBeRemoved) -join "' and '") | Write-Verbose

                                $objStatus.Status = "Complete"
                                $objStatus.TagsRemoved = [System.Collections.ArrayList]@("{0}" -f (($TagsToBeRemoved) -join ", "))
                                $objStatus.Details = "{0} tags removed" -f $TagsToBeRemoved.count

                            }
                        }

                        if ( -not $TagsToBeRemoved -and $TagNotfoundList) {

                            if ($TagNotfoundList.count -eq 1) {
                                "{0}: Tag not removed as not present: '{1}'" -f $SerialNumber, $TagNotfoundList | Write-Verbose

                                $objStatus.Status = "Warning"
                                $objStatus.TagsNotRemoved = [System.Collections.ArrayList]@($TagNotfoundList)
                                $objStatus.Details = "Tag not found" 

                            }
                            else {
                                "{0}: Tags not removed as not present: '{1}'" -f $SerialNumber, (($TagNotfoundList) -join "' and '") | Write-Verbose

                                $objStatus.Status = "Warning"
                                $objStatus.TagsNotRemoved = [System.Collections.ArrayList]@("{0}" -f (($TagNotfoundList) -join ", "))
                                $objStatus.Details = "{0} tag(s) not found" -f $TagNotfoundList.count

                            }
                        }

                    }

                }
                elseif (($response | % response) -eq "success" ) {

                    if ($TagsList.Count -eq 1) {
                        "{0}: Tag '{1}' successfully removed." -f $SerialNumber , $TagsList.name | Write-Verbose

                        $objStatus.Status = "Complete"
                        $objStatus.TagsRemoved = [System.Collections.ArrayList]@($TagsList.name)

                        $objStatus.Details = "1 tag removed" 

                    }
                    else {
                        "{0}: Tags '{1}' successfully removed." -f $SerialNumber , (($TagsList | % name) -join "' and '") | Write-Verbose

                        $objStatus.Status = "Complete"
                        $objStatus.TagsRemoved = [System.Collections.ArrayList]@( "{0}" -f (($TagsList | % name) -join ", "))

                        $objStatus.Details = "{0} tags removed" -f $TagsList.count
                    }

                }
               
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device untagging error!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
        }

        [void] $RemoveTagsDevicesStatus.add($objStatus)

    } 
    
    end {

        if (-not $Whatif) {

            if ($RemoveTagsDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the untagging attempt!"
          
            }
        }

        Return $RemoveTagsDevicesStatus

    }
}


Function Get-HPEGLLocation {
    <#
    .SYNOPSIS
    Retrieve device locations.
 
    .DESCRIPTION
    This Cmdlet returns a collection of physical locations and service shipping addresses for all devices.
 
    .PARAMETER Name
    Optional parameter that can be used to display a location by name.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLLocation
 
    Return all physical locations.
 
    .EXAMPLE
    Get-HPEGLLocation -Name Geneva
 
    Return the Geneva location information.
   
    .LINK
    Get-HPEGLDevice
    New-HPEGLLocation
    Set-HPEGLLocation
    Remove-HPEGLLocation
    Set-HPEGLDeviceLocation
    Remove-HPEGLDeviceLocation
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$Name,            
 
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif

    ) 
    
    Begin {
    
        $UriAdd = $DevicesLocationUri
  
    }

    Process {

        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf 
        
        }
        catch {
   
            Throw $_
       
        }
       

        if ($Null -ne $Collection.data) {
              
            $CollectionList = $Collection.data 
                         
            if ($Name) {

                $CollectionList = $CollectionList | Where-Object { $_.name -eq $Name } 

                if (! $CollectionList) {
                    return
                }
                else {
                    "Selected collection data for {0}: {1}" -f $Name, $CollectionList | Write-Verbose

                    $UriAdd = $DevicesLocationUri + "/" + $CollectionList.id

                    "URI for the {0} location: {1}" -f $Name, $UriAdd | Write-Verbose

                    try {
                        [array]$Location = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf 
                
                    }
                    catch {
           
                        Throw $_
               
                    }

                    $ReturnData = Invoke-RepackageObjectWithType -RawObject $Location -ObjectName "Location.detailed"         
                

                }
            }
            else {

                $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Location"         
                $ReturnData = $ReturnData | Sort-Object name

            }     
      
            return $ReturnData 
  
        }
        else {

            return 
            
        }
    }
}


Function New-HPEGLLocation {
    <#
    .SYNOPSIS
    Creates a new physical location and service shipping address for devices.
 
    .DESCRIPTION
    This Cmdlet can be used to create a new physical location and its street address that can then be later assigned to
    a device using Set-HPEGLDeviceLocation.
 
    The Street Address is the physical location of the devices assigned to the location.
    This address will be used as the default shipping and receiving address for devices assigned to the location.
 
    A differents shipping and receiving address can be set. If set, this shipping and receiving address will be used when support
    cases are generated for devices assigned to the location.
        
    .PARAMETER Name
    Name of the physical location.
 
    .PARAMETER Description
    Optional parameter to set a description of the location.
 
    .PARAMETER Country
    The country of the street address of the location.
 
    .PARAMETER Street
    The postal street address of the location.
 
    .PARAMETER Street2
    The postal street address 2 of the location (optional).
 
    .PARAMETER City
    The city of the street address of the location.
     
    .PARAMETER State
    The state of the street address of the location.
 
    .PARAMETER PostalCode
    The postal code of the street address of the location.
 
    .PARAMETER ShippingReceivingCountry
    (optional) The country of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingStreet
    (optional) The street of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingStreet2
    (optional) The street 2 of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingCity
    (optional) The city of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingState
    (optional) The state of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingPostalCode
    (optional) The postal code of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER PrimaryContactEmail
    Optional parameter to set the primary contact email address of the location.
 
    .PARAMETER PrimaryContactPhone
    Optional parameter to set the primary contact phone number of the location.
 
    .PARAMETER ShippingReceivingContactEmail
    Optional parameter to set the shipping and receiving contact email address of the location.
 
    .PARAMETER ShippingReceivingContactPhone
    Optional parameter to set the shipping and receiving contact phone number of the location.
 
    .PARAMETER SecurityContactEmail
    Optional parameter to set the security contact email address of the location.
 
    .PARAMETER SecurityContactPhone
    Optional parameter to set the security contact phone number of the location.
 
    .PARAMETER OperationsContactEmail
    Optional parameter to set the operations contact email address of the location.
 
    .PARAMETER OperationsContactPhone
    Optional parameter to set the operations contact phone number of the location.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
     
    .EXAMPLE
    New-HPEGLLocation -Name Boston -Description "My Boston location" -Country US -Street "321 Summer Street" -Street2 "5th floor" -City Boston -State MA -PostalCode 02210 -PrimaryContactEmail Lisa@email.com -PrimaryContactPhone "+1234567890" -ShippingReceivingContactEmail Lisa@email.com -ShippingReceivingContactPhone "+1234567890"
 
    Create a new physical location with a shipping and receiving contact information as the same as the primary contact one and with the service shipping address defined as the same as the location address.
     
    .EXAMPLE
    New-HPEGLLocation -Name Boston -Description "My Boston location" -Country US -Street "321 Summer Street" -Street2 "5th floor" -City Boston -State MA -PostalCode 02210 -PrimaryContactEmail Lisa@email.com -ShippingReceivingContactEmail Albert@email.com -ShippingReceivingContactPhone 4545454 -ShippingReceivingCountry France -ShippingReceivingStreet "5th Avenue" -ShippingReceivingCity Mougins -ShippingReceivingState NA -ShippingReceivingPostalCode 06250
 
    Create a new physical location with a different service shipping and receiving address and contact information.
     
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - name of the location object attempted to be created
        * Status - status of the creation attempt (Failed for http error return; Complete if the creation is successful; Warning if no action is needed)
        * Details - more information about the status
        * Exception - exception information of the error generated
     
 
    .LINK
    Get-HPEGLLocation
    Set-HPEGLLocation
    Remove-HPEGLLocation
    Set-HPEGLDeviceLocation
    Remove-HPEGLDeviceLocation
    [${Global:HPEGreenLakeSession.apiCredentials}]
     
   #>


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

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$Country,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$Street,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$Street2,        

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$State,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$PostalCode,
        
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingCountry, 

        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingStreet, 
        
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingStreet2, 
        
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingCity, 
        
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingState,    

        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingPostalCode,    

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$PrimaryContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$PrimaryContactPhone,  

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingContactPhone,  

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$SecurityContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$SecurityContactPhone,      
        
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$OperationsContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [ValidateNotNullOrEmpty()]
        [String]$OperationsContactPhone,    

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceiving")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesLocationUri  
        $NewLocationStatus = [System.Collections.ArrayList]::new()

               
    }

    Process {         


        # Build object for the output
        $objStatus = [pscustomobject]@{
            Name      = $Name
            Status    = $Null
            Details   = $Null
            Exception = $Null
                          
        }

        # Check if location already exists
        try {
            $Locationfound = Get-HPEGLLocation -Name $Name
                
        }
        catch {
            Throw $_                
        }


        if ( $Locationfound) {
            "'{0}' Location name already created, use another name!" -f $Name | Write-Verbose
            $objStatus.Status = "Warning"
            $objStatus.Details = "Location name already created!"
            
        }
        else {

            # Get contact names from emails
            $PrimaryContactInfo = Get-HPEGLUser -Email $PrimaryContactEmail

            if ( $PrimaryContactInfo) {
                $PrimaryContactName = $PrimaryContactInfo.contact.first_name + " " + $PrimaryContactInfo.contact.last_name
            }
            else {
                Throw "$PrimaryContactEmail contact email cannot be found on the HPE GreenLake platform!"
            }

            if ($ShippingReceivingContactEmail) {

                $ShippingReceivingContactInfo = Get-HPEGLUser -Email $ShippingReceivingContactEmail

                if ( $ShippingReceivingContactInfo) {
                    $ShippingReceivingContactName = $ShippingReceivingContactInfo.contact.first_name + " " + $ShippingReceivingContactInfo.contact.last_name

                }
                else {
                    Throw "$ShippingReceivingContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }
            
            if ($SecurityContactEmail) {

                $SecurityContactInfo = Get-HPEGLUser -Email $SecurityContactEmail

                if ( $SecurityContactInfo) {
                    $SecurityContactName = $SecurityContactInfo.contact.first_name + " " + $SecurityContactInfo.contact.last_name

                }
                else {
                    Throw "$SecurityContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }
            
            if ($OperationsContactEmail) {

                $OperationsContactInfo = Get-HPEGLUser -Email $OperationsContactEmail

                if ( $OperationsContactInfo) {
                    $OperationsContactName = $OperationsContactInfo.contact.first_name + " " + $OperationsContactInfo.contact.last_name

                }
                else {
                    Throw "$OperationsContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }


            # Defining location street address or location street address with shipping and receiving address

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

            $StreetAddress = [PSCustomObject]@{
                country         = $Country
                street_address  = $Street
                street_address2 = $Street2
                city            = $City
                state           = $State
                postal_code     = $PostalCode
                type            = "street"

            }

            $LocationAddressList += $StreetAddress 

            if ($ShippingReceivingCountry) {

                $ShippingReceivingAddress = [PSCustomObject]@{
                    country         = $ShippingReceivingCountry
                    street_address  = $ShippingReceivingStreet
                    street_address2 = $ShippingReceivingStreet2
                    city            = $ShippingReceivingCity
                    state           = $ShippingReceivingState
                    postal_code     = $ShippingReceivingPostalCode
                    type            = "shipping_receiving"
                }
                    
                $LocationAddressList += $ShippingReceivingAddress

            }
           
           
            # Defining contacts

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


            $PrimaryContact = [PSCustomObject]@{ 
                type         = "primary"
                name         = $PrimaryContactName
                phone_number = $PrimaryContactPhone
                email        = $PrimaryContactEmail
            }              
            
            $ContactsList += $PrimaryContact 


            if ($ShippingReceivingContactEmail) {
    
                $ShippingReceivingContact = [PSCustomObject]@{ 
                    type         = "shipping_receiving"
                    name         = $ShippingReceivingContactName
                    phone_number = $ShippingReceivingContactPhone
                    email        = $ShippingReceivingContactEmail
                }

                $ContactsList += $ShippingReceivingContact

            }
            
            if ($SecurityContactEmail) {

                $SecurityContact = [PSCustomObject]@{ 
                    type         = "security"
                    name         = $SecurityContactName
                    phone_number = $SecurityContactPhone
                    email        = $SecurityContactEmail
                }

                $ContactsList += $SecurityContact
            }
            
            if ($OperationsContactEmail) {

                $OperationsContact = [PSCustomObject]@{ 
                    type         = "operations"
                    name         = $OperationsContactName
                    phone_number = $OperationsContactPhone
                    email        = $OperationsContactEmail
                }

                $ContactsList += $OperationsContact
            }

            # Building payload

            $Payload = [PSCustomObject]@{
                name        = $Name
                description = $Description
                type        = "building"
                addresses   = $LocationAddressList
                contacts    = $ContactsList

            } | ConvertTo-Json -Depth 5
   
                   
            # Create Location
            try {

                $Response = Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $Payload -WhatIfBoolean $WhatIf 
                
                if (-not $Whatif) {

                    "'{0}' Location successfully created" -f $Name | Write-Verbose
                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Location successfully created"
        
                }

            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Location cannot be created!"
                    $objStatus.Exception = $_.Exception.message 
                }

            }

        }
        

        [void] $NewLocationStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($NewLocationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more location failed the creation attempt!"
          
            }
        }

        Return $NewLocationStatus

    }
}


Function Set-HPEGLLocation {
    <#
    .SYNOPSIS
    Modify an existing physical location.
 
    .DESCRIPTION
    This Cmdlet can be used to modify a physical location information such as its addresses, contacts and details information.
 
    The Street Address is the physical location of the devices assigned to the location.
    This address will be used as the default shipping and receiving address for devices assigned to the location.
 
    A differents shipping and receiving address can be set. If set, this shipping and receiving address will be used when support
    cases are generated for devices assigned to the location.
        
    .PARAMETER Name
    Name of the physical location.
 
    .PARAMETER NewName
    Optional parameter to set a new name to the location.
 
    .PARAMETER Description
    Optional parameter to set a description of the location.
 
    .PARAMETER Country
    Optional parameter to set the country of the location.
 
    .PARAMETER Street
    Optional parameter to set the street address of the location.
 
    .PARAMETER Street2
    Optional parameter to set the street address 2 of the location.
 
    .PARAMETER City
    Optional parameter to set the city of the location.
     
    .PARAMETER State
    Optional parameter to set the state of the location.
 
    .PARAMETER PostalCode
    Optional parameter to set the postal code of the location.
 
    .PARAMETER ShippingReceivingCountry
    Optional parameter to set the country of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingStreet
    Optional parameter to set the street of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingStreet2
    Optional parameter to set the street 2 of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingCity
    Optional parameter to set the city of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingState
    Optional parameter to set the state of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER ShippingReceivingPostalCode
    Optional parameter to set the postal code of the shipping and receiving address of the location.
    This parameter can be used if the shipping and receiving address is different than the street address.
 
    .PARAMETER RemoveShippingReceivingAddress
    Optional parameter to delete the shipping and receiving address of the location.
 
    .PARAMETER PrimaryContactEmail
    Optional parameter to set the primary contact email address of the location.
 
    .PARAMETER PrimaryContactPhone
    Optional parameter to set the primary contact phone number of the location.
 
    .PARAMETER ShippingReceivingContactEmail
    Optional parameter to set the shipping and receiving contact email address of the location.
 
    .PARAMETER ShippingReceivingContactPhone
    Optional parameter to set the shipping and receiving contact phone number of the location.
 
    .PARAMETER RemoveShippingReceivingContact
    Optional parameter to delete the shipping and receiving contact of the location.
 
    .PARAMETER SecurityContactEmail
    Optional parameter to set the security contact email address of the location.
 
    .PARAMETER SecurityContactPhone
    Optional parameter to set the security contact phone number of the location.
 
    .PARAMETER RemoveSecurityContact
    Optional parameter to delete the security contact of the location.
 
    .PARAMETER OperationsContactEmail
    Optional parameter to set the operations contact email address of the location.
 
    .PARAMETER OperationsContactPhone
    Optional parameter to set the operations contact phone number of the location.
 
    .PARAMETER RemoveOperationsContact
    Optional parameter to delete the operations contact of the location.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
     
    .EXAMPLE
    Set-HPEGLLocation -Name "Mougins" -NewName "HPE Mougins" -Description "Location in Central Europe" -Whatif
 
    Rename the "Mougins" location to "HPE Mougins" and change its description.
 
    .EXAMPLE
    Set-HPEGLLocation -Name Houston -PostalCode 77389 -State TX -Street "1701 East Mossy Oaks Road"
 
    Modify the street address of the "Houston" location with a new postal code, a new state and street address.
 
    .EXAMPLE
    Set-HPEGLLocation -Name Houston -PrimaryContactEmail TheBoss@email.com -PrimaryContactPhone "+123456789" -Whatif
 
    Modify the "Houston" location with a primary email contact and phone number.
 
    .EXAMPLE
    Set-HPEGLLocation -Name Mougins -ShippingReceivingCountry France -ShippingReceivingStreet "790 Avenue du Docteur Donat" -ShippingReceivingStreet2 "Marco Polo - Batiment B" -ShippingReceivingCity Mougins -ShippingReceivingPostalCode 06254 -ShippingReceivingState " "
 
    Add a shipping and receiving address to the "Mougins" location or modify the address information if a shipping and receiving address is present.
 
    .EXAMPLE
    Set-HPEGLLocation -Name Boston -RemoveShippingReceivingAddress
 
    Remove the existing shipping and receiving address for the "Boston" location.
 
    .EXAMPLE
    Set-HPEGLLocation -Name Mougins -ShippingReceivingContactEmail TheTech@email.com -ShippingReceivingContactPhone "+123456789"
 
    Modify the existing shipping and receiving contact information for the "Mougins" location or add a new shipping and receiving contact if not present.
 
    .EXAMPLE
    Set-HPEGLLocation -Name Barcelona -RemoveShippingReceivingContact
 
    Remove the existing shipping and receiving contact for the "Barcelona" location.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - name of the location object attempted to be modified
        * Status - status of the modification attempt (Failed for http error return; Complete if the modification is successful; Warning if no action is needed)
        * Details - more information about the status
        * Exception - exception information of the error generated
     
 
    .LINK
    Get-HPEGLLocation
    New-HPEGLLocation
    Remove-HPEGLLocation
    Set-HPEGLDeviceLocation
    Remove-HPEGLDeviceLocation
    [${Global:HPEGreenLakeSession.apiCredentials}]
     
   #>


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

        [Parameter (Mandatory, ParameterSetName = "Details")]
        [Parameter (Mandatory = $False, ParameterSetName = "OperationsContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "SecurityContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveShippingReceivingAddress")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveOperationsContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveSecurityContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveShippingReceivingContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = "Details")]
        [ValidateNotNullOrEmpty()]
        [String]$NewName,

        [Parameter (Mandatory = $False, ParameterSetName = "Details")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$Country,

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$Street,

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$Street2,        

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$State,

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$PostalCode,
        
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingCountry, 

        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingStreet, 
        
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingStreet2, 
        
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingCity, 
        
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingState,    

        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingPostalCode,    

        [Parameter (Mandatory = $False, ParameterSetName = "RemoveShippingReceivingAddress")]
        [ValidateNotNullOrEmpty()]
        [Switch]$RemoveShippingReceivingAddress,    

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryContact")]
        [ValidateNotNullOrEmpty()]
        [String]$PrimaryContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryContact")]
        [ValidateNotNullOrEmpty()]
        [String]$PrimaryContactPhone,  

        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingContact")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingContact")]
        [ValidateNotNullOrEmpty()]
        [String]$ShippingReceivingContactPhone, 
        
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveShippingReceivingContact")]
        [ValidateNotNullOrEmpty()]
        [Switch]$RemoveShippingReceivingContact,    

        [Parameter (Mandatory = $False, ParameterSetName = "SecurityContact")]
        [ValidateNotNullOrEmpty()]
        [String]$SecurityContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "SecurityContact")]
        [ValidateNotNullOrEmpty()]
        [String]$SecurityContactPhone,  
        
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveSecurityContact")]
        [ValidateNotNullOrEmpty()]
        [Switch]$RemoveSecurityContact,    
        
        [Parameter (Mandatory = $False, ParameterSetName = "OperationsContact")]
        [ValidateNotNullOrEmpty()]
        [String]$OperationsContactEmail,   

        [Parameter (Mandatory = $False, ParameterSetName = "OperationsContact")]
        [ValidateNotNullOrEmpty()]
        [String]$OperationsContactPhone,  
        
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveOperationsContact")]
        [ValidateNotNullOrEmpty()]
        [Switch]$RemoveOperationsContact,  

        [Parameter (Mandatory = $False, ParameterSetName = "Details")]
        [Parameter (Mandatory = $False, ParameterSetName = "OperationsContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "SecurityContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "ShippingReceivingAddress")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveShippingReceivingAddress")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveOperationsContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveSecurityContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "RemoveShippingReceivingContact")]
        [Parameter (Mandatory = $False, ParameterSetName = "PrimaryAddress")]
        [Switch]$Whatif
    ) 

    Begin {

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

               
    }

    Process {         


        # Build object for the output
        $objStatus = [pscustomobject]@{
            Name      = $Name
            Status    = $Null
            Details   = $Null
            Exception = $Null
                          
        }

        # Check if location exists
        try {
            
            $Locationfound = Get-HPEGLLocation -Name $Name

            $UriAdd = $DevicesLocationUri + "/" + $Locationfound.id


                
        }
        catch {
            Throw $_                
        }


        if (-not $Locationfound) {
            "'{0}' Location name cannot be found!" -f $Name | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Location name cannot be found on the HPE GreenLake platform!"
            
        }
        else {

            $Name = $Locationfound.name
            $Description = $Locationfound.description


            if ($PrimaryContactEmail) {

                $PrimaryContactInfo = Get-HPEGLUser -Email $PrimaryContactEmail
                
                # Get contact names from emails
                if ( $PrimaryContactInfo) {
                    $PrimaryContactName = $PrimaryContactInfo.contact.first_name + " " + $PrimaryContactInfo.contact.last_name
                }
                else {
                    Throw "$PrimaryContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }          

            if ($ShippingReceivingContactEmail) {

                $ShippingReceivingContactInfo = Get-HPEGLUser -Email $ShippingReceivingContactEmail

                if ( $ShippingReceivingContactInfo) {
                    $ShippingReceivingContactName = $ShippingReceivingContactInfo.contact.first_name + " " + $ShippingReceivingContactInfo.contact.last_name

                }
                else {
                    Throw "$ShippingReceivingContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }
            
            if ($SecurityContactEmail) {

                $SecurityContactInfo = Get-HPEGLUser -Email $SecurityContactEmail

                if ( $SecurityContactInfo) {
                    $SecurityContactName = $SecurityContactInfo.contact.first_name + " " + $SecurityContactInfo.contact.last_name

                }
                else {
                    Throw "$SecurityContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }
            
            if ($OperationsContactEmail) {

                $OperationsContactInfo = Get-HPEGLUser -Email $OperationsContactEmail

                if ( $OperationsContactInfo) {
                    $OperationsContactName = $OperationsContactInfo.contact.first_name + " " + $OperationsContactInfo.contact.last_name

                }
                else {
                    Throw "$OperationsContactEmail contact email cannot be found on the HPE GreenLake platform!"
                }
            }

            # Modifying details (Name or Description)

            if ($NewName -or $Description) {

                if (! $Description) {
                    $Description = $Locationfound.description
                }

                if ($NewName) {
                    $Name = $NewName
                }
                else {
                    $Name = $Locationfound.name
                }

                # Building payload
           
                $Payload = [PSCustomObject]@{
                    name        = $Name
                    description = $Description
                    type        = "building"
         
                } | ConvertTo-Json -Depth 5
            }


            # Modifying street address

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

            if ($Country -or $Street -or $Street2 -or $City -or $State -or $PostalCode) {
            
                if (! $Country) {
                    $Country = ($Locationfound.addresses | ? type -eq Street ).country
                }
            
                if (! $Street) {
                    $Street = ($Locationfound.addresses | ? type -eq Street ).street_address
                }

                if (! $Street2) {
                    $Street2 = ($Locationfound.addresses | ? type -eq Street ).street_address2
                }

                if (! $City) {
                    $City = ($Locationfound.addresses | ? type -eq Street ).city
                }

                if (! $State) {
                    $State = ($Locationfound.addresses | ? type -eq Street ).state
                }

                if (! $PostalCode) {
                    $PostalCode = ($Locationfound.addresses | ? type -eq Street ).postal_code
                }

                $PrimaryAddressId = ($Locationfound.addresses | ? type -eq Street).id


                $StreetAddress = [PSCustomObject]@{
                    country         = $Country
                    street_address  = $Street
                    street_address2 = $Street2
                    city            = $City
                    state           = $State
                    postal_code     = $PostalCode
                    type            = "street"
                    id              = $PrimaryAddressId
                }

                $LocationAddressList += $StreetAddress 
            }

            # Modifying shipping/receiving address

            if ($ShippingReceivingCountry -or $ShippingReceivingStreet -or $ShippingReceivingStreet2 -or $ShippingReceivingCity -or $ShippingReceivingState -or $ShippingReceivingPostalCode) {

                if (! $ShippingReceivingCountry) {
                    $ShippingReceivingCountry = ($Locationfound.addresses | ? type -eq shipping_receiving ).country
                }
                
                if (! $ShippingReceivingStreet) {
                    $ShippingReceivingStreet = ($Locationfound.addresses | ? type -eq shipping_receiving ).street_address
                }
    
                if (! $ShippingReceivingStreet2) {
                    $ShippingReceivingStreet2 = ($Locationfound.addresses | ? type -eq shipping_receiving ).street_address2
                }
    
                if (! $ShippingReceivingCity) {
                    $ShippingReceivingCity = ($Locationfound.addresses | ? type -eq shipping_receiving ).city
                }
    
                if (! $ShippingReceivingState) {
                    $ShippingReceivingState = ($Locationfound.addresses | ? type -eq shipping_receiving ).state
                }
    
                if (! $ShippingReceivingPostalCode) {
                    $ShippingReceivingPostalCode = ($Locationfound.addresses | ? type -eq shipping_receiving ).postal_code
                }

                $ShippingAddressId = ($Locationfound.addresses | ? type -eq shipping_receiving).id


                $ShippingReceivingAddress = [PSCustomObject]@{
                    country         = $ShippingReceivingCountry
                    street_address  = $ShippingReceivingStreet
                    street_address2 = $ShippingReceivingStreet2
                    city            = $ShippingReceivingCity
                    state           = $ShippingReceivingState
                    postal_code     = $ShippingReceivingPostalCode
                    type            = "shipping_receiving"
                    id              = $ShippingAddressId 

                }
                    
                $LocationAddressList += $ShippingReceivingAddress
            }
            
            if ($RemoveShippingReceivingAddress) {
    
                $ShippingAddressId = ($Locationfound.addresses | ? type -eq shipping_receiving).id
    
                if (! $ShippingAddressId) {
 
                    "There is no Shipping and Receiving address for the '{0}' location!" -f $Name | Write-Verbose
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "There is no Shipping and Receiving address for this location on the HPE GreenLake platform!"
                    [void] $UpdateLocationStatus.add($objStatus)
                    Return

                }
                else {

                    $StreetAddressId = ($Locationfound.addresses | ? type -eq street).id

                    $Country = ($Locationfound.addresses | ? type -eq Street ).country
                
                    $Street = ($Locationfound.addresses | ? type -eq Street ).street_address
    
                    $Street2 = ($Locationfound.addresses | ? type -eq Street ).street_address2
    
                    $City = ($Locationfound.addresses | ? type -eq Street ).city
    
                    $State = ($Locationfound.addresses | ? type -eq Street ).state
    
                    $PostalCode = ($Locationfound.addresses | ? type -eq Street ).postal_code
    
                    $StreetAddress = [PSCustomObject]@{
                        country         = $Country
                        street_address  = $Street
                        street_address2 = $Street2
                        city            = $City
                        state           = $State
                        postal_code     = $PostalCode
                        type            = "street"
                        id              = $StreetAddressId 
    
                    }

                    $LocationAddressList += $StreetAddress      
                    
                    $ShippingAddressInfo = [PSCustomObject]@{ 
                        type = "shipping_receiving"
                        id   = $ShippingAddressId
                    }         
                    
                    $LocationAddressList += $ShippingAddressInfo      

                }
            }

            

            # Modifying primary contact

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

            if ($PrimaryContactEmail -or $PrimaryContactPhone) {
        
                if (! $PrimaryContactName) {
                    $PrimaryContactName = ($Locationfound.contacts | ? type -eq primary).name
                }

                if (! $PrimaryContactPhone) {
                    $PrimaryContactPhone = ($Locationfound.contacts | ? type -eq primary).phone_number
                }

                if (! $PrimaryContactEmail) {
                    $PrimaryContactEmail = ($Locationfound.contacts | ? type -eq primary).email
                }

                $PrimaryContactId = ($Locationfound.contacts | ? type -eq primary).id
               
                $ContactInfo = [PSCustomObject]@{ 
                    type = "primary"
                    id   = $PrimaryContactId
                }         
                
                $ContactsList += $ContactInfo             
                
                $PrimaryContact = [PSCustomObject]@{ 
                    type         = "primary"
                    name         = $PrimaryContactName
                    phone_number = $PrimaryContactPhone
                    email        = $PrimaryContactEmail
                    location_id  = $Locationfound.id
                }              
            
                $ContactsList += $PrimaryContact 

            }

            # Modifying shipping/receiving contact

            if ( $ShippingReceivingContactEmail -or $ShippingReceivingContactPhone) {

                if (! $ShippingReceivingContactName) {
                    $ShippingReceivingContactName = ($Locationfound.contacts | ? type -eq shipping_receiving).name
                }

                if (! $ShippingReceivingContactPhone) {
                    $ShippingReceivingContactPhone = ($Locationfound.contacts | ? type -eq shipping_receiving).phone_number
                }

                if (! $ShippingReceivingContactEmail) {
                    $ShippingReceivingContactEmail = ($Locationfound.contacts | ? type -eq shipping_receiving).email
                }

                # If contact not existing
                if (! ($Locationfound.contacts | ? type -eq shipping_receiving)) {

                    $ShippingReceivingContact = [PSCustomObject]@{ 
                        type         = "shipping_receiving"
                        name         = $ShippingReceivingContactName
                        phone_number = $ShippingReceivingContactPhone
                        email        = $ShippingReceivingContactEmail
                        location_id  = $Locationfound.id
                    }

                    $ContactsList += $ShippingReceivingContact

                }
                # If contact already created
                else {

                    $ShippingReceivingContactId = ($Locationfound.contacts | ? type -eq shipping_receiving).id
    
                    $ContactInfo = [PSCustomObject]@{ 
                        type = "shipping_receiving"
                        id   = $ShippingReceivingContactId
                    }         
                    
                    $ContactsList += $ContactInfo  

                    $ShippingReceivingContact = [PSCustomObject]@{ 
                        type         = "shipping_receiving"
                        name         = $ShippingReceivingContactName
                        phone_number = $ShippingReceivingContactPhone
                        email        = $ShippingReceivingContactEmail
                        location_id  = $Locationfound.id
                    }

                    $ContactsList += $ShippingReceivingContact
                }
            }

            if ($RemoveShippingReceivingContact) {
                
                $ShippingReceivingContactId = ($Locationfound.contacts | ? type -eq shipping_receiving).id

                if ( ! $ShippingReceivingContactId) {
                    
                    "There is no Shipping and Receiving contact for the '{0}' location!" -f $Name | Write-Verbose
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "There is no Shipping and Receiving contact for this location on the HPE GreenLake platform!"
                    [void] $UpdateLocationStatus.add($objStatus)
                    Return

                }
                else {
    
                    $ContactInfo = [PSCustomObject]@{ 
                        type = "shipping_receiving"
                        id   = $ShippingReceivingContactId
                    }         
                
                    $ContactsList += $ContactInfo  
                }
            }
            
            if ( $SecurityContactEmail -or $SecurityContactPhone) {

                if (! $SecurityContactName) {
                    $SecurityContactName = ($Locationfound.contacts | ? type -eq security).name
                }

                if (! $SecurityContactPhone) {
                    $SecurityContactPhone = ($Locationfound.contacts | ? type -eq security).phone_number
                }

                if (! $SecurityContactEmail) {
                    $SecurityContactEmail = ($Locationfound.contacts | ? type -eq security).email
                }

                # If contact not existing

                if (! ($Locationfound.contacts | ? type -eq security)) {

                    $SecurityContact = [PSCustomObject]@{ 
                        type         = "security"
                        name         = $SecurityContactName
                        phone_number = $SecurityContactPhone
                        email        = $SecurityContactEmail
                        location_id  = $Locationfound.id

                    }

                    $ContactsList += $SecurityContact

                }
                # If contact already created
                else {

                    $SecurityContactId = ($Locationfound.contacts | ? type -eq security).id

                    $ContactInfo = [PSCustomObject]@{ 
                        type = "security"
                        id   = $SecurityContactId
                    }         
                
                    $ContactsList += $ContactInfo  

                    $SecurityContact = [PSCustomObject]@{ 
                        type         = "security"
                        name         = $SecurityContactName
                        phone_number = $SecurityContactPhone
                        email        = $SecurityContactEmail
                        location_id  = $Locationfound.id
                    }

                    $ContactsList += $ShippingReceivingContact
                }
            }

            if ($RemoveSecurityContact) {
                
                $SecurityContactId = ($Locationfound.contacts | ? type -eq security).id

                if ( ! $SecurityContactId) {
                    
                    "There is no security contact for the '{0}' location!" -f $Name | Write-Verbose
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "There is no security contact for this location on the HPE GreenLake platform!"
                    [void] $UpdateLocationStatus.add($objStatus)
                    Return

                }
                else {

                    $ContactInfo = [PSCustomObject]@{ 
                        type = "security"
                        id   = $SecurityContactId
                    }         
            
                    $ContactsList += $ContactInfo  
                }
            }
            
            if ($OperationsContactEmail -or $OperationsContactPhone) {

                if (! $OperationsContactName) {
                    $OperationsContactName = ($Locationfound.contacts | ? type -eq operations).name
                }

                if (! $OperationsContactPhone) {
                    $OperationsContactPhone = ($Locationfound.contacts | ? type -eq operations).phone_number
                }

                if (! $OperationsContactEmail) {
                    $OperationsContactEmail = ($Locationfound.contacts | ? type -eq operations).email
                }

                # If contact not existing

                if (! ($Locationfound.contacts | ? type -eq operations)) {

                    $OperationsContact = [PSCustomObject]@{ 
                        type         = "operations"
                        name         = $OperationsContactName
                        phone_number = $OperationsContactPhone
                        email        = $OperationsContactEmail
                        location_id  = $Locationfound.id
                    }

                    $ContactsList += $OperationsContact

                }                  
                # If contact already created
                else {

                    $OperationsContactId = ($Locationfound.contacts | ? type -eq operations).id

                    $ContactInfo = [PSCustomObject]@{ 
                        type = "operations"
                        id   = $OperationsContactId
                    }         
            
                    $ContactsList += $ContactInfo  

                    $OperationsContact = [PSCustomObject]@{ 
                        type         = "operations"
                        name         = $OperationsContactName
                        phone_number = $OperationsContactPhone
                        email        = $OperationsContactEmail
                        location_id  = $Locationfound.id
                    }

                    $ContactsList += $OperationsContact
                }
            }

            if ($RemoveOperationsContact) {

                $OperationsContactId = ($Locationfound.contacts | ? type -eq operations).id

                if ( ! $OperationsContactId) {
                    
                    "There is no operations contact for the '{0}' location!" -f $Name | Write-Verbose
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "There is no operations contact for this location on the HPE GreenLake platform!"
                    [void] $UpdateLocationStatus.add($objStatus)
                    Return
                }
                else {

                    $ContactInfo = [PSCustomObject]@{ 
                        type = "operations"
                        id   = $OperationsContactId
                    }         
        
                    $ContactsList += $ContactInfo  
                }
            }

            # Building payload

            if ( $LocationAddressList) {
                $Payload = [PSCustomObject]@{
                    name        = $Name
                    description = $Description
                    type        = "building"
                    addresses   = $LocationAddressList
    
                } | ConvertTo-Json -Depth 5
            }

            if ( $ContactsList) {

                $Payload = [PSCustomObject]@{
                    name        = $Name
                    description = $Description
                    type        = "building"
                    contacts    = $ContactsList

                } | ConvertTo-Json -Depth 5
            }

            
            if ( $LocationAddressList -and $ContactsList) {
                $Payload = [PSCustomObject]@{
                    name        = $Name
                    description = $Description
                    type        = "building"
                    addresses   = $LocationAddressList
                    contacts    = $ContactsList

    
                } | ConvertTo-Json -Depth 5
            }
                   
            # Modify Location
            try {

                $Response = Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PUT' -body $Payload -WhatIfBoolean $WhatIf 
                
                if (-not $Whatif) {

                    "'{0}' Location successfully updated" -f $Name | Write-Verbose
                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Location successfully modified"
        
                }

            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Location cannot be modified!"
                    $objStatus.Exception = $_.Exception.message 
                }

            }

        }
        

        [void] $UpdateLocationStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($UpdateLocationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more location failed the modification attempt!"
          
            }
        }

        Return $UpdateLocationStatus

    }
}


Function Remove-HPEGLLocation {
    <#
    .SYNOPSIS
    Delete a physical location and service shipping address.
 
    .DESCRIPTION
    This Cmdlet can be used to delete a physical location and its addresses and contacts.
 
    Any assigned devices will be released.
    Any associated addresses will no longer be accessible for automated support case creation.
    All associated contacts will no longer be assigned to any devices assigned to this location.
        
    .PARAMETER Name
    Name of the physical location.
 
    .PARAMETER Force
    Switch parameter that can be used to perform the deletion without prompting the user for confirmation.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
     
    .EXAMPLE
    Remove-HPEGLLocation -Name Boston
     
    Delete the Boston physical location and any associated service shipping addresses and contacts. Any devices assigned to the Boston location are released.
 
    .EXAMPLE
    Get-HPEGLLocation -Name Mougins | Remove-HPEGLLocation -Force
 
    Delete the Mougins physical location and any associated service shipping addresses and contacts without prompting for confirmation.
 
    .INPUTS
    System.Collections.ArrayList
        List of location(s) from Get-HPEGLDeviceLocation.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - name of the location object attempted to be deleted
        * Status - status of the deletion attempt (Failed for http error return; Complete if the deletion is successful; Warning if no action is needed)
        * Details - more information about the status
        * Exception - exception information of the error generated
     
 
    .LINK
    Get-HPEGLLocation
    New-HPEGLLocation
    Set-HPEGLLocation
    Set-HPEGLDeviceLocation
    Remove-HPEGLDeviceLocation
    [${Global:HPEGreenLakeSession.apiCredentials}]
     
   #>


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

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name, 

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Force,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {


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

    Process {         


        if ($Force) {
            $decision = 0
        }
        else {
            $title = "Any assigned devices will be released. Any associated addresses will no longer be accessible for automated support case creation. All associated contacts will no longer be assigned to any devices assigned to this location." 
            $question = 'Are you sure you want to proceed?'
            $choices = '&Yes', '&No'
            $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
        }
           
        if ($decision -eq 0) {

            # Build object for the output
            $objStatus = [pscustomobject]@{
                Name      = $Name
                Status    = $Null
                Details   = $Null
                Exception = $Null
                          
            }

            # Check if location exists
            try {
                $Locationfound = Get-HPEGLLocation -Name $Name

                $UriAdd = $DevicesLocationUri + "/" + $Locationfound.id
                
            }
            catch {
                Throw $_                
            }


            if ( -not $Locationfound) {
                "'{0}' Location name cannot be found!" -f $Name | Write-Verbose
                $objStatus.Status = "Failed"
                $objStatus.Details = "Location name cannot be found on the HPE GreenLake platform!"
            
            }
            else {           
                   
                # Delete Location
                try {

                    $Response = Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'DELETE' -body $Payload -WhatIfBoolean $WhatIf 
                
                    if (-not $Whatif) {

                        "'{0}' Location successfully deleted" -f $Name | Write-Verbose
                        $objStatus.Status = "Complete"
                        $objStatus.Details = "Location successfully deleted"
        
                    }

                }
                catch {

                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Location cannot be deleted!"
                        $objStatus.Exception = $_.Exception.message 
                    }

                }

            }
        

            [void] $RemoveLocationStatus.add($objStatus)

        }

        else {
                
            'Operation cancelled by user!' | Write-Verbose

            $objStatus.Status = "Failed"
            $objStatus.Details = "Operation cancelled by the user!"
    
        }
    

    }

    end {

        if (-not $Whatif) {

            if ($RemoveLocationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more location failed the deletion attempt!"
          
            }
        }

        Return $RemoveLocationStatus

    }
}


Function Set-HPEGLDeviceLocation {
    <#
    .SYNOPSIS
    Assign device(s) to a physical location.
 
    .DESCRIPTION
    This Cmdlet assigns device(s) to an HPE GreenLake physical location.
         
    .PARAMETER SerialNumber
    Serial number of the device to be assigned to the location.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER LocationName
    Name of the available physical location to assign.
    This value can be retrieved from Get-HPEGLLocation.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
    
    .EXAMPLE
    Set-HPEGLDeviceLocation -LocationName London -SerialNumber QWERTY2124
     
    Assign the specified device to the London location.
 
    .EXAMPLE
    'QWERTY2124', 'CW12312333' | Set-HPEGLDeviceLocation -LocationName London
 
    Assign the devices with the serial numbers listed as a pipeline input to the London location.
 
    .INPUTS
    System.Collections.ArrayList
        List of device serial numbers.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device to be assigned to an application instance.
        * Status - Status of the assignment attempt (Failed for http error return; Complete if assignment is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLDevice
    Get-HPEGLLocation
    New-HPEGLLocation
    Set-HPEGLLocation
    Remove-HPEGLLocation
    Remove-HPEGLDeviceLocation
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('name')]
        [String]$LocationName,

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri
        $AssignmentDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }
    

        if (-not $device) {
            # Must return a message if device not found
            "{0}: Device not found so the location cannot be assigned." -f $SerialNumber | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }

        else {

            # Check if location exists
            try {
                $Locationfound = Get-HPEGLLocation -Name $LocationName
                
            }
            catch {
                Throw $_                
            }


            if ( -not $Locationfound) {
                "'{0}' Location name cannot be found!" -f $LocationName | Write-Verbose
                $objStatus.Status = "Failed"
                $objStatus.Details = "Location name cannot be found on the HPE GreenLake platform!"
            
            }
            else {         

                $PartNumber = $device | % part_number
                $DeviceType = $device | % device_type

            
                # Build DeviceList object
            
                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber 
                    device_type   = $DeviceType
                    location_id   = $Locationfound.id
                }
            


                # Build payload
                $payload = [PSCustomObject]@{ devices = $DeviceList
                } | ConvertTo-Json -Depth 5
                
       
                # Assign Device to location
                try {
                    Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PATCH' -body $payload -WhatIfBoolean $WhatIf | out-Null

                    if (-not $Whatif) {

                        "{0}: Device successfully assigned to location: {1}" -f $SerialNumber, $LocationName | Write-Verbose

                        $objStatus.Status = "Complete"
                        $objStatus.Details = "Device successfully assigned to location!"

                    }
                }
                catch {
                    
                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Device cannot be assigned to location!"
                        $objStatus.Exception = $_.Exception.message 
                    }
                    
                    
                }
            }
        }

        [void] $AssignmentDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($AssignmentDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the assignment attempt!"
          
            }
        }

        Return $AssignmentDevicesStatus

    }
}


Function Remove-HPEGLDeviceLocation {
    <#
    .SYNOPSIS
    Remove device(s) from a physical location.
 
    .DESCRIPTION
    This Cmdlet unassigns device(s) from an HPE GreenLake physical location.
         
    .PARAMETER SerialNumber
    Serial number of the device to be unassigned from a physical location.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
    
    .EXAMPLE
    Remove-HPEGLDeviceLocation -SerialNumber QWERTY12345
     
    Unassign the specified device from the physical location.
 
    .EXAMPLE
    'QWERTY12345' , 'CW12312333' | Remove-HPEGLDeviceLocation
 
    Unassign the devices with the serial numbers listed as a pipeline input from their physical location.
 
    .INPUTS
    System.Collections.ArrayList
        List of device serial numbers.
 
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device to be unassigned from a physical location.
        * Status - Status of the unassignment attempt (Failed for http error return; Complete if unassignment is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLDevice
    Get-HPEGLLocation
    New-HPEGLLocation
    Set-HPEGLLocation
    Remove-HPEGLLocation
    Set-HPEGLDeviceLocation
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesUri
        $UnassignmentDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }
    

        if (-not $device) {
            # Must return a message if device not found
            "{0}: Device not found so the location cannot be unassigned." -f $SerialNumber | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }

        else {             

            $PartNumber = $device | % part_number
            $DeviceType = $device | % device_type

            
            # Build DeviceList object
            
            $DeviceList += [PSCustomObject]@{
                serial_number = $SerialNumber
                part_number   = $PartNumber 
                device_type   = $DeviceType
                location_id   = ""
            }
            


            # Build payload
            $payload = [PSCustomObject]@{ devices = $DeviceList
            } | ConvertTo-Json -Depth 5
                
       
            # Unassign Device from location
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PATCH' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    "{0}: Device successfully unassigned from location: {1}" -f $SerialNumber, $LocationName | Write-Verbose

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully unassigned from location!"

                }
            }
            catch {
                    
                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device cannot be unassigned from location!"
                    $objStatus.Exception = $_.Exception.message 
                }
    
            }
        }

        [void] $UnassignmentDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($UnassignmentDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the unassignment attempt!"
          
            }
        }

        Return $UnassignmentDevicesStatus

    }
}



############################ APPLICATION ###################################


Function Get-HPEGLApplication {
    <#
    .SYNOPSIS
    Retrieve provisioned applications and instances.
 
    .DESCRIPTION
    This Cmdlet returns a collection of provisioned applications and instances to assign to devices.
 
    .PARAMETER Name
    Optional parameter that can be used to display all application instances by name.
 
    .PARAMETER Region
    Optional parameter that can be used to select the application instances matching with a region, for instance, the string 'central' will
    return all region names with the word 'central', like us-central, eu-central, etc.)
    If Region is defined with only 2 characters, the command returns only the applications whose region name starts with these two characters.
 
    .PARAMETER Provisioned
    Optional parameter that can be used to display the list of provisioned applications.
 
    .PARAMETER Available
    Optional parameter that can be used to display the list of available applications that can be provisioned.
 
    .PARAMETER AssignedDevices
    Optional parameter that can be used to display the list of devices assigned to a particular application instance.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLApplication
 
    Return all applications, both the ones available for provisioning and the ones provisioned.
 
    .EXAMPLE
    Get-HPEGLApplication -Name 'Compute Ops Management'
 
    Return all Compute Ops Management application instances.
 
    .EXAMPLE
    Get-HPEGLApplication -Name 'Compute Ops Management' -Provisioned
 
    Return all Compute Ops Management application instances that are provisioned.
 
    .EXAMPLE
    Get-HPEGLApplication -Name 'Compute Ops Management' -Region EU
 
    Return all Compute Ops Management application instances that are provisioned in Europe.
 
    .EXAMPLE
    Get-HPEGLApplication -Available
 
    Return all applications available for provisioning in the different regions.
 
    .EXAMPLE
    Get-HPEGLApplication -Available -Region 'eu-central'
 
    Return all applications available for provisioning in the Central Europe region.
     
    .EXAMPLE
    Get-HPEGLApplication -Available -Name "Aruba Central" -Region AP
  
    Return all Aruba Central applications available for provisioning in the Asia Pacific region.
     
    .EXAMPLE
    Get-HPEGLApplication -Name 'Compute Ops Management' -Region EU -AssignedDevices
  
    Return all devices assigned to the "Compute Ops Management" application in European regions.
 
    .LINK
    Add-HPEGLApplication
    Remove-HPEGLApplication
    Get-HPEGLApplicationResourceRestrictionPolicyFilter
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Provisioned')]
    Param( 
        [Parameter (Mandatory = $false, ParameterSetName = 'Provisioned')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Available')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedDevices')]
        # [ValidateSet( 'Compute Ops Management', 'Data Services Cloud Console', 'Aruba Central', 'HPE GreenLake' )]
        [String]$Name,            
 
        [Parameter (Mandatory = $false, ParameterSetName = 'Provisioned')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Available')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedDevices')]
        [String]$Region,
    
        [Parameter (Mandatory = $false, ParameterSetName = 'Provisioned')]
        [Switch]$Provisioned,

        [Parameter (Mandatory = $false, ParameterSetName = 'Available')]
        [Switch]$Available,

        [Parameter (Mandatory = $false, ParameterSetName = 'AssignedDevices')]
        [Switch]$AssignedDevices,

        [Parameter(Mandatory = $False, ParameterSetName = 'Provisioned')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Available')]
        [Parameter (Mandatory = $false, ParameterSetName = 'AssignedDevices')]
        [Switch]$Whatif

    ) 
    
    Begin {
    
        $UriAdd = $ApplicationsProvisionsUri
  
        # If the region has 2 characters, the search usually is a region code like US, AP, EU so to avoid matching errors with region names,
        # it is necessary to make a match on the first 2 characters of the chain.
        if ($Region.Length -eq 2) {  
            $Region = "^$Region.*" 
        }
    }

    Process {

        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf 
        
        }
        catch {
   
            Throw $_
       
        }
       
        
        if ($AssignedDevices) {

            try {
                $AppRegionfound = Get-HPEGLApplication -Name $Name -Region $Region
            }
            catch {
       
                Throw $_
           
            }
          
            if ($AppRegionfound) {

                $ApplicationInstanceId = $AppRegionfound.application_instance_id

                try {
                    [array]$Collection = Get-HPEGLdevice -NoLimit | Where-Object application_instance_id -eq $ApplicationInstanceId
                    $ReturnData = Invoke-RepackageObjectWithType -RawObject $Collection -ObjectName "Device"
                    $ReturnData = $ReturnData | Sort-Object serial_number, ccs_region
                    return $ReturnData 
                }
                catch {
           
                    Throw $_
               
                }

            }
        }

        if ($Null -ne $Collection.applications) {
              
            $CollectionList = $Collection.applications 
            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Application"         
                         
            if ($Name -and -not $Region) {
                $ReturnData = $ReturnData | Where-Object { $_.application_name -eq $name } | Sort-Object ccs_region

            }
            elseif ($Name -and $Region) {
                $ReturnData = $ReturnData | Where-Object { $_.application_name -eq $name -and $_.ccs_region -match $Region } | Sort-Object application_name

            }
            elseif (-not $Name -and $Region) {
                $ReturnData = $ReturnData | Where-Object { $_.ccs_region -match $Region } | Sort-Object application_name
                
            }
            else {
                $ReturnData = $ReturnData | Sort-Object application_name, ccs_region

            }     
      
            return $ReturnData 
  
        }
        elseif ($Null -ne $Collection.provisions) {

            $CollectionList = $Collection.provisions 
           
            if ($Provisioned) {

                $CollectionList = $CollectionList |  Where-Object { $_.provision_status -eq "PROVISIONED" }
                        
            }

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Application"         

            if ($Available) {

                $CollectionList = $CollectionList |  Where-Object { $_.provision_status -ne "PROVISIONED" }
                $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Application.Available"    
                       
            }
                        
            if ($Name -and -not $Region) {
                $ReturnData = $ReturnData | Where-Object { $_.name -eq $name } | Sort-Object region

            }
            elseif ($Name -and $Region) {
                $ReturnData = $ReturnData | Where-Object { $_.name -eq $name -and $_.region -match $Region } | Sort-Object name

            }
            elseif (-not $Name -and $Region) {
                $ReturnData = $ReturnData | Where-Object { $_.region -match $Region } | Sort-Object name

            }
            else {
                $ReturnData = $ReturnData | Sort-Object name, region

            }     
      
      
            return $ReturnData 
            


        }
        else {

            return 
            
        }
    }
}


Function Get-HPEGLApplicationResourceRestrictionPolicyFilter {
    <#
    .SYNOPSIS
    Retrieve resource restriction policy filters.
 
    .DESCRIPTION
    This Cmdlet returns the resource restriction policy filters that are available in an application instance.
 
    .PARAMETER Application
    Parameter to display resource restriction policy filters for an application name chosen from a predefined list.
    The predefined applications are as follows:
        * Compute Ops Management
        * Data Services Cloud Console
        * Aruba Central
 
    .PARAMETER ApplicationName
    Parameter to display resource restriction policy filter for an application name (can be retrieved using Get-HPEGLApplication).
 
    .PARAMETER Region
    Name of the region of the application (can be retrieved using Get-HPEGLApplication).
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLApplicationResourceRestrictionPolicy -ApplicationName 'Compute Ops Management' -Region "eu-central"
   
    Returns all resource restriction policy filters for the Compute Ops Management application in the Central European region.
 
    .EXAMPLE
    Get-HPEGLApplicationResourceRestrictionPolicy -Application 'Compute Ops Management' -Region "us-west" -FilterName RRP_ESXi_Houston
   
    Returns the 'RRP_ESXi_Houston' resource restriction policy filter for the Compute Ops Management application in the US western region.
 
    .LINK
    Get-HPEGLApplication
    Add-HPEGLApplication
    Remove-HPEGLApplication
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory, ParameterSetName = 'Application')]
        [ValidateSet( 'Compute Ops Management', 'Data Services Cloud Console', 'Aruba Central' )]
        [String]$Application,

        [Parameter (Mandatory, ParameterSetName = 'ApplicationName')]
        [String]$ApplicationName,   
        
        [Parameter (Mandatory, ParameterSetName = 'ApplicationName')]
        [Parameter (Mandatory, ParameterSetName = 'Application')]
        [String]$Region,

        [Parameter (Mandatory = $False, ParameterSetName = 'ApplicationName')]
        [Parameter (Mandatory = $False, ParameterSetName = 'Application')]
        [String]$FilterName,

        [Parameter (Mandatory = $false, ParameterSetName = 'ApplicationName')]
        [Parameter (Mandatory = $False, ParameterSetName = 'Application')]
        [Switch]$Whatif

    ) 
    
    Begin {
  
       
    }

    Process {

        if ($Application) {
            $ApplicationName = $Application
        }

        try {

            $_Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName -Region $Region
                     
        }
        catch {
   
            Throw $_
       
        }
       
        
        if ($_Application) {

                  
            $ApplicationId = $_Application.application_id

            $UriAdd = $ApplicationsScopeAssignmentsUri + "?application_id=" + $ApplicationId + "&include_predefined_filters_and_scope_resource_instances=true"

            try {
                [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf 
              
            }
            catch {

                Throw $_
   
            }
        }
       

        if ($Null -ne $Collection) {
           
            $Collection = $Collection | ? region -eq $Region

            $Collection | Out-String | Write-Verbose

            $FilterList = @()
            
            if ($Collection.slug -eq "HPECC") {
               
                $ApplicationInstanceId = $_Application.application_instance_id
                $ApplicationCustomerId = $_Application.application_customer_id
                $Slug = $Collection.scope_resources.slug

                $UriAdd = $ApplicationInstancesUri + "/" + $ApplicationInstanceId + "/scope_resource_instances?limit=200&offset=0&application_cid=" + $ApplicationCustomerId + "&scope_resource=$slug"
            
                try {
                    [array]$FilterCollection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf 
              
                }
                catch {

                    Throw $_
   
                }

                $FilterCollection | Out-String | Write-Verbose

                foreach ($Filter in $FilterCollection.scope_resource_instances) {
                    
                    "Filter {0}" -f $filter.name | Write-Verbose

                    $ReturnData = $FilterCollection | Select-Object  `
                    @{N = "filter_name"; E = { $Filter.name } }, `
                    @{N = "application_name"; E = { $ApplicationName } }, `
                    @{N = "region"; E = { $Collection.region } }, `
                    @{N = "slug"; E = { $Filter.slug } }, `
                    @{N = "scope_type_name"; E = { $_.scope_resource_instances.name } }, `
                        # @{N = "description"; E = { $_.scope_resource_instances.description } }, `
                    @{N = "application_customer_id"; E = { $_.application_customer_id } }, `
                    @{N = "application_instance_id"; E = { $_.application_instance_id } }, `
                    @{N = "application_id"; E = { $_.application_id } }

                    $FilterList += $ReturnData | Sort-Object -Property filter_name
                }

            } 

            elseif ($Collection.scope_resources) {
               
                foreach ($Filter in $Collection.scope_resources) {
                    
                    "Filter {0}" -f $filter.name | Write-Verbose

                    $ReturnData = $Collection | Select-Object  `
                    @{N = "filter_name"; E = { $Filter.name } }, `
                    @{N = "application_name"; E = { $ApplicationName } }, `
                    @{N = "region"; E = { $_.region } }, `
                    @{N = "slug"; E = { $Filter.slug } }, `
                    @{N = "scope_type_name"; E = { $_.scope_resources.name } }, `
                        # @{N = "description"; E = { $_.scope_resources.description } }, `
                    @{N = "application_customer_id"; E = { $_.application_customer_id } }, `
                    @{N = "application_instance_id"; E = { $_.application_instance_id } }, `
                    @{N = "application_id"; E = { $_.application_id } }

                    $FilterList += $ReturnData | Sort-Object -Property filter_name
                }
            }
            elseif ($Collection.predefined_filters) {      
                    
                foreach ($Filter in $Collection.predefined_filters) {
                        
                    "Predefined filter {0}" -f $Filter.name | Write-Verbose

                    $ReturnData = $Collection | Select-Object  `
                    @{N = "filter_name"; E = { $Filter.name } }, `
                    @{N = "application_name"; E = { $ApplicationName } }, `
                    @{N = "region"; E = { $_.region } }, `
                    @{N = "slug"; E = { $Filter.slug } }, `
                    @{N = "scope_type_name"; E = { $Filter.name } }, `
                        # @{N = "description"; E = { $Filter.description } }, `
                    @{N = "application_customer_id"; E = { $_.application_customer_id } }, `
                    @{N = "application_instance_id"; E = { $_.application_instance_id } }, `
                    @{N = "application_id"; E = { $_.application_id } }

                    $FilterList += $ReturnData | Sort-Object -Property filter_name
                }
            } 
      

            if ($FilterName) {
                $FilterList = $FilterList | ? filter_name -eq $FilterName

            } 

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $FilterList -ObjectName "Application.Resource.Restriction.Policy.Filter"         
            $ReturnData = $ReturnData | sort-object filter_name, application_name, region

            return $ReturnData

        }     
       
        else {

            return 
            
        }
    }
}


Function Add-HPEGLApplication {
    <#
    .SYNOPSIS
    Deploy an application in a region.
 
    .DESCRIPTION
    This Cmdlet can be used to deploy an application in a new region.
         
    .PARAMETER ApplicationName
    Name of the available application to deploy.
    This value can be retrieved from Get-HPEGLApplication -Available.
 
    .PARAMETER Region
    Name of the region to deploy the application.
    This value can be retrieved from Get-HPEGLApplication -Available
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Add-HPEGLApplication -ApplicationName "Aruba Central" -Region "eu-central"
 
    Deploy the application "Aruba Central" in the "eu-central" region.
 
    .EXAMPLE
    Get-HPEGLApplication -Available -Name "Compute Ops Management" -Region "us-west" | Add-HPEGLApplication
 
    Get the Compute Ops Management application available in the western US region and deploy it.
 
    .INPUTS
    System.Collections.ArrayList
        List of Application(s) from Get-HPEGLApplication.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Application - Name of the application attempted to be deployed
        * Region - Name of the region to deploy the application
        * Status - Status of the deployment attempt (Failed for http error return; Complete if deployment is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLApplication -Available
    Remove-HPEGLApplication
    Get-HPEGLApplicationResourceRestrictionPolicyFilter
    [${Global:HPEGreenLakeSession}]
     
   #>


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

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('ccs_region')]
        [String]$Region,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $ApplicationProvisioningUri  
        $DeployApplicationStatus = [System.Collections.ArrayList]::new()


    }

    Process {


        try {
            $Appfound = Get-HPEGLApplication -Name $ApplicationName 
      
        }
        catch {    
            Throw $_
        
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Application = $ApplicationName
            Region      = $Region                            
            Status      = $Null
            Details     = $Null
            Exception   = $Null
                                  
        }

        if (-not $Appfound) {
            # Must return a message if ApplicationName not found
            $objStatus.Status = "Failed"
            $objStatus.Details = "Application cannot be found on the HPE GreenLake platform!"
            
        }
        else {

            try {
                $AppRegionfound = Get-HPEGLApplication -Name $ApplicationName -Region $Region

            }
            catch {    
                Throw $_
    
            }
        
            if (-not $AppRegionfound -or $AppRegionfound.region -ne $Region) {
                # Must return a message if Application is not found in the region
                "{0}: Application not available in {1} region!" -f $ApplicationName, $Region | Write-Verbose
            
                $objStatus.Status = "Failed"
                $objStatus.Details = "Application not available in $Region region!"
            
            }
            elseif ($AppRegionfound.provision_status) {
                # Must return a message if Application is already provisioned
                "{0}: Application is already provisioned in {1} region!" -f $ApplicationName, $Region | Write-Verbose

                $objStatus.Status = "Warning"
                $objStatus.Details = "Application is already provisioned in $Region region!"
            

            }
            else {
       
                $ApplicationId = $AppRegionfound.application_id


                # Build payload
                $payload = ConvertTo-Json @{
                    region         = $Region
                    application_id = $ApplicationId 
                    action         = "PROVISION"
                
                }
      

                # Deploy the application in a region.
                try {
                    Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | Out-Null

                    if (-not $Whatif) {

                        "{0}: Application successfully deployed in {1} region" -f $ApplicationName, $Region | Write-Verbose
                    
                        $objStatus.Status = "Complete"
                        $objStatus.Details = "Application successfully deployed in $Region region"

                    }

                }
                catch {

                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Application cannot be deployed!"
                        $objStatus.Exception = $_.Exception.message 
                    }
                }           

            }
       
        }

        [void] $DeployApplicationStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($DeployApplicationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more applications failed the deployment attempt!"
          
            }
        }

        Return $DeployApplicationStatus

    }
}


Function Remove-HPEGLApplication {
    <#
    .SYNOPSIS
    Remove an application from a region.
 
    .DESCRIPTION
    This Cmdlet can be used to remove an application from a region. This action is irreversible and cannot be canceled or undone once the process has begun.
    All users will lose access and this will permanently delete all device and user data.
     
    The cmdlet issues a message at runtime to warn the user of the irreversible impact of this action and asks for a confirmation for the removal of the application.
         
    .PARAMETER ApplicationName
    Name of the available application to remove.
    This value can be retrieved from Get-HPEGLApplication -Available.
     
    .PARAMETER Region
    Name of the region where the application is removed.
    This value can be retrieved from Get-HPEGLApplication -Available
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLApplication -Provisioned -Name "Compute Ops Management" -Region "us-west" | Remove-HPEGLApplication
 
    Get the provisioned Compute Ops Management application in the western US region and remove it.
    A warning message appears and asks the user to confirm the action.
 
    .EXAMPLE
    Remove-HPEGLApplication -ApplicationName "Aruba Central" -Region "eu-central"
 
    Remove the "Aruba Central" application from the Central Europe region after the user has confirmed the removal.
    
    .INPUTS
    System.Collections.ArrayList
        List of Application(s) from Get-HPEGLApplication.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Application - Name of the application attempted to be removed
        * Region - Name of the region where the application is removed
        * Status - Status of the removal attempt (Failed for http error return; Complete if removal is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLApplication -Available
    Add-HPEGLApplication
    Get-HPEGLApplicationResourceRestrictionPolicyFilter
    [${Global:HPEGreenLakeSession}]
     
   #>


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

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('ccs_region')]
        [String]$Region,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

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


    }

    Process {
        
        try {
            $AppRegionfound = Get-HPEGLApplication -Name $ApplicationName -Region $Region
        }
        catch {    
            Throw $_
    
        }
       
        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Application = $ApplicationName
            Region      = $Region                            
            Status      = $Null
            Details     = $Null
            Exception   = $Null
                                      
        }  
       
       
        if (-not $AppRegionfound) {
            # Must return a message if Application is not found in the region
            "{0}: Application not available in {1} region!" -f $ApplicationName, $Region | Write-Verbose

            $objStatus.Status = "Failed"
            $objStatus.Details = "Application not available in $Region region!"

        }
        elseif (-not $AppRegionfound.provision_status) {
            # Must return a message if Application is not provisioned
            "{0}: Application is not provisioned!" -f $ApplicationName  | Write-Verbose

            $objStatus.Status = "Failed"
            $objStatus.Details = "Application is not provisioned!"
        }
        else {       
           
            $title = "All users will lose access and this will permanently delete all device and user data. Confirm that you would like to remove {0} {1}." -f $ApplicationName, $Region
            $question = 'This action is irreversible and cannot be canceled or undone once the process has begun. Are you sure you want to proceed?'
            $choices = '&Yes', '&No'

            $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)

            if ($decision -eq 0) {

                $ApplicationId = $AppRegionfound.application_customer_id

                $UriAdd = $ApplicationProvisioningUri + "/" + $ApplicationId
    
                # Build payload
                $payload = ConvertTo-Json @{
                    action = "UNPROVISION"
                    
                }
          
    
                # Deploy the application in a region.
                try {
                    Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'PATCH' -body $payload -WhatIfBoolean $WhatIf | Out-Null

                    if (-not $Whatif) {
    
                        "{0}: Application successfully removed from {1} region!" -f $ApplicationName, $Region | Write-Verbose

                        $objStatus.Status = "Complete"
                        $objStatus.Details = "Application successfully removed from $Region region"

                    }

                }
                catch {

                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Application cannot be removed!"
                        $objStatus.Exception = $_.Exception.message 
                    }
                }           
    
                
          
            }
            else {
                'Operation cancelled by user!' | Write-Verbose

                $objStatus.Status = "Failed"
                $objStatus.Details = "Operation cancelled by the user!"
            }
       
        }

        [void] $RemoveApplicationStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($RemoveApplicationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more applications failed the removal attempt!"
          
            }
        }

        Return $RemoveApplicationStatus

    }
}


Function Set-HPEGLDeviceApplication {
    <#
    .SYNOPSIS
    Assign device(s) to an application instance.
 
    .DESCRIPTION
    This Cmdlet assigns device(s) to an HPE GreenLake application instance.
         
    .PARAMETER SerialNumber
    Serial number of the device to be assigned to an application instance.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER ApplicationName
    Name of the available application to assign.
    This value can be retrieved from Get-HPEGLApplication.
 
    .PARAMETER Region
    Name of the region of the application.
    This value can be retrieved from Get-HPEGLApplication.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
    
    .EXAMPLE
    Get-HPEGLApplication -name "Compute Ops Management" -Region "US-West" | Set-HPEGLDeviceApplication -SerialNumber "1234567890"
     
    Assign the specified device to the application "Compute Ops Management" in the western US region.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'MXQ72407P3' },
        [PSCustomObject]@{SerialNumber = 'MXQ73200W1' }
    )
 
    $devices | Set-HPEGLDeviceApplication -ApplicationName "Compute Ops Management" -Region "US-West"
 
    Assign the devices specified in an array to the application Compute Ops Management in the western US region.
 
    .EXAMPLE
    Add-Content -Path Tests\SerialNumbers.csv -Value '"Serialnumber"'
 
    $Serialnumbers = @('7CE244P9LM' , 'MXQ73200W1')
 
    $Serialnumbers | foreach { Add-Content -Path Tests\SerialNumbers.csv -Value $_ }
 
    Import-Csv Tests\SerialNumbers.csv | Set-HPEGLDeviceApplication -ApplicationName "Compute Ops Management" -Region "US-West"
 
    Assign the devices listed in a csv file to an application instance.
 
    .INPUTS
    System.Collections.ArrayList
        List of devices(s) from Get-HPEGLDevice to be assigned to an application instance.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device to be assigned to an application instance.
        * Status - Status of the assignment attempt (Failed for http error return; Complete if assignment is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLApplication
    Remove-HPEGLDeviceApplication
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('ccs_region')]
        [String]$Region,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesApplicationInstanceUri  
        $AssignmentDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }
    

        if (-not $device) {
            # Must return a message if device not found
            "{0}: Device not found so this application instance cannot be assigned." -f $SerialNumber | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif ( $device.application_id) {
            "{0}: Device already assigned to an application instance." -f $SerialNumber | Write-Verbose
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device already assigned to an application instance!"
        }
        else {

            $PartNumber = $device | % part_number
            $DeviceType = $device | % device_type

            $Gen11 = $device | ? device_model -match "Gen11"  
        
            # Build DeviceList object
            if ($gen11) {

                $mac = $device | % mac_address

                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber 
                    mac_address   = $mac
                    device_type   = $DeviceType
                }
            }
            else {

                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber 
                    device_type   = $DeviceType
                }
            }
        
            


            try {
                $Appfound = Get-HPEGLApplication -Name $ApplicationName 
          
            }
            catch {    
                Throw $_
            
            }

            if (-not $Appfound) {
                # Must return a message if ApplicationName not found
                $objStatus.Status = "Failed"
                $objStatus.Details = "Application cannot be found on the HPE GreenLake platform!"
                
            }
            else {
    
                try {
                    $AppRegionfound = Get-HPEGLApplication -Provisioned -Name $ApplicationName -Region $Region
    
                }
                catch {    
                    Throw $_
        
                }

                if (-not $AppRegionfound) {
                    # Must return a message if Application is not provisioned in the region
                    "{0}: Application not provisioned in {1} region!" -f $ApplicationName, $Region | Write-Verbose
            
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Application not provisioned in $Region region!"
            
                }
                else {

                    $ApplicationInstanceId = $AppRegionfound.application_instance_id

                    $ApplicationId = $AppRegionfound.application_id


                    # Build payload
                    $payload = [PSCustomObject]@{ assign_list = @(
                            @{  devices                 = $DeviceList
                                application_id          = $ApplicationId
                                application_instance_id = $ApplicationInstanceId
                            })
                    } | ConvertTo-Json -Depth 5
                
       
                    # Assign Device to Application
                    try {
                        Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | out-Null

                        if (-not $Whatif) {

                            "{0}: Device successfully assigned to application instance: {1}" -f $SerialNumber, $ApplicationName + " / " + $Region | Write-Verbose

                            $objStatus.Status = "Complete"
                            $objStatus.Details = "Device successfully assigned to application instance!"

                        }
                    }
                    catch {
                    
                        if (-not $Whatif) {
                            $objStatus.Status = "Failed"
                            $objStatus.Details = "Device cannot be assigned to application instance!"
                            $objStatus.Exception = $_.Exception.message 
                        }
                    }
                }
            }
        }

        [void] $AssignmentDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($AssignmentDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the assignment attempt!"
          
            }
        }

        Return $AssignmentDevicesStatus

    }
}


Function Remove-HPEGLDeviceApplication {
    <#
    .SYNOPSIS
    Unassign device(s) from an application instance.
 
    .DESCRIPTION
    This Cmdlet unassigns device(s) from an HPE GreenLake application instance.
         
    .PARAMETER SerialNumber
    Serial number of the device to be unassigned from an application instance.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
    
    .EXAMPLE
    Remove-HPEGLDeviceApplication -SerialNumber MXQ73200W1
 
    Unassign the specified device from its application instance.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'CNX2380BLC' },
        [PSCustomObject]@{SerialNumber = 'MXQ73200W1' }
    )
 
    $devices | Remove-HPEGLDeviceApplication
 
    Unassign the specified devices from their application instances.
 
    .INPUTS
    System.Collections.ArrayList
        List of devices(s) from Get-HPEGLDevice to be unassigned from an application instance.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device to be unassigned from an application instance.
        * Status - Status of the un-assignment attempt (Failed for http error return; Complete if un-assignment is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLApplication
    Set-HPEGLDeviceApplication
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $DevicesApplicationInstanceUri  
        $UnassignmentDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {

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

        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                      
        }

        if (-not $device) {
            # Must return a message if device not found
            "{0}: Device not found so application instance cannot be unassigned." -f $SerialNumber  | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif ( -not $device.application_id) {
            "{0}: Device not assigned to an application instance." -f $SerialNumber  | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device not assigned to an application instance!"
        }
        else {

            $PartNumber = $device | % part_number
            $DeviceType = $device | % device_type

            $Gen11 = $device | ? device_model -match "Gen11"

            
            # Build DeviceList object
            if ($gen11) {

                $mac = $device | % mac_address

                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber 
                    mac_address   = $mac
                    device_type   = $DeviceType
                }
            }
            else {

                $DeviceList += [PSCustomObject]@{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber 
                    device_type   = $DeviceType
                }
            }
        

            # Build payload
            $payload = [PSCustomObject]@{
                devices = $DeviceList
            } | ConvertTo-Json -Depth 5
   
        
            # Unassign Device from Application
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'DELETE' -body $payload -WhatIfBoolean $WhatIf | out-Null
                    
                if (-not $Whatif) {

                    "{0}: Device successfully unassigned from the application instance." -f $SerialNumber
                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully unassigned from the application instance!"
                }
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device cannot be unassigned from the application instance!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
             
        }

        [void] $UnassignmentDevicesStatus.add($objStatus)
        
    }

    end {

        if (-not $Whatif) {

            if ($UnassignmentDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the un-assignment attempt!"
          
            }
        }

        Return $UnassignmentDevicesStatus

    }
}


Function Get-HPEGLAPIcredential {
    <#
    .SYNOPSIS
    Retrieve API credential for an application instance.
 
    .DESCRIPTION
    This Cmdlet returns a collection of API credential resources for an HPE GreenLake application instance
 
    .PARAMETER Name
    Name of the API client credential to retrieve.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLAPICredential
 
    Return the API credentials for all application instances.
 
    .EXAMPLE
    Get-HPEGLAPICredential -Name "Grafana-COM-AP_NorthEast"
 
    Return the API credential for the application instance "Grafana-COM-AP_NorthEast".
 
    .LINK
    New-HPEGLAPIcredential
    Remove-HPEGLAPICredential
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [String]$Name,  

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $ApplicationsAPICredentialsUri

        
    }

    Process {
       
        $ReturnData = @()

        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf

        }  
        catch {    
            Throw $_

        }

        if ($Null -ne $Collection ) {

            If ($Name) {

                $CollectionList = $Collection | ? credential_name -eq $Name
            }
            else {

                $CollectionList = $Collection 
            }

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Application.API.Credential"         

            $ReturnData = $ReturnData | Sort-Object { $_.credential_name }
            
            return $ReturnData 
    
        }
        else {
            return
        }
    }
}


Function New-HPEGLAPIcredential {
    <#
    .SYNOPSIS
    Creates API credential for an application instance.
 
    .DESCRIPTION
    This Cmdlet generates API client credential for an HPE GreenLake application instance.
         
    API client credential is used to generate access tokens that are required for accessing account data. You can maintain a maximum of 5 credentials.
     
    The prerequisite to generate an API access token is that the application instance is provisioned/added to the user's customer account.
    The user must have a role that is required to perform the intended operation in the application instance.
        
    .PARAMETER TemplateName
    Template name of the API client credential to create. This parameter is used to automatically generate the name of the API client credential.
    This parameter is used to automatically generate the API client ID name based on the templatename, the application name and region.
    The generated name has the following format: <TemplateName>_<ApplicationName>_<ApplicationRegion>
    <ApplicationName> can be either COM, DSCC or the application name without spaces.
    Example of auto-generated API Credential names: "Grafana-DSCC-US_West", "Ansible-COM-EU_Central", "Terraform-Aruba_Central-AP_Central"
 
    .PARAMETER ApplicationName
    Name of the provisioned application that will be accessible using the API credentials.
    This value can be retrieved from Get-HPEGLApplication -Provisioned.
 
    .PARAMETER Region
    Name of the application region that will be accessed using the API credentials.
    This value can be retrieved from Get-HPEGLApplication -Provisioned.
 
    .PARAMETER Location
    Directory to which the API credentials will be exported to.
    The exported API credentials include everything you need to execute a subsequent API request with the application.
    Exported file name will be "<Auto-generated API Credential name>_API_Credential.json".
    This is an optional parameter. Note that generated API credentials are always stored during a session in ${Global:HPEGreenLakeSession.apiCredentials}
 
    .PARAMETER Encrypt
    Optional parameter to encrypt the API credentials exported in the $Location directory.
     
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
     
    .EXAMPLE
    Get-HPEGLApplication -Name 'Data Services Cloud Console' -Region "EU-Central" | New-HPEGLAPIcredential -TemplateName Grafana -Location . -Encrypt
     
    Generates the 'Grafana-DSCC-EU_Central' API client credential for the 'Data Services Cloud Console' application instance
    in the Central Europe region.
    
    At the same time, the API credentials, including, among others, the client ID and secret, are encrypted then exported to a JSON file named
    'Grafana-DSCC-EU_Central_API_Credentials.json' in the local folder.
 
    Later, when you need to read the contents of this encrypted API credential file, you can use the following commands:
    $SecureApplicationAPICredential = Get-Content Grafana-COM-<Region_Name>_API_Credentials.json | ConvertTo-SecureString
    $Bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureApplicationAPICredential)
    $ApplicationAPICredential = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) | ConvertFrom-Json
 
    Note that decryption is only supported on the same machine from which the cmdlet was executed.
     
    .EXAMPLE
    Get-HPEGLApplication -Provisioned -Name 'Compute Ops Management' | New-HPEGLAPIcredential -TemplateName Grafana -Location c:\MyCredentials
     
    Generates API client credentials for all provisioned instances of Compute Ops Management. Credentials names are automatically generated
    from the TemplateName property, for example "Grafana-COM-AP_NorthEast' for 'Compute Ops Management AP NorthEast', 'Grafana-COM-EU_Central' for
    'Compute Ops Management EU Central', etc.
 
    API credentials for each 'Compute Ops Management' application instances are then exported as JSON files to c:\MyCredentials folder.
    Exported files are named 'Grafana-COM-<Region_Name>_API_Credentials.json'. Note that these files are in clear text (unencrypted) but contain
    sensitive data that may be subject to cyberattacks.
     
    .EXAMPLE
    Get-HPEGLApplication -Name 'Data Services Cloud Console' -Region "EU-Central" | New-HPEGLAPIcredential -TemplateName Grafana
    $Grafana_DSCC_EU_Central_Credentials = $HPEGreenLakeSession.apiCredentials | ? credential_name -eq "Grafana-DSCC-EU_Central"
    Connect-DSCC -Client_Id $Grafana_DSCC_EU_Central_Credentials.client_id -Client_Secret $Grafana_DSCC_EU_Central_Credentials.client_secret -GreenlakeType EU -AutoRenew -WhatIfToken
 
    Shows how to pass the API credentials stored in the $HPEGreenLakeSession global variable to Connect-DSCC, the function that provides the initial connection
    to HPE Data Storage Cloud Services.
 
    Method 1: Access API credentials using the global variable:
    - When API Credentials are created, they are stored in $HPEGreenLakeSession.apiCredentials global variable object.
    - Accessible as long as the PowerShell console is active and Disconnect-HPEGL has not been used.
     
    .EXAMPLE
    Get-HPEGLApplication -Name 'Data Services Cloud Console' -Region "EU-Central" | New-HPEGLAPIcredential -TemplateName Grafana -Location . -Encrypt
    $Secure_Grafana_DSCC_EU_Central_Credentials = Get-Content .\Grafana-DSCC-EU_Central_API_Credentials.json | ConvertTo-SecureString
    $Bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Secure_Grafana_DSCC_EU_Central_Credentials)
    $Grafana_DSCC_EU_Central_Credentials = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($Bstr) | ConvertFrom-Json
    Connect-DSCC -Client_Id $Grafana_DSCC_EU_Central_Credentials.client_id -Client_Secret $Grafana_DSCC_EU_Central_Credentials.client_secret -GreenlakeType EU -AutoRenew -WhatIfToken
 
    Shows how to pass the API credentials stored in an encrypted API credential file to Connect-DSCC, the function that provides the initial connection
    to HPE Data Storage Cloud Services.
 
    Method 2: Access API credentials using encrypted API credential:
    - Use encrypted JSON file that has been exported with Location and Encrypt parameters.
    - Decryption is only supported on the same machine from which the cmdlet was executed.
   
    .EXAMPLE
    Get-HPEGLApplication -Name 'Data Services Cloud Console' -Region "EU-Central" | New-HPEGLAPIcredential -TemplateName Grafana -Location .
    $Grafana_DSCC_EU_Central_Credentials = Get-Content .\Grafana-DSCC-EU_Central_API_Credentials.json | ConvertFrom-Json
    Connect-DSCC -Client_Id $Grafana_DSCC_EU_Central_Credentials.client_id -Client_Secret $Grafana_DSCC_EU_Central_Credentials.client_secret -GreenlakeType EU -AutoRenew -WhatIfToken
 
    Shows how to pass the API credentials stored in a clear text API credential file to Connect-DSCC, the function that provides the initial connection
    to HPE Data Storage Cloud Services.
 
    Method 3: Access API credentials using unencrypted API credential:
    - File is in clear text (unencrypted) but contains sensitive data that may be subject to cyberattacks.
    - You must rely on the operating system's security file system to protect your sensitive data.
 
    .INPUTS
    System.Collections.ArrayList
        List of Application instance(s) from Get-HPEGLApplication.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - name of the API credential object attempted to be created
        * Filename - name of the file that was exported
        * Location - path of the file that was exported
        * Encrypted - encryption status Boolean
        * Status - status of the creation attempt (Failed for http error return; Complete if the creation is successful; Warning if no action is needed)
        * Details - more information about the status
        * Exception - exception information of the error generated
 
    HPEGreenLakeSession.apiCredentials
        When a creation is successful, an object is then added to ${Global:HPEGreenLakeSession.apiCredentials} API credential tracker variable.
        The object returned will contain the following public properties:
 
             ==================================================================================================
             | Name | Type | Value |
             |-------------------------------------------------------------------------------------------------
             | credential_name | String | Name of the generated credential |
             --------------------------------------------------------------------------------------------------
             | application_name | String | Name of the provisioned application |
             --------------------------------------------------------------------------------------------------
             | region | String | Name of the application region |
             --------------------------------------------------------------------------------------------------
             | application_instance_id | String | ID of the provisioned application instance |
             --------------------------------------------------------------------------------------------------
             | client_secret | String | API Client Secret |
             --------------------------------------------------------------------------------------------------
             | client_id | String | API Client ID |
             --------------------------------------------------------------------------------------------------
             | connectivity_endpoint | String | Connectivity endpoint of the API |
             ==================================================================================================
 
    .LINK
    Get-HPEGLAPICredential
    Remove-HPEGLAPICredential
    Get-HPEGLApplication
    [${Global:HPEGreenLakeSession.apiCredentials}]
     
   #>


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

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "Encrypt")]
        [ValidateNotNullOrEmpty()]
        [String]$TemplateName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Encrypt")]
        [ValidateNotNullOrEmpty()]
        [Alias('name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Encrypt")]
        [ValidateNotNullOrEmpty()]
        [Alias('ccs_region')]
        [String]$Region,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory, ParameterSetName = "Encrypt")]
        [Alias ("x", "export", 'exportFile')]
        [ValidateScript({ Test-Path $_ })]
        [String]$Location,

        [Parameter (Mandatory = $False, ParameterSetName = "Encrypt")]
        [Switch]$Encrypt,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Parameter (Mandatory = $False, ParameterSetName = "Encrypt")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $ApplicationsAPICredentialsUri  
        $NewAPICredentialStatus = [System.Collections.ArrayList]::new()

               
    }

    Process {         


        try {
            $application = Get-HPEGLApplication -Provisioned -Name $ApplicationName -Region $Region
        }
        catch {
            Throw $_
        }    
        
        # Build object for the output
        $objStatus = [pscustomobject]@{
            Name      = $Null
            Filename  = $Null
            Location  = $Null     
            Encrypted = $Null                       
            Status    = $Null
            Details   = $Null
            Exception = $Null
                          
        }

        if (-not $application) {
            # Must return a message if application not found
            "'{0}' Application not found or not provisioned! API credential cannot be created!" -f ($ApplicationName + " - " + $Region) | Write-Verbose
            
            $objStatus.Status = "Failed"
            $objStatus.Details = "Application cannot be found on the HPE GreenLake platform!"
        }
        else {
        
            $ApplicationInstanceId = $application.application_instance_id
          
            if ($ApplicationName -eq "Compute Ops Management") {
                $ApplicationName = "COM"
            }  
            elseif ($ApplicationName -eq "Data Services Cloud Console") {
                $ApplicationName = "DSCC"
            }
            else {
                $ApplicationName = $ApplicationName.replace(" ", "_")
            }
       
            $CredentialName = $TemplateName + "-" + $ApplicationName + "-" + $application.region 

            $objStatus.Name = $CredentialName 

            # Check if credential already exists
            try {
                $Credentialfound = Get-HPEGLAPICredential -Name $CredentialName
                
            }
            catch {
                Throw $_                
            }


            if ( $Credentialfound) {
                "'{0}' API credential name already created, use another name!" -f $CredentialName | Write-Verbose
                $objStatus.Status = "Warning"
                $objStatus.Details = "API credential name already created!"
            
            }
            else {

                $Payload = [PSCustomObject]@{
                    credential_name         = $CredentialName
                    application_instance_id = $ApplicationInstanceId 
                } | ConvertTo-Json -Depth 5
   
        
                # Create API Credential
                try {

                    $Response = Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $Payload -WhatIfBoolean $WhatIf 
                
                    if (-not $Whatif) {


                        "'{0}' API credential successfully created for '{1}' - '{2}'" -f $CredentialName, $Application.name, $Application.region_name | Write-Verbose
                        $objStatus.Status = "Complete"
                        $objStatus.Details = "API Credential successfully created"

            
                        # Save Application token
                        $Clientsecret = $Response.client_secret
                        $ClientID = $Response.client_id
    
                        $ConnectivityEndpoint = (Get-HPEGLAPICredential -Name $CredentialName).app_nbapi_endpoint
                
                
                        $ApplicationAPICredential = [PSCustomObject]@{
                            credential_name         = $CredentialName 
                            application_name        = $ApplicationName
                            region                  = $Region
                            application_instance_id = $ApplicationInstanceId
                            client_secret           = $Clientsecret 
                            client_id               = $ClientID
                            connectivity_endpoint   = $ConnectivityEndpoint
                        }
    
                        [System.Collections.ArrayList]$global:HPEGreenLakeSession.apiCredentials += @($ApplicationAPICredential)
    
                
                        if ($Location) {
                    
                            if ([System.IO.Path]::IsPathRooted($Location)) {

                                $objStatus.Location = $Location

                            }
                            else {
                                $objStatus.Location = (Resolve-Path $Location).Path

                            }

                            $_filename = "{0}_API_Credentials.json" -f $CredentialName

                            $objStatus.Filename = $_filename
    
                            $ApplicationAPICredentialJson = $ApplicationAPICredential | convertto-json -depth 99
    
                            if ($Encrypt) {
                    
                                $ApplicationAPICredentialJson  | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File  ($Location + '\' + $_filename)
                                "Encrypted file '{0}' successfully created in '{1}'" -f $_filename, ((get-Item ($Location + '\' + $_filename)).DirectoryName) | Write-Verbose
                                $objStatus.Encrypted = $True

                            }
                            else {
                        
                                $ApplicationAPICredentialJson | Out-File ($Location + '\' + $_filename)
                                "Unencrypted file '{0}' successfully created in '{1}'" -f $_filename, ((get-Item ($Location + '\' + $_filename)).DirectoryName) | Write-Verbose
                                $objStatus.Encrypted = $False
    
                            }
                        }
        
                    }

                }
                catch {

                    # if ($Response -match "Error status Code: 400") {
                    # "'{0}' API credential cannot be created because you have reached the maximum of 5 credentials" -f $CredentialName | Write-Verbose
    
                    # }

                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "API Credential cannot be created!"
                        $objStatus.Exception = $_.Exception.message 
                    }

                }

            }
        }

        [void] $NewAPICredentialStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($NewAPICredentialStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more API Credentials failed the creation attempt!"
          
            }
        }

        Return $NewAPICredentialStatus

    }
}


Function Remove-HPEGLAPICredential {
    <#
    .SYNOPSIS
    Deletes API credential of an application instance.
 
    .DESCRIPTION
    This Cmdlet deletes API client credential for an HPE GreenLake application instance.
         
    .PARAMETER Name
    Name (Case sensitve) of the API client credential to delete.
 
    .PARAMETER ApplicationInstanceId
    Application Instance ID of an application instance that will be accessible using the API credentials.
    This value can be retrieved from Get-HPEGLApplication.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
    
    .EXAMPLE
    Remove-HPEGLAPICredential -Name "Grafana-COM-AP_NorthEast"
 
    Delete the API credential "Grafana-COM-AP_NorthEast".
 
    .EXAMPLE
    Get-HPEGLAPICredential | ? credential_name -match Grafana | Remove-HPEGLAPIcredential
 
    Delete all API credentials whose name matches with Grafana (such as Grafana-COM-AP_NorthEast, Grafana-COM-EU_Central, Grafana-COM-US_West).
 
    .EXAMPLE
    Get-HPEGLAPICredential | Remove-HPEGLAPICredential
 
    Delete all API credentials.
 
    .INPUTS
    System.Collections.ArrayList
        List of API Credential(s) from Get-HPEGLAPICredential.
     
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - name of the API credential object attempted to be deleted
        * Status - status of the creation attempt (Failed for http error return; Complete if the deletion is successful)
        * Details - more information about the status
        * Exception - exception information of the error generated
 
    .LINK
    Get-HPEGLAPICredential
    New-HPEGLAPIcredential
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias ('credential_name')]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

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

    Process {

        try {
            $APIcredential = Get-HPEGLAPICredential | ? credential_name -CEQ $Name
        }
        catch {
            Throw $_
        }
   
        # Build object for the output
        $objStatus = [pscustomobject]@{
            Name      = $Name
            Status    = $Null
            Details   = $Null
            Exception = $Null
                          
        }

        if (-not $APIcredential) {
            # Must return a message if API credential not found
            "'{0}' API credential not found!" -f $name | Write-Verbose
               
            $objStatus.Status = "Failed"
            $objStatus.Details = "API credential cannot be found!"
        }
        else {

            # Delete API Credential

            $UriAdd = $ApplicationsAPICredentialsUri + "/$Name" 
     
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'DELETE' -WhatIfBoolean $WhatIf | Out-Null


                if (-not $Whatif) {

                    "'{0}' API credential successfully deleted!" -f $Name | Write-Verbose
                    $objStatus.Status = "Complete"
                    $objStatus.Details = "API Credential successfully deleted"
      
                    # Remove credential from $HPEGreenLakeSession.apiCredentials global variable
                    "Removing API credential from HPEGreenLakeSession.apiCredentials global variable" | Write-Verbose

                    $Global:HPEGreenLakeSession.apiCredentials = ($Global:HPEGreenLakeSession.apiCredentials  | Where-Object { $_.credential_name -ne $Name } )

                    Start-Sleep 1

                }
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "API Credential cannot be deleted!"
                    $objStatus.Exception = $_.Exception.message 
                }

            }
        }  
        [void] $RemoveAPICredentialStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($RemoveAPICredentialStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more API Credentials failed the deletion attempt!"
          
            }
        }

        Return $RemoveAPICredentialStatus

    }
}


############################ SUBSCRIPTION - LICENSE ###################################


Function Get-HPEGLDeviceSubscription {
    <#
    .SYNOPSIS
    Retrieve Device Subscriptions.
 
    .DESCRIPTION
    This Cmdlet returns a collection of device subscriptions or a collection of device subscriptions with the specified parameter(s).
    Subscriptions are required to assign them to devices using Set-HPEGLDeviceSubscription.
 
    .PARAMETER Available
    Optional parameter that can be used to display the subscriptions with available quantity.
 
    .PARAMETER Expired
    Optional parameter that can be used to display the subscriptions that are expired.
    
    .PARAMETER NotExpired
    Optional parameter that can be used to display the subscriptions that are not expired.
 
    .PARAMETER DeviceType
    Optional parameter that can be used to select a subscription device type such as 'ACCESS POINT', 'GATEWAY', 'SERVER', 'STORAGE', 'SWITCH'.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLDeviceSubscription
 
    Return all device subscriptions.
 
    .EXAMPLE
    Get-HPEGLDeviceSubscription -NotExpired
     
    Return all device subscriptions that are not expired.
 
    .EXAMPLE
    Get-HPEGLDeviceSubscription -NotExpired -Available
     
    Return all device subscriptions that are not expired and with available quantity.
 
    .EXAMPLE
    Get-HPEGLDeviceSubscription -Available -NotExpired -DeviceType SWITCH
 
    Return all 'Switch' subscriptions that are not expired and with available quantity.
 
    .LINK
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    Get-HPEGLDeviceAutoSubscription
    Set-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotExpired')]
        [Switch]$Available,

        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Switch]$Expired,

        [Parameter (Mandatory = $false, ParameterSetName = 'NotExpired')]
        [Switch]$NotExpired,

        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotExpired')]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('ACCESS POINT', 'GATEWAY', 'SERVER', 'STORAGE', 'SWITCH')]
        [String]$DeviceType,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Parameter(Mandatory = $False, ParameterSetName = 'NotExpired')]
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $LicenseDevicesProductTypeDeviceUri
        
    }

    Process {

        $ReturnData = @()
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Post -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }
                
        if ($Null -ne $Collection.subscriptions) {

            $CollectionList = $Collection.subscriptions 

            
            if ($Available -and $NotExpired) {
                # "Available and notexpired" -f $Null
                $CollectionList = $CollectionList | Where-Object { $_.available_quantity -ge 1 -and $_.license_state_type -ne "Ended" }
            }
            elseif ($Available -and $Expired) {    
                # "Available and expired" -f $Null
                $CollectionList = $CollectionList | Where-Object { $_.available_quantity -ge 1 -and $_.license_state_type -eq "Ended" }
            }
            elseif ($Available -and -not $Expired -and -not $NotExpired) {    
                # "Available" -f $Null
                $CollectionList = $CollectionList | Where-Object available_quantity -ge 1
            }       
            elseif ($Expired -and -not $Available -and -not $NotExpired) {    
                # "Expired" -f $Null
                $CollectionList = $CollectionList | Where-Object license_state_type -eq "Ended"   
            }  
            elseif ($NotExpired -and -not $Available -and -not $Expired) {    
                # "Not Expired" -f $Null
                $CollectionList = $CollectionList | Where-Object license_state_type -ne "Ended"
            }

            if ($DeviceType) {

                if ($DeviceType -eq "ACCESS POINT") {
                    $_DeviceType = "AP"
                }
                    
                if ($DeviceType -eq "GATEWAY") {
                    $_DeviceType = "GATEWAY"
                }
        
                if ($DeviceType -eq "SERVER") {
                    $_DeviceType = "COMPUTE"
                }
        
                if ($DeviceType -eq "STORAGE") {
                    $_DeviceType = "STORAGE"
                }
        
                if ($DeviceType -eq "SWITCH") {
                    $_DeviceType = "SWITCH"
                }

                $CollectionList = $CollectionList | Where-Object supported_device_types -match $_DeviceType
            }    

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "License.Device"    

            $ReturnData = $ReturnData | Sort-Object { $_.subscription_key }
    
            return $ReturnData 
        }
        else {

            return 
            
        }
    }
}


Function Add-HPEGLDeviceSubscription {
    <#
    .SYNOPSIS
    Add device subscription.
 
    .DESCRIPTION
    This Cmdlet adds device subscription to the HPE GreenLake account.
    Subscriptions are required to assign them to devices using Set-HPEGLDeviceSubscription.
 
    .PARAMETER SubscriptionKey
    Subscription key to add to the GreenLake account.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Add-HPEGLDeviceSubscription -SubscriptionKey 'Kxxxxxxxxxx'
 
    Add the device subscription key 'Kxxxxxxxxxx'.
     
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SubscriptionKey - Subscription key attempted to be added
        * Status - Status of the addition attempt (Failed for http error return; Complete if addition is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    Get-HPEGLDeviceAutoSubscription
    Set-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [String]$SubscriptionKey,
        
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $AddLicenseDevicesUri
        $AddDevicesSubscriptionStatus = [System.Collections.ArrayList]::new()
        
    }

    Process {

        # Build payload
        $payload = [PSCustomObject]@{
            key = $SubscriptionKey 
        } | ConvertTo-Json -Depth 5

        
        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SubscriptionKey = $SubscriptionKey
            Status          = $Null
            Details         = $Null
            Exception       = $Null
          
        }

        # Add device subscription
        try {
            Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | out-Null

            if (-not $Whatif) {

                $objStatus.Status = "Complete"
                $objStatus.Details = "Device subscription successfully added to the HPE GreenLake platform"
                
            }
            
        }
        catch {

            if (-not $Whatif) {
                $objStatus.Status = "Failed"
                $objStatus.Details = "Device subscription was not added to the HPE GreenLake platform"
                $objStatus.Exception = $_.Exception.message 
            }
        
        }    

        [void] $AddDevicesSubscriptionStatus.add($objStatus)

  
    }
    end {

        if (-not $Whatif) {

            if ($AddDevicesSubscriptionStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more device subscriptions could not be added!"
          
            }
        }

        Return $AddDevicesSubscriptionStatus

    }
      
}


Function Get-HPEGLServiceSubscription {
    <#
    .SYNOPSIS
    Retrieve Service Subscriptions.
 
    .DESCRIPTION
     This Cmdlet returns a collection of service subscriptions or a collection of service subscriptions with the specified parameter(s).
  
    .PARAMETER Available
    Optional parameter that can be used to display the subscriptions with available quantity.
 
    .PARAMETER Expired
    Optional parameter that can be used to display the subscriptions that are expired.
    
    .PARAMETER NotExpired
    Optional parameter that can be used to display the subscriptions that are not expired.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLServiceSubscription
 
    Return all service subscriptions.
 
    .EXAMPLE
    Get-HPEGLServiceSubscription -NotExpired
     
    Return all service subscriptions that are not expired.
 
    .EXAMPLE
    Get-HPEGLServiceSubscription -NotExpired -Available
     
    Return all service subscriptions that are not expired and with available quantity.
 
 
    .LINK
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    Get-HPEGLDeviceAutoSubscription
    Set-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'NotExpired')]
    Param( 
       
        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Parameter (Mandatory = $false, ParameterSetName = 'NotExpired')]
        [Switch]$Available,

        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Switch]$Expired,

        [Parameter (Mandatory = $false, ParameterSetName = 'NotExpired')]
        [Switch]$NotExpired,
   
        [Parameter (Mandatory = $false, ParameterSetName = 'Expired')]
        [Parameter(Mandatory = $False, ParameterSetName = 'NotExpired')]
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $ServiceSubscriptionsListUri + "?product_type=SERVICE"
        
    }

    Process {

        $ReturnData = @()
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method GET -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }
   
   
        
        if ($Null -ne $Collection.subscriptions) {

            $CollectionList = $Collection.subscriptions 

            
            if ($Available -and $NotExpired) { 
                # "Available and notexpired" -f $Null
                $CollectionList = $CollectionList | Where-Object { $_.available_quantity -ge 1 -and $_.license_state_type -ne "Ended" }
            
            }
            elseif ($Available -and $Expired) {    
                # "Available and expired" -f $Null
                $CollectionList = $CollectionList | Where-Object { $_.available_quantity -ge 1 -and $_.license_state_type -eq "Ended" }
            }
            elseif ($Available -and -not $Expired -and -not $NotExpired) {    
                # "Available" -f $Null
                $CollectionList = $CollectionList | Where-Object available_quantity -ge 1
            }       
            elseif ($Expired -and -not $Available -and -not $NotExpired) {    
                # "Expired" -f $Null
                $CollectionList = $CollectionList | Where-Object license_state_type -eq "Ended"   
            }  
            elseif ($NotExpired -and -not $Available -and -not $Expired) {    
                # "Not Expired" -f $Null
                $CollectionList = $CollectionList | Where-Object license_state_type -ne "Ended"
            }
  

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "License.Service"    

            $ReturnData = $ReturnData | Sort-Object { $_.subscription_key }
    
            return $ReturnData 
        }
        else {

            return 
            
        }  
    }
}


Function Get-HPEGLDeviceAutoSubscription {
    <#
    .SYNOPSIS
    Retrieve auto-subscribed device(s).
 
    .DESCRIPTION
    This Cmdlet returns the device types enabled for automatic subscription assignment.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLDeviceAutoSubscription
 
    Return all auto-subscribed device types.
 
    .LINK
    Set-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Set-HPEGLDeviceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 
        [Switch]$Whatif   
    ) 

    Begin {

        $UriAdd = $AutoLicenseDevicesUri
        
    }

    Process {

        $ReturnData = @()
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method GET -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }
  
        
        if ($Null -ne $Collection.autolicenses) {

            $CollectionList = $Collection.autolicenses | Where-Object { $_.enabled -eq $True }

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "License.Auto"    

            $ReturnData = $ReturnData | Sort-Object { $_.device_type }
    
            return $ReturnData 
        }
        else {

            return 
            
        }  
    }
}


function Set-HPEGLDeviceAutoSubscription {
    <#
    .SYNOPSIS
    Configure auto-subscribe for each supported device type.
 
    .DESCRIPTION
    This Cmdlet enables automatic assignment of subscriptions to device(s). When a subscription assigned to a device expires
    or is canceled, HPE GreenLake checks for the available subscription tokens in your account and assigns the lengthiest available
    subscription token to the device.
 
    .PARAMETER AccessPointSubscriptionTier
    Parameter to define the automatic subscription for "Access Points". The subscription level can be selected from a predefined list.
 
    .PARAMETER GatewaySubscriptionTier
    Parameter to define the automatic subscription for "Gateways". The subscription level can be selected from a predefined list.
 
    .PARAMETER ComputeSubscriptionTier
    Parameter to define the automatic subscription for "Computes". The subscription level can be selected from a predefined list.
 
    .PARAMETER SwitchSubscriptionTier
    Parameter to define the automatic subscription for "Switches". The subscription level can be selected from a predefined list.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Set-HPEGLDeviceAutoSubscription -ComputeSubscriptionTier ENHANCED
 
    Configure auto-subscribe for your Compute devices using the Enhanced subscription tier.
 
    .EXAMPLE
    Set-HPEGLDeviceAutoSubscription -SwitchSubscriptionTier ADVANCED
 
    Configure auto-subscribe for your Switch devices using the Advanced subscription tier.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * DeviceType - Type of the device to be configured for auto-subscription.
        * Status - Status of the auto-subscription assignment attempt (Failed for http error return; Complete if auto-subscription is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    Get-HPEGLDeviceSubscription
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
         
   #>


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

        [Parameter (Mandatory, ParameterSetName = "AP")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('FOUNDATION', 'ADVANCED')]
        [String]$AccessPointSubscriptionTier,

        [Parameter (Mandatory, ParameterSetName = "Gateway")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('FOUNDATION', 'ADVANCED')]
        [String]$GatewaySubscriptionTier,

        [Parameter (Mandatory, ParameterSetName = "Compute")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('STANDARD', 'ENHANCED')]
        [String]$ComputeSubscriptionTier,

        [Parameter (Mandatory, ParameterSetName = "Switch")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('FOUNDATION', 'ADVANCED')]
        [String]$SwitchSubscriptionTier,

        [Parameter (Mandatory = $False, ParameterSetName = "AP")]
        [Parameter (Mandatory = $False, ParameterSetName = "Gateway")]
        [Parameter (Mandatory = $False, ParameterSetName = "Compute")]
        [Parameter (Mandatory = $False, ParameterSetName = "Switch")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $AutoLicenseDevicesUri  
        $AutoSubscriptionStatus = [System.Collections.ArrayList]::new()

    }

    Process {
      
        if ($AccessPointSubscriptionTier -eq 'FOUNDATION' ) {
            $AutoLicenseSubscriptionTierGroup = "FOUNDATION_AP"
            $DeviceType = "AP"
        }
        elseif ($AccessPointSubscriptionTier -eq 'ADVANCED' ) {
            $AutoLicenseSubscriptionTierGroup = "ADVANCED_AP"
            $DeviceType = "AP"
        }


        if ($GatewaySubscriptionTier -eq 'FOUNDATION' ) {
            $AutoLicenseSubscriptionTierGroup = "FOUNDATION_GW"
            $DeviceType = "GATEWAY"

        }
        elseif ($GatewaySubscriptionTier -eq 'ADVANCED' ) {
            $AutoLicenseSubscriptionTierGroup = "ADVANCED_GW"
            $DeviceType = "GATEWAY"

        }


        if ($ComputeSubscriptionTier -eq 'STANDARD' ) {
            $AutoLicenseSubscriptionTierGroup = "STANDARD_COMPUTE"
            $DeviceType = "COMPUTE"

        }
        elseif ($ComputeSubscriptionTier -eq 'ENHANCED' ) {
            $AutoLicenseSubscriptionTierGroup = "ENHANCED_COMPUTE"
            $DeviceType = "COMPUTE"

        }


        if ($SwitchSubscriptionTier -eq 'FOUNDATION' ) {
            $AutoLicenseSubscriptionTierGroup = "FOUNDATION_SWITCH"
            $DeviceType = "SWITCH"

        }
        elseif ($SwitchSubscriptionTier -eq 'ADVANCED' ) {
            $AutoLicenseSubscriptionTierGroup = "ADVANCED_SWITCH"
            $DeviceType = "SWITCH"

        }



        # Build object for the output
        $objStatus = [pscustomobject]@{
 
            DeviceType = $DeviceType
            Status     = $Null
            Details    = $Null
            Exception  = $Null
                 
        }


        # Build payload
        $payload = ConvertTo-Json @(
            @{
                device_type                          = $DeviceType
                enabled                              = $True 
                auto_license_subscription_tier_group = $AutoLicenseSubscriptionTierGroup
                    
            }
        ) 
  

        # Assign Device to Application
    
        try {
            Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | Out-Null
               
            if (-not $Whatif) {

                $objStatus.Status = "Complete"
                $objStatus.Details = "Automatic assignment of subscriptions to $DeviceType successfully set!"
                

            }
        }
        catch {
            if (-not $Whatif) {
                $objStatus.Status = "Failed"
                $objStatus.Details = "Automatic assignment of subscriptions to $DeviceType cannot be set!"
                $objStatus.Exception = $_.Exception.message 
            }
        }
        

        [void] $AutoSubscriptionStatus.add($objStatus)
    }

    end {

        if (-not $Whatif) {

            if ($AutoSubscriptionStatus | Where-Object { $_.Status -eq "Failed" }) {
 
                write-error "$DeviceType automatic assignment of subscription configuration failure!"
         
            }
        }

        Return $AutoSubscriptionStatus

    }
}


function Remove-HPEGLDeviceAutoSubscription {
    <#
    .SYNOPSIS
    Delete auto-subscribe for each supported device type.
 
    .DESCRIPTION
    This Cmdlet disables automatic assignment of subscriptions to device(s).
 
    .PARAMETER AccessPoint
    Parameter to delete the automatic subscription for "Access Points".
 
    .PARAMETER Gateway
    Parameter to delete the automatic subscription for "Gateways".
 
    .PARAMETER Compute
    Parameter to delete the automatic subscription for "Computes".
 
    .PARAMETER Switch
    Parameter to delete the automatic subscription for "Switches".
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Remove-HPEGLDeviceAutoSubscription -Compute
 
    Remove auto-subscribe for Compute devices.
 
    .EXAMPLE
    Remove-HPEGLDeviceAutoSubscription -Switch
 
    Remove auto-subscribe for Switch devices.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
     
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * DeviceType - Type of the device to be removed from auto-subscription.
        * Status - Status of the auto-subscription un-assignment attempt (Failed for http error return; Complete if successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLDeviceAutoSubscription
    Set-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    Get-HPEGLDeviceSubscription
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Remove-HPEGLDeviceSubscription
    [${Global:HPEGreenLakeSession}]
         
   #>


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

        [Parameter (Mandatory, ParameterSetName = "AP")]
        [Switch]$AccessPoint,

        [Parameter (Mandatory, ParameterSetName = "Gateway")]
        [Switch]$Gateway,

        [Parameter (Mandatory, ParameterSetName = "Compute")]
        [Switch]$Compute,

        [Parameter (Mandatory, ParameterSetName = "Switch")]
        [Switch]$Switch,

        [Parameter (Mandatory = $False, ParameterSetName = "AP")]
        [Parameter (Mandatory = $False, ParameterSetName = "Gateway")]
        [Parameter (Mandatory = $False, ParameterSetName = "Compute")]
        [Parameter (Mandatory = $False, ParameterSetName = "Switch")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $AutoLicenseDevicesUri  
        $AutoSubscriptionStatus = [System.Collections.ArrayList]::new()

    }

    Process {
      
        if ($AccessPoint ) {
            $DeviceType = "AP"
        }

        if ($Gateway) {
            $DeviceType = "GATEWAY"

        }

        if ($Compute ) {
            $DeviceType = "COMPUTE"

        }

        if ($Switch) {
            $DeviceType = "SWITCH"

        }

        try {
            $AutoLicenseSubscriptionTierGroup = (Get-HPEGLDeviceAutoSubscription | Where-Object { $_.device_type -eq $DeviceType }).auto_license_subscription_tier_group
        }
        catch {
            Throw $_
        }

        if ($AutoLicenseSubscriptionTierGroup) {

            # Build object for the output
            $objStatus = [pscustomobject]@{
 
                DeviceType = $DeviceType
                Status     = $Null
                Details    = $Null
                Exception  = $Null
                 
            }


            # Build payload
            $payload = ConvertTo-Json @(
                @{
                    device_type                          = $DeviceType
                    enabled                              = $False 
                    auto_license_subscription_tier_group = $AutoLicenseSubscriptionTierGroup
                    
                }
            ) 
  

            # Assign Device to Application
    
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | Out-Null
               
                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Automatic assignment of subscriptions to $DeviceType successfully set!"
                

                }
            }
            catch {
                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Automatic assignment of subscriptions to $DeviceType cannot be set!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
        }

        else {
           
            $objStatus.Status = "Failed"
            $objStatus.Details = "Automatic subscription cannot be found!"
           
        }

        [void] $AutoSubscriptionStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($AutoSubscriptionStatus | Where-Object { $_.Status -eq "Failed" }) {
 
                write-error "$DeviceType automatic assignment of subscription configuration failure!"
         
            }
        }

        Return $AutoSubscriptionStatus

    }
}


Function Set-HPEGLDeviceSubscription {
    <#
    .SYNOPSIS
    Apply a subscription key to device(s).
 
    .DESCRIPTION
    This Cmdlet applies a license subscription key to device(s).
         
    .PARAMETER SerialNumber
    Serial number of the device to which a subscription key is to be applied.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER SubscriptionKey
    Subscription key of a VALID AND NOT EXPIRED license.
    This value can be retrieved from Get-HPEGLlicense -Available -NotExpired
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLDeviceSubscription -Available -NotExpired | select -First 1 | Set-HPEGLDeviceSubscription -SerialNumber CNX2380BLC
 
    Apply a subscription key to the device with the license provided in the pipeline.
 
    .EXAMPLE
    $SubscriptionKey = (Get-HPEGLDeviceSubscription -Available -NotExpired).subscription_key
 
    Set-HPEGLDeviceSubscription -SerialNumber CNX2380BLC -SubscriptionKey $SubscriptionKey
 
    Apply a subscription key to the device with the serial number CNX2380BLC.
 
    .EXAMPLE
    $SubscriptionKey = (Get-HPEGLDeviceSubscription -Available -NotExpired).subscription_key
 
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'CNX2380BLC' },
        [PSCustomObject]@{SerialNumber = 'MXQ73200W1' }
    )
 
    $devices | Set-HPEGLDeviceSubscription -SubscriptionKey $SubscriptionKey
 
    Apply a subscription key to devices defined in the $devices array.
 
    .EXAMPLE
    $SubscriptionKey = (Get-HPEGLDeviceSubscription -Available -NotExpired -DeviceType SWITCH | ? product_description -match 83).subscription_key
    Import-Csv Tests/Network_Devices.csv | Set-HPEGLDeviceSubscription -SubscriptionKey $SubscriptionKey
 
    Apply a subscription key to devices listed in a csv file containing at least a SerialNumber column.
 
    .INPUTS
    System.Collections.ArrayList
        - List of device(s) from Get-HPEGLDevice.
        or
        - A subscription key from Get-HPEGLDeviceSubscription
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device to be assigned to an application instance.
        * Status - Status of the assignment attempt (Failed for http error return; Complete if assignment is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice -RequireAssignment
    Get-HPEGLDeviceSubscription
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Remove-HPEGLDeviceSubscription
    Set-HPEGLDeviceAutoSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('subscription_key')]
        [String]$SubscriptionKey,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $LicenseDevicesUri  
        $SubscriptionDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {
         
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                  
        }

        if (-not $device) {
            # Must return a message if device not found
            "{0}: Device not found so subscription key cannot be attached." -f $SerialNumber  | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif ( $device.subscription_key ) {
            "{0}: Device already licensed with a subscription key." -f $SerialNumber  | Write-Verbose
            $objStatus.Status = "Warning"
            $objStatus.Details = "Device already licensed with a subscription key!"
        }
        elseif (-not $device.application_name) {
            # Must return a message if the device is not assigned to an application.
            "{0}: Device not assigned to an application! Use first Set-HPEGLDeviceApplication." -f $SerialNumber  | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device not assigned to an application! Use first Set-HPEGLDeviceApplication!"
        }
        else {
        

            $PartNumber = $device | % part_number
            $DeviceType = $device | % device_type


            # Build payload
            $payload = ConvertTo-Json @(
                @{
                    serial_number    = $SerialNumber
                    part_number      = $PartNumber 
                    device_type      = $DeviceType
                    subscription_key = $SubscriptionKey
                }
            ) 
   

            # Assign Device to Application
     
            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | Out-Null
                
                if (-not $Whatif) {

                    $License = Get-HPEGLDeviceSubscription | ? { $_.subscription_key -eq $SubscriptionKey }
                    $LicenseName = $License.product_description
                    $LicenseDescription = $License.subscription_tier_description

                    "{0}: Device successfully attached to subscription key: {1}" -f $SerialNumber, $LicenseName + " / " + $LicenseDescription | Write-Verbose
                    
                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully attached to subscription key!"

                }
            }
            catch {
                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device cannot be attached to subscription key!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
        }

        [void] $SubscriptionDevicesStatus.add($objStatus)
    }

    end {

        if (-not $Whatif) {

            if ($SubscriptionDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the assignment attempt!"
          
            }
        }

        Return $SubscriptionDevicesStatus

    }
}


Function Remove-HPEGLDeviceSubscription {
    <#
    .SYNOPSIS
    Detach a subscription key from device(s).
 
    .DESCRIPTION
    This Cmdlet detaches a Compute Ops Management license subscription key to device(s).
 
    .PARAMETER SerialNumber
    Serial number of the device to which a subscription key must be detached.
    This value can be retrieved from Get-HPEGLDevice.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
    
    .EXAMPLE
    Remove-HPEGLDeviceSubscription -SerialNumber CNX2380BLC
 
    Detach a subscription key from a device.
 
    .EXAMPLE
    $devices = @(
        [PSCustomObject]@{SerialNumber = 'CNX2380BLC' },
        [PSCustomObject]@{SerialNumber = 'MXQ73200W1' }
    )
 
    $devices | Remove-HPEGLDeviceSubscription
 
    Detach subscription keys from devices defined in the $devices array.
 
    .EXAMPLE
    Import-Csv Tests/Network_Devices.csv | Remove-HPEGLDeviceSubscription
 
    Detach subscription keys from devices listed in a csv file containing at least a SerialNumber column.
 
    .INPUTS
    System.Collections.ArrayList
        List of device(s) from Get-HPEGLDevice.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * SerialNumber - Serial number of the device to be assigned to an application instance.
        * Status - Status of the assignment attempt (Failed for http error return; Complete if assignment is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLdevice -RequireAssignment
    Get-HPEGLDeviceSubscription
    Add-HPEGLDeviceSubscription
    Get-HPEGLServiceSubscription
    Set-HPEGLDeviceSubscription
    Set-HPEGLDeviceAutoSubscription
    Remove-HPEGLDeviceAutoSubscription
    [${Global:HPEGreenLakeSession}]
     
   #>


    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
 
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [Alias('serial_number')]
        [String]$SerialNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $LicenseDevicesUri  
        $RemoveSubscriptionDevicesStatus = [System.Collections.ArrayList]::new()

    }

    Process {
         
        try {
            $device = Get-HPEGLdevice -SearchString $SerialNumber -ErrorAction SilentlyContinue
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            SerialNumber = $SerialNumber
            Status       = $Null
            Details      = $Null
            Exception    = $Null
                      
        }
    
        if (-not $device) {
            # Must return a message if device not found
            "{0}: Device not found so subscription key cannot be detached." -f $SerialNumber | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device cannot be found on the HPE GreenLake platform!"
        }
        elseif ( -not $device.subscription_key) {
            "{0}: Device is not licensed with a subscription key." -f $SerialNumber | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "Device is not licensed with a subscription key!"
        }
        else {


            $PartNumber = $device | % part_number
            $DeviceType = $device | % device_type


            # Build payload
            $payload = ConvertTo-Json @(
                @{
                    serial_number = $SerialNumber
                    part_number   = $PartNumber 
                    device_type   = $DeviceType
                }
            ) 
   
       
            # Unassign Device from Application
     
            try {
                
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'DELETE' -body $payload -WhatIfBoolean $WhatIf | Out-Null

                if (-not $Whatif) {

                    "{0}: Device successfully detached from subscription key." -f $SerialNumber | Write-Verbose

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Device successfully detached from subscription key!"

                }

            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Device cannot be detached from subscription key!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
                            
        }
        [void] $RemoveSubscriptionDevicesStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($RemoveSubscriptionDevicesStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more devices failed the un-assignment attempt!"
          
            }
        }

        Return $RemoveSubscriptionDevicesStatus

    }
}


############################ USER - ROLES - PERMISSIONS ###################################


Function Get-HPEGLUser {
    <#
    .SYNOPSIS
    Retrieve user resource(s).
 
    .DESCRIPTION
    This Cmdlet returns a collection of user resources or user statistics. Roles and permissions can also be retrieved.
 
    .PARAMETER FirstName
    Specifies the first name associated with resources (case-sensitive).
 
    .PARAMETER LastName
    Specifies the last name associated with resources (case-sensitive).
   
    .PARAMETER Email
    Specifies the email associated with resources.
 
    .PARAMETER Unverified
    Optional parameter that can be used to display unverified users.
 
    .PARAMETER Stats
    Optional parameter that can be used to display user statistics.
 
    .PARAMETER Roles
    This option can be used to see the roles assigned to a user.
 
    .PARAMETER Permissions
    This option can be used to see the permissions assigned to a user.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLUser -FirstName Eddy
 
    Return the user resource with first name "Eddy".
 
    .EXAMPLE
    Get-HPEGLUser -Stats
 
    Return user statistics.
 
    .EXAMPLE
    Get-HPEGLUser -Permissions -FirstName Albert -LastName Einstein
 
    Return Albert Einstein permissions.
 
    .EXAMPLE
    Get-HPEGLUser -Roles -FirstName Albert -LastName Einstein
 
    Return Albert Einstein roles.
 
    .LINK
    Remove-HPEGLUser
    Send-HPEGLUserInvitation
    Get-HPEGLRole
    Get-HPEGLUserRole
    Set-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    Get-HPEGLResourceRestrictionPolicy
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Roles')]
        [Parameter (Mandatory, ParameterSetName = 'Permissions')]
        [Parameter (Mandatory, ParameterSetName = 'Activity')]
        [ValidateNotNullOrEmpty()]
        [String]$FirstName,  

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ParameterSetName = 'Roles')]
        [Parameter (Mandatory, ParameterSetName = 'Permissions')]
        [Parameter (Mandatory, ParameterSetName = 'Activity')]
        [ValidateNotNullOrEmpty()]
        [String]$LastName,  
        
        [Parameter (Mandatory, ParameterSetName = 'Email')]
        [Parameter (Mandatory, ParameterSetName = 'EmailRoles')]
        [Parameter (Mandatory, ParameterSetName = 'EmailPermissions')]
        [Parameter (Mandatory, ParameterSetName = 'EmailActivity')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,  

        [Parameter(Mandatory, ParameterSetName = 'Unverified')]
        [Switch]$Unverified,

        [Parameter(Mandatory, ParameterSetName = 'Stats')]
        [Switch]$Stats,

        [Parameter (Mandatory, ParameterSetName = 'Roles')]
        [Parameter (Mandatory, ParameterSetName = 'EmailRoles')]
        [Switch]$Roles,

        [Parameter (Mandatory, ParameterSetName = 'Permissions')]
        [Parameter (Mandatory, ParameterSetName = 'EmailPermissions')]
        [Switch]$Permissions,
        
        [Parameter (Mandatory, ParameterSetName = 'EmailActivity')]
        [Parameter (Mandatory, ParameterSetName = 'Activity')]
        [Switch]$Activity,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Unverified')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Roles')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Permissions')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Stats')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Email')]
        [Parameter (Mandatory = $false, ParameterSetName = 'EmailRoles')]
        [Parameter (Mandatory = $false, ParameterSetName = 'EmailPermissions')]
        [Parameter (Mandatory = $false, ParameterSetName = 'EmailActivity')]
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $UsersUri + "?limit=500&include_unverified=true"

        $query = @()

        if ($FirstName) {
            $query += "first_name=$FirstName"
        }

        if ($LastName) {
            $query += "last_name=$LastName"
        }

        if ($Stats) {
            $UriAdd = $UsersStatsUri
        }
        
        if ($query) {
            foreach ($Item in $query) {
                if ($query.count -eq 1) {
                    $queries = $Item
                }
                else {
                    $queries += ($Item + "&")
                }

                $UriAdd = $UriAdd + "&" + $queries

            }
            
        }
        
    }

    Process {
       
        $ReturnData = @()

   
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }

        if ($Stats) {

            $ReturnData = Invoke-RepackageObjectWithType -RawObject $Collection -ObjectName "User.stat"         
            return $ReturnData 

        }
        else {

            if ($Null -ne $Collection.users) {
                
                $CollectionList = $Collection.users 

                if ($Email) {
                    $CollectionList = $CollectionList | ? { $_.contact.email -eq $email }
                }

                if ($Unverified) {
                    $CollectionList = $CollectionList | ? { $_.user_status -eq "UNVERIFIED" }
                }

                if ($Roles) {

                    try {
                        $UserRoles = Get-HPEGLUserRole -Email $Email 
                        return $UserRoles 
                        
                    }
                    catch {
                        Throw $_
                    }
                   

                }
                elseif ($Permissions) {

                    $PermissionsList = @()

                    if ($Email) {
                        $CollectionList = $CollectionList | ? { $_.contact.email -eq $email }
                    }

                    $UserRoles = $CollectionList.user_role
                                       
                    foreach ($UserRole in $UserRoles) {

                        $Rolename = $UserRole | % role_name
                        $AppName = $UserRole | % application_name
                        $AppID = $UserRole | % application_id
                        
                        "{0}: {1} role" -f $AppName, $Rolename | Write-Verbose

                        try {
                            $ResourcePolicies = Get-HPEGLRole | ? { $_.application_id -eq $Appid -and $_.name -eq $RoleName } | % resource_policies

                            foreach ($ResourcePolicy in $ResourcePolicies) {

                                $ReturnData = $ResourcePolicy |  Select-Object  @{N = "Application"; E = { $AppName } }, @{N = "Resource"; E = { $_.resource.matcher } }, @{N = "Permissions"; E = { $_.permissions.slug } }, @{N = "Effect"; E = { $_.effect } }

                                $PermissionsList += $ReturnData 
                            }
                        }
                        catch {
                            throw $_
                        }

                     
                       
                    }

                    return $PermissionsList


                }
                else {

                    $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "User"         
                    $ReturnData = $ReturnData | Sort-Object { $_.contact.last_name }
           

                    if ($Activity) {

                        $SearchString = $ReturnData.contact.Email
                        $ReturnData = Get-HPEGLAuditLog -SearchString $SearchString -Limit 100
                        return $ReturnData 

                    }
                    else {
                        return $ReturnData 
                        
                    }

                }
    
            }
            else {

                return 
                
            }
        }
        
    }
}


Function Send-HPEGLUserInvitation {
    <#
    .SYNOPSIS
    Send an invite.
 
    .DESCRIPTION
    This cmdlet can be used by account administrators to invite team members to join HPE GreenLake.
    An email notification is sent to the specified user's address and the user is added to the team members using the assigned role.
 
    .PARAMETER Email
    Specifies the email associated with resources.
 
    .PARAMETER Role
    Specifies the HPE GreenLake role to assign to the user.
    The predefined roles are as follows:
        * Account Administrator
        * Observer
        * Operator
        * Orders Administrator
        * Orders Observer
        * Orders Operator
 
    .PARAMETER SenderEmail
    This option can be used to specify the email of the sender of this invitation.
 
    .PARAMETER Resend
    The Resend switch can be used to send a new invitation to an existing user.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Send-HPEGLUserInvitation -Email leonhard.euler@mathematician.edu -Role 'Orders Operator' -SenderEmail bernhard.riemann@mathematician.edu
 
    Leonhard Euler is added to the team members as an Order Operator and an email notification is sent to the specified email address.
    Bernhard Riemann is recorded as the administrator who added Leonhard Euler to the group.
 
    .EXAMPLE
    Send-HPEGLUserInvitation -Email leonhard.euler@mathematician.com -Resend
 
    A new invitation is sent to Leonhard Euler.
 
    .EXAMPLE
    'leonhard.euler@mathematician.com','bernhard.riemann@mathematician.edu' | Send-HPEGLUserInvitation -Role 'Account Administrator'
 
    Leonhard Euler and Bernhard Riemann are added to the team members as administrators and email notifications are sent to them.
 
    .INPUTS
    System.Collections.ArrayList
        List of email addresses.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Email - Email of the user
        * Status - Status of the join group/email notification attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLUser
    Remove-HPEGLUser
    Get-HPEGLRole
    Get-HPEGLUserRole
    Set-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    Get-HPEGLResourceRestrictionPolicy
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Resend')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,  

        [Parameter (Mandatory, ParameterSetName = 'Default')]
        [ValidateSet('Account Administrator', 'Observer', 'Operator', 'Orders Administrator', 'Orders Observer', 'Orders Operator')]
        [String]$Role,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$SenderEmail,  

        [Parameter (Mandatory = $false, ParameterSetName = 'Resend')]
        [Switch]$Resend,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Resend')]
        [Switch]$Whatif
       
    ) 

    Begin {

        if ($Resend) {
            # Resend an invite
            $UriAdd = $ReInviteUserUri 
        }
        else {
            $UriAdd = $InviteUserUri
        }
        
        $UserInvitationStatus = [System.Collections.ArrayList]::new()

    }

    Process {
            
        
        try {
            $User = Get-HPEGLUser -Email $Email
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Email     = $Email
            Status    = $Null
            Details   = $Null
            Exception = $Null
                  
        }

        if ($Resend) {

            if (-not $User) {
                # Must return a message if account not found
                "{0}: User account does not exist!" -f $Email | Write-Verbose
                $objStatus.Status = "Failed"
                $objStatus.Details = "User account does not exist!"
            }
            else {
             
                # Create payload
                $Payload = [PSCustomObject]@{
                    usernames = @($Email)
            
                } | ConvertTo-Json      

                # Resend invitation
                
                try {
                    [array]$Collection = Invoke-HPEGLWebRequest -Method Post -UriAdd $UriAdd -Body $Payload -whatifBoolean $WhatIf

                    if (-not $Whatif) {
                        $objStatus.Status = "Complete"
                        $objStatus.Details = "Invitation resent!"
                    }

                    if ($Collection.message) {
                        $Collection.message  | Write-Verbose
                    }
                }
                catch {
            
                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Invitation resending failure!"
                        $objStatus.Exception = $_.Exception.message 
                    }
                }
           
            }
        }
        else {

            if ($User) {
                # Must return a message if account found
                "{0}: User account has already been invited!" -f $Email | Write-Verbose
                $objStatus.Status = "Warning"
                $objStatus.Details = "User account has already been invited!"
            }
            else {

                try {
                    $AppRole = Get-HPEGLRole -HPEGreenLake
                }
                catch {
                    Throw $_
                }
        
            
                $RoleSlug = $AppRole | ? name -eq $Role | % slug
 

                # Create payload
                $Payload = [PSCustomObject]@{
                    user_names          = @($Email)
                    contact_information = if ($SenderEmail) { $SenderEmail } else { $Null }
                    roles               = @(
                        @{ role          = @{
                                application_id = "00000000-0000-0000-0000-000000000000"
                                slug           = $RoleSlug 
                            }
                            access_rules = $Null
                        })
                } | ConvertTo-Json -Depth 5
                    
        
                # Send invitation
                
                try {
                    [array]$Collection = Invoke-HPEGLWebRequest -Method Post -UriAdd $UriAdd -Body $Payload -whatifBoolean $WhatIf
        
                    if (-not $Whatif) {
                        $objStatus.Status = "Complete"
                        $objStatus.Details = "Invitation sent!"
                    }
        
                    if ($Collection.message) {
                        $Collection.message  | Write-Verbose
                    }
                }
                catch {
                    
                    if (-not $Whatif) {
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Invitation sending failure!"
                        $objStatus.Exception = $_.Exception.message 
                    }
                }
            }
        }     

        [void] $UserInvitationStatus.add($objStatus)
    }

    end {

        if (-not $Whatif) {

            if ($UserInvitationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more failures to send an invitation!"
          
            }
        }

        Return $UserInvitationStatus

    }
}


Function Remove-HPEGLUser {
    <#
    .SYNOPSIS
    Delete a user from the HPE GreenLake console.
 
    .DESCRIPTION
    This cmdlet can be used by account administrators to delete a user account of the HPE GreenLake platform.
     
    .PARAMETER Email
    Specifies the email address of the user to delete.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Remove-HPEGLUser -Email johanncarlfriedrich.gauss@mathematician.edu
     
    Delete the user Johann Carl Friedrich Gauss.
 
    .INPUTS
    System.Collections.ArrayList
        List of email addresses.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Email - Email of the user
        * Status - Status of the removal attempt (Failed for http error return; Complete if successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLUser
    Send-HPEGLUserInvitation
    Get-HPEGLRole
    Get-HPEGLUserRole
    Set-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    Get-HPEGLResourceRestrictionPolicy
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,  

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif
       
    ) 

    Begin {
       
        $UriAdd = $UsersUri
        $UserRemovalStatus = [System.Collections.ArrayList]::new()
        
    }

    Process {    
        
        try {
            $User = Get-HPEGLUser -Email $Email
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Email     = $Email
            Status    = $Null
            Details   = $Null
            Exception = $Null
              
        }
        
        if (-not $User) {
            # Must return a message if account found
            "{0}: User account not found!" -f $Email | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "User account not found!"
        }
        else {
      
            # Create payload
            $Payload = [PSCustomObject]@{
                usernames = @($Email)
                
            } | ConvertTo-Json             
    

            # Remove user
        
            try {
                [array]$Collection = Invoke-HPEGLWebRequest -Method Delete -UriAdd $UriAdd -Body $Payload -whatifBoolean $WhatIf

                if (-not $Whatif) {
                    $objStatus.Status = "Complete"
                    $objStatus.Details = "User account removed!"
                }

                if ($Collection.message) {
                    $Collection.message  | Write-Verbose
                }

            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "User account removal failure!"
                    $objStatus.Exception = $_.Exception.message 
                }
            }
        }

        [void] $UserRemovalStatus.add($objStatus)

    }
    end {

        if (-not $Whatif) {

            if ($UserRemovalStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more user account failed the deletion attempt!"
          
            }
        }

        Return $UserRemovalStatus

    }
}


Function Get-HPEGLRole {
    <#
    .SYNOPSIS
    View application roles.
 
    .DESCRIPTION
    This Cmdlet returns the application roles.
    Roles are groups of permissions that grant access to users.
 
    .PARAMETER ApplicationName
    Name of the application (can be retrieved using Get-HPEGLApplication).
     
    .PARAMETER ArubaCentral
    Optional parameter to display the roles of the Aruba Central application.
 
    .PARAMETER ComputeOpsManagement
    Optional parameter to display the roles of the Compute Ops Management application.
 
    .PARAMETER DataServicesCloudConsole
    Optional parameter to display a specific role of the Data Services Cloud Console application.
 
    .PARAMETER HPEGreenLake
    Optional parameter to display the roles of the HPE GreenLake application.
 
    .PARAMETER ArubaCentralRole
    Optional parameter to display a specific role of the Aruba Central application.
    The predefined roles are as follows:
        * Aruba Central Administrator
        * Aruba Central Guest Operator
        * Aruba Central Operator
        * Aruba Central view edit role
        * Aruba Central View Only
        * Netlnsight Campus Admin
        * Netlnsight Campus Viewonly
 
    .PARAMETER ComputeOpsManagementRole
    Optional parameter to display a specific role of the Compute Ops Management application.
    The predefined roles are as follows:
        * Administrator
        * Observer
        * Operator
 
    .PARAMETER DataServicesCloudConsoleRole
    Optional parameter to display a specific role of the Data Services Cloud Console application.
    The predefined roles are as follows:
        * Administrator
        * Backup and Recovery Administrator
        * Backup and Recovery Operator
        * Data Ops Manager Administrator
        * Data Ops Manager Operator
        * Disaster Recovery Admin
        * Read only
 
    .PARAMETER HPEGreenLakeRole
    Optional parameter to display a specific role of the HPE GreenLake application.
    The predefined roles are as follows:
        * Account Administrator
        * Observer
        * Operator
        * Orders Administrator
        * Orders Observer
        * Orders Operator
 
    .PARAMETER AssignedUsers
    The AssignedUsers directive will show you the users assigned to the role name.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLRole
 
    Return the application roles in your HPE GreenLake account.
 
    .EXAMPLE
    Get-HPEGLRole -ArubaCentral
 
    Return the roles for the Aruba Central application instances in your HPE GreenLake account.
 
    .EXAMPLE
    Get-HPEGLRole -ApplicationName "Project Denali"
 
    Return the roles for the Project Denali application instances in your HPE GreenLake account.
 
    .EXAMPLE
    Get-HPEGLRole -ApplicationName "Project Denali" -ApplicationRole Operator
     
    Return the Operator role information for the Project Denali application.
 
    .EXAMPLE
    Get-HPEGLRole -ComputeOpsManagementRole Administrator
 
    Return the Administrator role information for the Compute Ops Management application.
            
    .EXAMPLE
    Get-HPEGLRole -ComputeOpsManagementRole Administrator -AssignedUsers
 
    Return the users assigned to the Administrator role of the Compute Ops Management application.
 
    .LINK
    Get-HPEGLUser
    Remove-HPEGLUser
    Send-HPEGLUserInvitation
    Get-HPEGLUserRole
    Set-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    Get-HPEGLResourceRestrictionPolicy
    [${Global:HPEGreenLakeSession}]
     
   #>

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

       
        [Parameter (Mandatory, ParameterSetName = 'ApplicationName')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ApplicationName')]
        [String]$ApplicationName,
    
        [Parameter (Mandatory = $False, ParameterSetName = 'ApplicationName')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ApplicationName')]
        [String]$ApplicationRole,

        [Parameter (Mandatory = $false, ParameterSetName = 'ArubaCentral')]
        [Switch]$ArubaCentral,

        [Parameter (Mandatory = $false, ParameterSetName = 'ArubaCentralRole')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ArubaCentral')]
        [ValidateSet ('Aruba Central Administrator', 'Aruba Central Guest Operator', 'Aruba Central Operator', 'Aruba Central view edit role', 'Aruba Central View Only', 'Netlnsight Campus Admin', 'Netlnsight Campus Viewonly')]
        [String]$ArubaCentralRole,

        [Parameter (Mandatory = $false, ParameterSetName = 'ComputeOpsManagement')]
        [Switch]$ComputeOpsManagement,

        [Parameter (Mandatory = $false, ParameterSetName = 'ComputeOpsManagementRole')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ComputeOpsManagement')]
        [ValidateSet ('Administrator', 'Observer', 'Operator')]
        [String]$ComputeOpsManagementRole,

        [Parameter (Mandatory = $false, ParameterSetName = 'DataServicesCloudConsole')]
        [Switch]$DataServicesCloudConsole,

        [Parameter (Mandatory = $false, ParameterSetName = 'DataServicesCloudConsoleRole')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-DataServicesCloudConsole')]
        [ValidateSet ('Administrator', 'Backup and Recovery Administrator', 'Backup and Recovery Operator', 'Data Ops Manager Administrator', 'Data Ops Manager Operator', 'Disaster Recovery Admin', 'Read only')]
        [String]$DataServicesCloudConsoleRole,

        [Parameter (Mandatory = $false, ParameterSetName = 'HPEGreenLake')]
        [Switch]$HPEGreenLake,

        [Parameter (Mandatory = $false, ParameterSetName = 'HPEGreenLakeRole')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-HPEGreenLake')]
        [ValidateSet ('Account Administrator', 'Observer', 'Operator', 'Orders Administrator', 'Orders Observer', 'Orders Operator')]
        [String]$HPEGreenLakeRole,

        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ApplicationName')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ArubaCentral')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-ComputeOpsManagement')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-DataServicesCloudConsole')]
        [Parameter (Mandatory, ParameterSetName = 'AssignedUsers-HPEGreenLake')]
        [Switch]$AssignedUsers,

        [Parameter (Mandatory = $false, ParameterSetName = 'ApplicationName')]
        [Parameter (Mandatory = $false, ParameterSetName = 'ArubaCentral')]
        [Parameter (Mandatory = $false, ParameterSetName = 'ArubaCentralRole')]
        [Parameter (Mandatory = $false, ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (Mandatory = $false, ParameterSetName = 'ComputeOpsManagementRole')]
        [Parameter (Mandatory = $false, ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (Mandatory = $false, ParameterSetName = 'DataServicesCloudConsoleRole')]
        [Parameter (Mandatory = $false, ParameterSetName = 'HPEGreenLake')]
        [Parameter (Mandatory = $false, ParameterSetName = 'HPEGreenLakeRole')]
        [Parameter (Mandatory = $false, ParameterSetName = 'AssignedUsers-ArubaCentral')]
        [Parameter (Mandatory = $false, ParameterSetName = 'AssignedUsers-ComputeOpsManagement')]
        [Parameter (Mandatory = $false, ParameterSetName = 'AssignedUsers-DataServicesCloudConsole')]
        [Parameter (Mandatory = $false, ParameterSetName = 'AssignedUsers-HPEGreenLake')]
        [Switch]$Whatif


 
    ) 

    Begin {

        $UriAdd = $UsersRolesUri + $HPEGreenLakeSession.customerId + "/roles"
        
    }

    Process {

        if ($ApplicationName) {
            
            try {
                $Application = Get-HPEGLApplication -Name $ApplicationName 
                
            }
            catch {    
                Throw $_
    
            }
    
            if (-not $Application -and $ApplicationName -ne "HPE GreenLake platform") {
                "{0}: Application not found on the HPE GreenLake platform!" -f $ApplicationName | Write-Verbose
                Throw "Error! Application name not found!"
            }
            else {
                
                $ReturnData = @()
        
                try {
                    [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
                }
                catch {
                    Throw $_
                }

                if ($Null -ne $Collection.roles) {

                    $CollectionList = $Collection.roles  | ? application_name -eq $Applicationname       
                    
                    if ($ApplicationRole) {
                    
                        $CollectionList = $CollectionList | ? name -eq $ApplicationRole
                    }
                                  
                    if ($AssignedUsers) {

                        $ApplicationID = $CollectionList.application_id
                        $Slug = $CollectionList.slug
    
                        $UriAdd = "/authorization/ui/v1/customers/" + $HPEGreenLakeSession.customerId + "/applications/" + $ApplicationID + "/roles/" + $Slug + "/user_assignments"
    
                        try {
                            [array]$UserCollection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
                        }
                        catch {
                            Throw $_
                        }

                        if ($Null -ne $UserCollection.users) {
            
                            $ReturnData = Invoke-RepackageObjectWithType -RawObject $UserCollection.users -ObjectName "User.Role.Assigned.Users"    
                            $ReturnData = $UserCollection.users | Sort-Object { $_.email }

                            return $ReturnData 

                                        
                        }
                        else {
                            return   
                        }
                    }

            
                    $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Role"    

                    $ReturnData = $ReturnData | Sort-Object { $_.application_name, $_.name }

                    return $ReturnData 
                }
                else {

                    return
            
                }
        
            }           
        }
        else {

            $ReturnData = @()
        
            try {
                [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
            }
            catch {
                Throw $_
            }
        
   
            if ($Null -ne $Collection.roles) {

                $CollectionList = $Collection.roles 

                if ($ComputeOpsManagement) {
                    $application = "Compute Ops Management"
                }
                elseif ($DataServicesCloudConsole) { 
                    $application = "Data Services Cloud Console" 
                }
                elseif ($ArubaCentral) { 
                    $application = "Aruba Central" 
                }
                elseif ($HPEGreenLake) { 
                    # $application = "Common Cloud Service"
                    $application = "HPE GreenLake platform"

                }


                if ($ComputeOpsManagementRole) {
                    $application = "Compute Ops Management"
                }
                elseif ($DataServicesCloudConsoleRole) { 
                    $application = "Data Services Cloud Console" 
                }
                elseif ($ArubaCentralRole) { 
                    $application = "Aruba Central" 
                }
                elseif ($HPEGreenLakeRole) { 
                    # $application = "Common Cloud Service"
                    $application = "HPE GreenLake platform"
                }


                if ($Application) {

                    $CollectionList = $CollectionList | ? application_name -eq $Application

                    if ($ArubaCentralRole) {
                    
                        $CollectionList = $CollectionList | ? name -eq $ArubaCentralRole
                    }
                    if ($ComputeOpsManagementRole) {
                    
                        $CollectionList = $CollectionList | ? name -eq $ComputeOpsManagementRole
                    } 
                    
                    if ($DataServicesCloudConsoleRole) {
                    
                        $CollectionList = $CollectionList  | ? name -eq $DataServicesCloudConsoleRole
                    }
                    if ($HPEGreenLakeRole) {

                        $CollectionList = $CollectionList  | ? name -eq $HPEGreenLakeRole
                    }
                        
                }
                     
                if ($AssignedUsers) {

                    $ApplicationID = $CollectionList.application_id
                    $Slug = $CollectionList.slug
    
                    $UriAdd = "/authorization/ui/v1/customers/" + $HPEGreenLakeSession.customerId + "/applications/" + $ApplicationID + "/roles/" + $Slug + "/user_assignments"
    
                    try {
                        [array]$UserCollection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
                    }
                    catch {
                        Throw $_
                    }

                    if ($Null -ne $UserCollection.users) {
            
                        $ReturnData = Invoke-RepackageObjectWithType -RawObject $UserCollection.users -ObjectName "User.Role.Assigned.Users"    
                        $ReturnData = $UserCollection.users | Sort-Object { $_.email }

                        return $ReturnData 

                                        
                    }
                    else {
                        return   
                    }
                }

            
                $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Role"    

                $ReturnData = $ReturnData | Sort-Object { $_.application_name, $_.name }

                return $ReturnData 
            }
            else {

                return
            
            }
        }
    }
}


Function Get-HPEGLUserRole {
    <#
    .SYNOPSIS
    View user roles in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet lists the users' roles and permissions on the HPE GreenLake platformaccount.
    Roles are groups of permissions that grant access to users.
 
    .PARAMETER Email
    Email address of the user for whom you want to obtain roles and permissions (can be retrieved using Get-HPEGLUser).
 
    .PARAMETER Application
    Optional parameter to display user roles and permissions for an application name chosen from a predefined list.
    The predefined applications are as follows:
        * Compute Ops Management
        * Data Services Cloud Console
        * Aruba Central
        * HPE GreenLake
 
    .PARAMETER ApplicationName
    Optional parameter to display user roles and permissions for an application name (can be retrieved using Get-HPEGLApplication).
     
    .PARAMETER Permissions
    This switch can be used to display the permissions assigned to a user.
   
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLUserRole -Email Isaac.Newton@revolution.com
 
    Returns the user's roles for all applications for which the user has privileges.
 
    .EXAMPLE
    Get-HPEGLUserRole -Email Isaac.Newton@revolution.com -Permissions
 
    Return the user's permissions for all application for which the user has privileges.
 
    .EXAMPLE
    Get-HPEGLUserRole -Email Isaac.Newton@revolution.com -Application 'Compute Ops Management'
 
    Return the user's permissions for the Compute Ops management application.
 
    .EXAMPLE
    Get-HPEGLUserRole -Email Isaac.Newton@revolution.com -Application 'Data Services Cloud Console' -Permissions
 
    Return the user's permissions for the Data Services Cloud Console application.
 
    .EXAMPLE
    Get-HPEGLUserRole -Email Isaac.Newton@revolution.com -ApplicationName "Project Denali"
 
    Return the user's roles for the Project Denali application.
 
    .LINK
    Get-HPEGLUser
    Remove-HPEGLUser
    Send-HPEGLUserInvitation
    Get-HPEGLRole
    Set-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    Get-HPEGLResourceRestrictionPolicy
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory, ParameterSetName = 'Application')]
        [Parameter (Mandatory, ParameterSetName = 'ApplicationInstance')]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,
       
        [Parameter (ParameterSetName = 'Application')]
        [ValidateSet( 'Compute Ops Management', 'Data Services Cloud Console', 'Aruba Central', 'HPE GreenLake' )]
        [String]$Application,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "ApplicationInstance")]
        [ValidateNotNullOrEmpty()]
        [Alias('name')]
        [String]$ApplicationName,

        [Parameter (Mandatory = $False, ParameterSetName = 'Application')]
        [Parameter (Mandatory = $False, ParameterSetName = 'ApplicationInstance')]
        [Switch]$Permissions,

        [Parameter (Mandatory = $False, ParameterSetName = 'Application')]
        [Parameter (Mandatory = $False, ParameterSetName = 'ApplicationInstance')]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $AuthzUsersRolesAssignmentsUri + $HPEGreenLakeSession.customerId + "/users/" + $Email.ToLower() + "/role_assignments"

    }

    Process {
       

        $ReturnData = @()
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }
     

        if ($Null -ne $Collection.roles) {
                
            $PermissionsList = @()

            if ($Application) {

                if ($Application -eq "HPE Greenlake") {
                    $UserRoles = $Collection.roles | ? application_name -eq "HPE GreenLake platform"
                    
                    $ApplicationID = "00000000-0000-0000-0000-000000000000"
                
                }
                else {
                    $UserRoles = $Collection.roles | ? application_name -eq $Application

                    try {
                        $App = Get-HPEGLApplication -Name $Application | sort-object -Property application_id -Unique
                    }
                    catch {
                        Throw $_
                    }
                        

                    $ApplicationID = $App.application_id

                                     
                }
            }
            elseif ($ApplicationName) {
                 
                try {

                    $App = Get-HPEGLApplication -Name $ApplicationName | sort-object application_id -Unique 
                }
                catch {
                    Throw $_
                }
                                
                if (-not $App -and $ApplicationName -ne "HPE GreenLake platform") {
                    "{0}: Application not found on the HPE GreenLake platform!" -f $ApplicationName | Write-Verbose
                    Throw "Error! Application name not found!"
                }

                if ($ApplicationName -eq "HPE GreenLake platform") {

                    $ApplicationID = "00000000-0000-0000-0000-000000000000"

                }
                else {
                    $ApplicationID = $App.application_id

                }

                $UserRoles = $Collection.roles | ? application_id -eq $ApplicationID

                
            }
            else {
                $userRoles = $Collection.roles

            } 
            

            foreach ($UserRole in $UserRoles) {

                $UserFirstName = $Collection | % user_first_name
                $UserLastName = $Collection | % user_last_name
                $UserType = $Collection | % user_type

                $RoleName = $UserRole | % role_name
                $AppName = $UserRole | % application_name

                $AppID = $UserRole | % application_id
             
                $Slug = $UserRole | % slug
                    

                if ($Permissions -and $ApplicationID) {

                    "Permission + ApplicationID -- Application Name: {0}: Application ID: {1} - Role Name: {2}" -f $AppName, $ApplicationID, $Rolename | Write-Verbose


                    try {

                        $ResourcePolicies = (Get-HPEGLRole -ApplicationName $AppName -ApplicationRole $RoleName) | % resource_policies


                        "`nResource Policy: {0}" -f ($ResourcePolicies.resource.matcher)  | Write-Verbose

                    }
                    catch {
                        Throw $_
                    }
             
                    foreach ($ResourcePolicy in $ResourcePolicies) {
 
                        $ReturnData = $ResourcePolicy |  Select-Object @{N = "Email"; E = { $Email } }, @{N = "Application"; E = { $AppName } }, @{N = "Resource"; E = { $_.resource.matcher } }, @{N = "Permissions"; E = { $_.permissions.slug } }, @{N = "Effect"; E = { $_.effect } }

                        $PermissionsList += $ReturnData 

                    }

      


                }
                elseif ($Permissions) {

                    "Permission --Application Name: {0}: Application ID: {1} - Role Name: {2}" -f $AppName, $AppID, $RoleName | Write-Verbose
                   
                    try {

                        if ($AppName -eq "HPE GreenLake platform") {
            
                            $ResourcePolicies = Get-HPEGLRole -HPEGreenLakeRole $RoleName  | % resource_policies

                        }
                        else {
                            $ResourcePolicies = (Get-HPEGLRole -ApplicationName $AppName -ApplicationRole $RoleName) | % resource_policies
                        }

                        "`nResource Policies: {0}" -f $ResourcePolicies.resource.matcher  | Write-Verbose
                            
                            
                    }
                    catch {
                        Throw $_
                    }

                       
                    foreach ($ResourcePolicy in $ResourcePolicies) {

                        $ReturnData = $ResourcePolicy |  Select-Object  @{N = "Email"; E = { $Email } }, @{N = "Application"; E = { $AppName } }, @{N = "Resource"; E = { $_.resource.matcher } }, @{N = "Permissions"; E = { $_.permissions.slug } }, @{N = "Effect"; E = { $_.effect } }

                        "`nResource Policy: {0}" -f $ReturnData  | Write-Verbose


                        $PermissionsList += $ReturnData 



                    }

                }
                else {

                    if ($UserRole.resource_restriction_policies) {
                            
                        Write-Verbose "Resource Restriction policies found!"   
                                                       
                        if ($UserRole.resource_restriction_policies.name -eq "Allscopes") {
                            $RRPName = "Full Access"
                        }
                        else {
                            $RRPName = $UserRole.resource_restriction_policies.name 
                        }

                        $RRPDescription = $UserRole.resource_restriction_policies.description 
                        $ResourceRestrictionPolicyId = $UserRole.resource_restriction_policies.resource_restriction_policy_id
                          

                        $ReturnData = $UserRole  |  Select-Object `
                        @{N = "email"; E = { $Email } }, `
                        @{N = "user_first_name"; E = { $UserFirstName } }, `
                        @{N = "user_last_name"; E = { $UserLastName } }, `
                        @{N = "user_type"; E = { $UserType } }, `
                        @{N = "application_name"; E = { $AppName } }, `
                        @{N = "application_id"; E = { $AppID } }, `
                        @{N = "resource_restriction_policy_description"; E = { $RRPDescription } }, `
                        @{N = "resource_restriction_policy_id"; E = { $ResourceRestrictionPolicyId } }, `
                        @{N = "role"; E = { $Rolename } }, `
                        @{N = "resource_restriction_policy"; E = { $RRPName } }, `
                        @{N = "slug"; E = { $Slug } }

                        $PermissionsList += $ReturnData 
                            
                    }
                    else {
              
                        $ReturnData = $UserRole  |  Select-Object `
                        @{N = "email"; E = { $Email } }, `
                        @{N = "user_first_name"; E = { $UserFirstName } }, `
                        @{N = "user_last_name"; E = { $UserLastName } }, `
                        @{N = "user_type"; E = { $UserType } }, `
                        @{N = "application_name"; E = { $AppName } }, `
                        @{N = "application_id"; E = { $AppID } }, `
                        @{N = "resource_restriction_policy_description"; E = { $Null } }, `
                        @{N = "resource_restriction_policy_id"; E = { $Null } }, `
                        @{N = "role"; E = { $Rolename } }, `
                        @{N = "resource_restriction_policy"; E = { $Null } }, `
                        @{N = "slug"; E = { $Slug } }

                        $PermissionsList += $ReturnData 

                    }
                }
            }

            if (-not $Permissions) {
                $ReturnData = Invoke-RepackageObjectWithType -RawObject $PermissionsList -ObjectName "User.Role"         
                $ReturnData = $ReturnData | sort-object application_name, role

            }
            else {
                $ReturnData = $PermissionsList
            }
            

            return $ReturnData
           
        }

        else {
            return
        }
    }
}


Function Set-HPEGLUserRole {
    <#
    .SYNOPSIS
    Set user roles in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet sets users roles and permissions on the HPE GreenLake platformaccount.
    Roles are groups of permissions that grant users access to the HPE GreenLake applications.
 
    Roles are assigned to an application in all regions. If you need to further limit the scope of resources
    a user role can access, you can use the resource restriction policy feature (Set-HPEGLResourceRestrictionPolicy).
 
    .PARAMETER Email
    Email address of the user for whom you want to set roles and permissions (can be retrieved using Get-HPEGLUser).
 
    .PARAMETER ArubaCentralRole
    Name of the Aruba Central role to add to the user's roles.
    The predefined roles are as follows:
        * Aruba Central Administrator
        * Aruba Central Guest Operator
        * Aruba Central Operator
        * Aruba Central view edit role
        * Aruba Central View Only
        * Netlnsight Campus Admin
        * Netlnsight Campus Viewonly
 
    .PARAMETER ComputeOpsManagementRole
    Name of the Compute Ops Management role to add to the user's roles.
    The predefined roles are as follows:
        * Administrator
        * Observer
        * Operator
 
    .PARAMETER DataServicesCloudConsoleRole
    Name of the Data Services Cloud Console role to add to the user's roles.
    The predefined roles are as follows:
        * Administrator
        * Backup and Recovery Administrator
        * Backup and Recovery Operator
        * Data Ops Manager Administrator
        * Data Ops Manager Operator
        * Disaster Recovery Admin
        * Read only
 
    .PARAMETER HPEGreenLakeRole
    Name of the HPE GreenLakeRole role to add to the user's roles.
    The predefined roles are as follows:
        * Account Administrator
        * Observer
        * Operator
        * Orders Administrator
        * Orders Observer
        * Orders Operator
 
    .PARAMETER RoleName
    Role name of an application to be assigned (can be retrieved using Get-HPEGLRole).
         
    .PARAMETER ApplicationName
    Name of the application to which the role name will be assigned (can be retrieved using Get-HPEGLRole).
 
    .PARAMETER ResourceRestrictionPolicyName
    Name of a resource restriction policy (can be retrieved with Get-HPEGLResourceRestrictionPolicy).
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Set-HPEGLUserRole -Email richardfeynman@quantummechanics.lab -ComputeOpsManagementRole Observer
 
    Set the Observer role to richardfeynman@quantummechanics.lab for the "Compute Ops Management" application.
 
    .EXAMPLE
    Set-HPEGLUserRole -Email richardfeynman@quantummechanics.lab -ApplicationName "Data Services Cloud Console" -RoleName "Backup and Recovery Administrator"
 
    Set the Backup and Recovery Administrator role to richardfeynman@quantummechanics.lab for the "Data Services Cloud Console" application.
 
    .EXAMPLE
    $email = (Get-HPEGLUser -FirstName "Richard" -LastName 'Feynman').contact.email
    Get-HPEGLRole -ApplicationName "Compute Ops Management" -ApplicationRole Observer | Set-HPEGLUserRole -Email $email
 
    Set the Administrator role to the user Richard Feynman for the application "Compute Ops Management".
 
    .EXAMPLE
    Set-HPEGLUserRole -Email alexandreliapounov@math.edu -ComputeOpsManagementRole 'Administrator' -ResourceRestrictionPolicyName 'RRP_COM-Location-Texas'
 
    Set the resource restriction policy named 'RRP_COM-Location-Texas' to the user Alexandre Liapounov for the "Compute Ops Management" application with the Administrator role.
     
    .INPUTS
    System.Collections.ArrayList
        List of role(s) from Get-HPEGLRole.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Email - Email of the user
        * Role - Name of the role to assign
        * Application - Name of the application
        * ResourceRestrictionPolicyName - Name of the resource restriction policy to assign
        * Status - Status of the role assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLUser
    Remove-HPEGLUser
    Send-HPEGLUserInvitation
    Get-HPEGLRole
    Get-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    Get-HPEGLResourceRestrictionPolicy
    Set-HPEGLResourceRestrictionPolicy
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory, ParameterSetName = 'ArubaCentral')]
        [Parameter (Mandatory, ParameterSetName = 'HPEGreenLake')]
        [Parameter (Mandatory, ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (Mandatory, ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (Mandatory, ParameterSetName = 'Other')]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,
       
        [Parameter (Mandatory, ParameterSetName = 'ArubaCentral')]
        [ValidateSet ('Aruba Central Administrator', 'Aruba Central Guest Operator', 'Aruba Central Operator', 'Aruba Central view edit role', 'Aruba Central View Only', 'Netlnsight Campus Admin', 'Netlnsight Campus Viewonly')]
        [String]$ArubaCentralRole,

        [Parameter (Mandatory, ParameterSetName = 'HPEGreenLake')]
        [ValidateSet ('Account Administrator', 'Observer', 'Operator', 'Orders Administrator', 'Orders Observer', 'Orders Operator')]
        [String]$HPEGreenLakeRole,

        [Parameter (Mandatory, ParameterSetName = 'ComputeOpsManagement')]
        [ValidateSet ('Administrator', 'Observer', 'Operator')]
        [String]$ComputeOpsManagementRole,

        [Parameter (Mandatory, ParameterSetName = 'DataServicesCloudConsole')]
        [ValidateSet ('Administrator', 'Backup and Recovery Administrator', 'Backup and Recovery Operator', 'Data Ops Manager Administrator', 'Data Ops Manager Operator', 'Disaster Recovery Admin', 'Read only')]
        [String]$DataServicesCloudConsoleRole,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Other')]
        [Alias('application_name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Other')]
        [Alias('name')]
        [String]$RoleName,

        [Parameter (ParameterSetName = 'ArubaCentral')]
        [Parameter (ParameterSetName = 'HPEGreenLake')]
        [Parameter (ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (ParameterSetName = 'Other')]
        [String]$ResourceRestrictionPolicyName,

        [Parameter (ParameterSetName = 'ArubaCentral')]
        [Parameter (ParameterSetName = 'HPEGreenLake')]
        [Parameter (ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (ParameterSetName = 'Other')]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $AuthzUsersRolesUri + $Email.ToLower() + "/roles"

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


    }

    Process {

        try {
            # Test if user present
            $User = (Get-HPEGLUser).contact | ? email -eq $Email
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Email                         = $Email
            Role                          = $Null
            Application                   = $Null
            ResourceRestrictionPolicyName = $Null
            Status                        = $Null
            Details                       = $Null
            Exception                     = $Null
                  
        }
        
        if (-not $User) {
            # Must return a message if user not found
            "{0}: User not found." -f $Email | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "User cannot be found on the HPE GreenLake platform!"
            $objStatus.Application = $ApplicationName
            
        }
        
        ############## If RoleName / ApplicationName ##############
        elseif ($RoleName) {

            $objStatus.Role = $RoleName
            $objStatus.Application = $ApplicationName

            try {
                $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName  | sort-object -Property application_id  -Unique

                $ApplicationID = $Application.application_id
                
            }
            catch {    
                Throw $_

            }

            # If ApplicationName not found except if GreenLake application
            if (-not $Application -and $ApplicationName -ne "HPE GreenLake platform") {
                # Must return a message if Application is not provisioned in the region
                "{0}: Application not provisioned in a region!" -f $ApplicationName | Write-Verbose
    
                $objStatus.Status = "Failed"
                $objStatus.Details = "Application not provisioned in a region!"
                $objStatus.Application = $ApplicationName
           
    
            }

            # If ApplicationName
            else {

                # Role already assigned?
                try {

                    $AppRoles = Get-HPEGLRole -ApplicationName $ApplicationName 
                    $AppRole = $AppRoles | ? name -eq $RoleName
                    $Slug = $AppRole.slug
                              
                    "'{0}' role found for '{1}'" -f $Rolename, $ApplicationName | Write-Verbose
                    "Slug = {0}" -f $Slug | write-verbose

                }
                catch {
                    Throw $_
                }

                # If application role found
                if ( $AppRole) {
                    
                    try {

                        $ExistingUserRoles = Get-HPEGLUserRole -Email $email

                        $ApplicationNameUserRoles = $ExistingUserRoles | ? application_name -eq $ApplicationName

                        $Rolefound = $ApplicationNameUserRoles  | ? role -eq $RoleName

                        # Check if RRP name already assigned to the role
                        $RRPAlreadyAssigned = $Rolefound.resource_restriction_policy


                    }
                    catch {
                        Throw $_
                    }


                    # Role found without RRP parameter = ERROR
                    if ($Rolefound -and -not $ResourceRestrictionPolicyName) {

                        # Must return a message if Rolename is already assigned
                        "{0}: Role name is already assigned to this user!" -f $RoleName | Write-Verbose
    
                        $objStatus.Status = "Warning"
                        $objStatus.Details = "Application role name is already assigned to this user!"
                       

                    }

                    
                    # Role found with RRP parameter = MODIFICATION
                    elseif ($Rolefound -and $ResourceRestrictionPolicyName) {

                        $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                        try {
                            $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName  | sort-object -Property application_id  -Unique
        
                        }
                        catch {    
                            Throw $_

                        }


                        # Check if RRP is available
                        try {
                            $RRP = Get-HPEGLResourceRestrictionPolicy -Name $ResourceRestrictionPolicyName
                        }
                        catch {
                            Throw $_
                        }

                        if ($RRP) {
                   
                            $ResourceRestrictionPolicyIDToSet = $RRP.resource_restriction_policy_id

                            # If RRP name not already assigned to the role: Overwrite needed !
                            if ( $RRPAlreadyAssigned -ne $ResourceRestrictionPolicyName) {

                                $RolesList = [System.Collections.ArrayList]::new()
                
                                foreach ($ExistingUserRole in $ExistingUserRoles) {
                 
                                    $Slug = $ExistingUserRole.slug
                                    $ApplicationID = $ExistingUserRole.application_id
                 
                                    # If ExistingUserRole is not the one we want to modify with new RRP, we capture existing RRP
                                    if ($ExistingUserRole.resource_restriction_policy) {

                                        $ResourceRestrictionPolicyID = $ExistingUserRole.resource_restriction_policy_id

                                        # If ExistingUserRole is the one we want to modify with new RRP
                                        if ($ExistingUserRole.application_name -eq $ApplicationName -and $ExistingUserRole.role -eq $RoleName) {
                        
                                            $ResourceRestrictionPolicyID = $ResourceRestrictionPolicyIDToSet
                      
                                        }
                        
                                        $Role = [PSCustomObject]@{
                                            role                          = @{  
                                                slug           = $Slug
                                                application_id = $ApplicationID
                                            }
                                            resource_restriction_policies = @(
                                                $ResourceRestrictionPolicyID
                                            )
                                        }

                                    }
                                    else {                                
                  
                                        $Role = [PSCustomObject]@{
                                            role                          = @{  
                                                slug           = $Slug
                                                application_id = $ApplicationID
                                            }
                                            resource_restriction_policies = @( )
                                        }
                                    }

                                    $RolesList += $Role

                                }
                

                                # Build payload
                                $Payload = [PSCustomObject]@{ overwrite = @( 
                                        $RolesList
                                    )
                                } | ConvertTo-Json -Depth 5
                

                                # Set user role with RRP
                                try {
                                    Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                                    if (-not $Whatif) {

                                        "{0}: role with resource restriction policy {1} successfully set for {2}" -f $RoleName, $ResourceRestrictionPolicyName, $Email | Write-Verbose

                                        $objStatus.Status = "Complete"
                                        $objStatus.Details = "Resource restriction policy successfully set!"
                                        $objStatus.Application = $ApplicationName

                                    }

                                }
                                catch {
                                    if (-not $Whatif) {
                                        $objStatus.Status = "Failed"
                                        $objStatus.Details = "Resource restriction policy cannot be set!"
                                        $objStatus.Exception = $_.Exception.message 
                                        $objStatus.Application = $ApplicationName
                                    }
                                }

                            }
                            # If RRP name already assigned to the role
                            else {
                                # Must return a message if RRP name is already assigned to the role
                                "{0}: Resource restriction policy name is already assigned to this role!" -f $ResourceRestrictionPolicyName | Write-Verbose

                                $objStatus.Status = "Warning"
                                $objStatus.Details = "Resource restriction policy name is already assigned to this role!"
                            }
                        }
                        else {
                            # Must return a message if RRP name is not found in the region
                            "{0}: Resource restriction policy name cannot be found in this region!" -f $ResourceRestrictionPolicyName | Write-Verbose

                            $objStatus.Status = "Failed"
                            $objStatus.Details = "Resource restriction policy name cannot be found in this region!"
          
                        } 
                    }

                    # Role not found without RRP parameter = CREATION
                    # Role not found with RRP parameter = CREATION
                    elseif (-not $Rolefound) {    

                        $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                        if ($ApplicationName -eq "HPE GreenLake platform") {
                            $ApplicationID = "00000000-0000-0000-0000-000000000000"
                        }
                        else {
                            $ApplicationID = $Application.application_id
                        }

                        # If not RRP
                        if (-Not $ResourceRestrictionPolicyName) {

                            # Build payload
                            $Payload = [PSCustomObject]@{ add = @( 
                                    @{ 
                                        role                          = @{  
                                            slug           = $Slug
                                            application_id = $ApplicationID
                                        }
                                        resource_restriction_policies = $Null
                                    
                                    }
    
                                )
                            } | ConvertTo-Json -Depth 5

                            # Set user roles without RRP
                            try { 
                                Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null 
                                
                                if (-not $Whatif) {

                                    "{0}: Role successfully assigned to user: {1}" -f $Role, $Email | Write-Verbose

                                    $objStatus.Status = "Complete"
                                    $objStatus.Details = "Role successfully assigned!"
                                    $objStatus.Application = $ApplicationName

                                }
                            }
                            catch {
                                if (-not $Whatif) {
                                    $objStatus.Status = "Failed"
                                    $objStatus.Details = "Role cannot be assigned to user!"
                                    $objStatus.Exception = $_.Exception.message 
                                    $objStatus.Application = $ApplicationName
                                }
                            }

                        }
                        # If RRP
                        else {

                            $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                            # Check if RRP is available

                            try {
                                $RRP = Get-HPEGLResourceRestrictionPolicy -Name $ResourceRestrictionPolicyName
                            }
                            catch {
                                Throw $_
                            }
                            # If RRP name found
                            if ($RRP) {
                               
                                $ResourceRestrictionPolicyID = $RRP.resource_restriction_policy_id

                                # Check if RRP name already assigned to the role

                                try {
                                    $RRPAlreadyAssigned = ($ApplicationNameUserRoles | ? role -eq $RoleName).resource_restriction_policy
                                }
                                catch {
                                    Throw $_
                                }


                                if ( $RRPAlreadyAssigned -ne $ResourceRestrictionPolicyName) {

                                    # Build payload
                                    $Payload = [PSCustomObject]@{ add = @( 
                                            @{ 
                                                role                          = @{  
                                                    slug           = $Slug
                                                    application_id = $ApplicationID
                                                }
                                                resource_restriction_policies = @(
                                                    $ResourceRestrictionPolicyID
                                                )
                                            }
        
                                        )
                                    } | ConvertTo-Json -Depth 5
                        
                                    # Set user roles with RRP
                                    try { 
                                        Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null 
                                    
                                        if (-not $Whatif) {

                                            "{0}: Role successfully assigned to user: {1}" -f $Role, $Email | Write-Verbose

                                            $objStatus.Status = "Complete"
                                            $objStatus.Details = "Role successfully assigned!"
                                            $objStatus.Application = $ApplicationName

                                        }
                                    }
                                    catch {
                                        if (-not $Whatif) {
                                            $objStatus.Status = "Failed"
                                            $objStatus.Details = "Role cannot be assigned to user!"
                                            $objStatus.Exception = $_.Exception.message 
                                            $objStatus.Application = $ApplicationName
                                        }
                                    }
                                }
                                else {
                                    # Must return a message if RRP name is already assigned to the role
                                    "{0}: Resource restriction policy name is already assigned to this role!" -f $ResourceRestrictionPolicyName | Write-Verbose

                                    $objStatus.Status = "Warning"
                                    $objStatus.Details = "Resource restriction policy name is already assigned to this role!"
                                }
                            
                            }
                            # If not RRP name not found
                            else {
                                # Must return a message if RRP name is not found in the region
                                "{0}: Resource restriction policy name cannot be found in this region!" -f $ResourceRestrictionPolicyName | Write-Verbose
    
                                $objStatus.Status = "Failed"
                                $objStatus.Details = "Resource restriction policy name cannot be found in this region!"
                              
                            }
                        }
                    }
                }
                # If role not found
                else {
                    # Must return a message if Rolename is not found
                    "{0}: Role name cannot be found for application {1}!" -f $RoleName, $ApplicationName | Write-Verbose
    
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Role name cannot be found for this application!"
                    $objStatus.Application = $ApplicationName
                }            
            }
            
        }

        ############## If Predefined roles (i.e. -ComputeOpsManagementRole, etc.) ##############
        else {

            try {
                $ExistingUserRoles = Get-HPEGLUserRole -Email $email
            }
            catch {
                Throw $_
            }


            # Role already assigned?
            if ($MyInvocation.BoundParameters["ArubaCentralRole"] ) {
            
                $ApplicationName = "Aruba Central"
                $Rolename = $ArubaCentralRole
            
            }
            elseif ($MyInvocation.BoundParameters["HPEGreenLakeRole"] ) {
            
                $ApplicationName = "HPE GreenLake platform"
                $Rolename = $HPEGreenLakeRole
            
            }
            elseif ($MyInvocation.BoundParameters["ComputeOpsManagementRole"] ) {

                $ApplicationName = "Compute Ops Management"
                $Rolename = $ComputeOpsManagementRole
            
            }
            elseif ($MyInvocation.BoundParameters["DataServicesCloudConsoleRole"] ) {
            
                $ApplicationName = "Data Services Cloud Console"
                $Rolename = $DataServicesCloudConsoleRole

            }

            $ApplicationNameUserRoles = $ExistingUserRoles | ? application_name -eq $ApplicationName
            $Rolefound = $ApplicationNameUserRoles  | ? role -eq $RoleName

            $objStatus.Role = $Rolename
            $objStatus.Application = $ApplicationName
        
            # Role found without RRP parameter = ERROR
            if ($Rolefound -and -not $ResourceRestrictionPolicyName) {
        
                # Must return a message if Rolename is already assigned
                "{0}: Role name is already assigned to this user!" -f $RoleName | Write-Verbose
        
                $objStatus.Status = "Warning"
                $objStatus.Details = "Application role name is already assigned to this user!"
                $objStatus.Application = $ApplicationName

            }

            # Role found with RRP parameter = MODIFICATION
            elseif ($Rolefound -and $ResourceRestrictionPolicyName) {

                $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                # Get slug
                try {
                    $Slug = (Get-HPEGLRole -ApplicationName $ApplicationName -ApplicationRole $RoleName).slug
                }
                catch {
                    Throw $_
                }

                "Slug = {0}" -f $Slug | write-verbose
                

                try {
                    $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName  | sort-object -Property application_id  -Unique

                    $ApplicationID = $Application.application_id

                    
                }
                catch {    
                    Throw $_
    
                }

                if (-not $Application) {
                    # Must return a message if Application is not provisioned in the region
                    "{0}: Application not provisioned in a region!" -f $ApplicationName | Write-Verbose
        
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Application not provisioned in a region!"
                    $objStatus.Application = $ApplicationName
        
                }
                else {

                    # Check if RRP is available

                    try {
                        $RRP = Get-HPEGLResourceRestrictionPolicy -Name $ResourceRestrictionPolicyName
                    }
                    catch {
                        Throw $_
                    }

                    if ($RRP) {
                               
                        $ResourceRestrictionPolicyIDToSet = $RRP.resource_restriction_policy_id

                        # Check if RRP name already assigned to the role
                        $RRPAlreadyAssigned = $Rolefound.resource_restriction_policy

                        # If RRP name not already assigned to the role: Overwrite needed !
                        if ( $RRPAlreadyAssigned -ne $ResourceRestrictionPolicyName) {

                            $RolesList = [System.Collections.ArrayList]::new()
                            
                            foreach ($ExistingUserRole in $ExistingUserRoles) {
                             
                                $Slug = $ExistingUserRole.slug
                                $ApplicationID = $ExistingUserRole.application_id
                             
                                # If ExistingUserRole is not the one we want to modify with new RRP, we capture existing RRP
                                if ($ExistingUserRole.resource_restriction_policy) {

                                    $ResourceRestrictionPolicyID = $ExistingUserRole.resource_restriction_policy_id

                                    # If ExistingUserRole is the one we want to modify with new RRP
                                    if ($ExistingUserRole.application_name -eq $ApplicationName -and $ExistingUserRole.role -eq $RoleName) {
                                    
                                        $ResourceRestrictionPolicyID = $ResourceRestrictionPolicyIDToSet
                                  
                                    }
                                    
                                    $Role = [PSCustomObject]@{
                                        role                          = @{  
                                            slug           = $Slug
                                            application_id = $ApplicationID
                                        }
                                        resource_restriction_policies = @(
                                            $ResourceRestrictionPolicyID
                                        )
                                    }

                                }
                                else {                                
                              
                                    $Role = [PSCustomObject]@{
                                        role                          = @{  
                                            slug           = $Slug
                                            application_id = $ApplicationID
                                        }
                                        resource_restriction_policies = @( )
                                    }
                                }

                                $RolesList += $Role

                            }
                            

                            # Build payload
                            $Payload = [PSCustomObject]@{ overwrite = @( 
                                    $RolesList
                                )
                            } | ConvertTo-Json -Depth 5
                            

                            # Set user role with RRP
                            try {
                                Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                                if (-not $Whatif) {

                                    "{0}: role with resource restriction policy {1} successfully set for {2}" -f $RoleName, $ResourceRestrictionPolicyName, $Email | Write-Verbose

                                    $objStatus.Status = "Complete"
                                    $objStatus.Details = "Resource restriction policy successfully set!"
                                    $objStatus.Application = $ApplicationName

                                }

                            }
                            catch {
                                if (-not $Whatif) {
                                    $objStatus.Status = "Failed"
                                    $objStatus.Details = "Resource restriction policy cannot be set!"
                                    $objStatus.Exception = $_.Exception.message 
                                    $objStatus.Application = $ApplicationName
                                }
                            }

                        }
                        # If RRP name already assigned to the role
                        else {
                            # Must return a message if RRP name is already assigned to the role
                            "{0}: Resource restriction policy name is already assigned to this role!" -f $ResourceRestrictionPolicyName | Write-Verbose

                            $objStatus.Status = "Warning"
                            $objStatus.Details = "Resource restriction policy name is already assigned to this role!"
                        }
                    }
                    else {
                        # Must return a message if RRP name is not found in the region
                        "{0}: Resource restriction policy name cannot be found in this region!" -f $ResourceRestrictionPolicyName | Write-Verbose

                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Resource restriction policy name cannot be found in this region!"
                      
                    }
                        
                }
             
            }
            
            # Role not found without RRP parameter = CREATION
            # Role not found with RRP parameter = CREATION
            elseif (-not $Rolefound) {   

                $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                # Get slug
                try {
                    $Slug = (Get-HPEGLRole -ApplicationName $ApplicationName -ApplicationRole $RoleName).slug
                }
                catch {
                    Throw $_
                }

                "Slug = {0}" -f $Slug | write-verbose
                
                # If all apps except GreenLake application
                if (-not $MyInvocation.BoundParameters["HPEGreenLakeRole"]) {

                    try {
                        $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName  | sort-object -Property application_id  -Unique
                    
                    }
                    catch {    
                        Throw $_
    
                    }

                    if (-not $Application) {
                        # Must return a message if Application is not provisioned in the region
                        "{0}: Application not provisioned in a region!" -f $ApplicationName | Write-Verbose
        
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Application not provisioned in a region!"
                        $objStatus.Application = $ApplicationName
        
                    }
                    else {

                        $ApplicationID = $Application.application_id
                        
                        # If not RRP
                        if (-Not $ResourceRestrictionPolicyName) {

                            # Build payload
                            $Payload = [PSCustomObject]@{ add = @( 
                                    @{ 
                                        role                          = @{  
                                            slug           = $Slug
                                            application_id = $ApplicationID
                                        }
                                        resource_restriction_policies = $Null
                                    
                                    }
    
                                )
                            } | ConvertTo-Json -Depth 5

                            # Set user roles without RRP
                            try { 
                                Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null 
                                
                                if (-not $Whatif) {

                                    "{0}: Role successfully assigned to user: {1}" -f $Role, $Email | Write-Verbose

                                    $objStatus.Status = "Complete"
                                    $objStatus.Details = "Role successfully assigned!"
                                    $objStatus.Application = $ApplicationName

                                }
                            }
                            catch {
                                if (-not $Whatif) {
                                    $objStatus.Status = "Failed"
                                    $objStatus.Details = "Role cannot be assigned to user!"
                                    $objStatus.Exception = $_.Exception.message 
                                    $objStatus.Application = $ApplicationName
                                }
                            }

                        }
                        
                        # If RRP
                        else {

                            $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                            # Check if RRP is available

                            try {
                                $RRP = Get-HPEGLResourceRestrictionPolicy -Name $ResourceRestrictionPolicyName
                            }
                            catch {
                                Throw $_
                            }

                            if ($RRP) {
                               
                                $ResourceRestrictionPolicyID = $RRP.resource_restriction_policy_id

                                # Check if RRP name already assigned to the role

                                try {
                                    $RRPAlreadyAssigned = (Get-HPEGLUserRole -Email $email -ApplicationName $ApplicationName | ? role -eq $RoleName).resource_restriction_policy
                                }
                                catch {
                                    Throw $_
                                }

                                # If RRP name not already assigned to the role
                                if ( $RRPAlreadyAssigned -ne $ResourceRestrictionPolicyName) {

                                    # Build payload
                                    $Payload = [PSCustomObject]@{ add = @( 
                                            @{ 
                                                role                          = @{  
                                                    slug           = $Slug
                                                    application_id = $ApplicationID
                                                }
                                                resource_restriction_policies = @(
                                                    $ResourceRestrictionPolicyID
                                                )
                                            }
        
                                        )
                                    } | ConvertTo-Json -Depth 5
                            

                                    # Set user role with RRP
                                    try {
                                        Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                                        if (-not $Whatif) {

                                            "{0}: Role successfully assigned to user: {1}" -f $RoleName, $Email | Write-Verbose

                                            $objStatus.Status = "Complete"
                                            $objStatus.Details = "Role successfully assigned!"
                                            $objStatus.Application = $ApplicationName

                                        }

                                    }
                                    catch {
                                        if (-not $Whatif) {
                                            $objStatus.Status = "Failed"
                                            $objStatus.Details = "Role cannot be assigned to user!"
                                            $objStatus.Exception = $_.Exception.message 
                                            $objStatus.Application = $ApplicationName
                                        }
                                    }

                                }
                                # If RRP name already assigned to the role
                                else {
                                    # Must return a message if RRP name is already assigned to the role
                                    "{0}: Resource restriction policy name is already assigned to this role!" -f $ResourceRestrictionPolicyName | Write-Verbose

                                    $objStatus.Status = "Warning"
                                    $objStatus.Details = "Resource restriction policy name is already assigned to this role!"
                                }
                            }
                            else {
                                # Must return a message if RRP name is not found in the region
                                "{0}: Resource restriction policy name cannot be found in this region!" -f $ResourceRestrictionPolicyName | Write-Verbose

                                $objStatus.Status = "Failed"
                                $objStatus.Details = "Resource restriction policy name cannot be found in this region!"
                      
                            }
                        }
                    }
                }

                # If GreenLake application
                else {

                    $ApplicationID = "00000000-0000-0000-0000-000000000000"

                    # Build payload

                    # No resource restriction policy exists for HPE GreenLake = "HPE GreenLake platform"

                    # Build payload
                    $Payload = [PSCustomObject]@{ add = @( 
                            @{ 
                                role                          = @{  
                                    slug           = $Slug
                                    application_id = $ApplicationID
                                }
                                resource_restriction_policies = $Null
                                
                            }

                        )
                    } | ConvertTo-Json -Depth 5

                    # Set user roles without RRP
                    try { 
                        Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null 
                            
                        if (-not $Whatif) {

                            "{0}: Role successfully assigned to user: {1}" -f $Role, $Email | Write-Verbose

                            $objStatus.Status = "Complete"
                            $objStatus.Details = "Role successfully assigned!"
                            $objStatus.Application = $ApplicationName

                        }
                    }
                    catch {
                        if (-not $Whatif) {
                            $objStatus.Status = "Failed"
                            $objStatus.Details = "Role cannot be assigned to user!"
                            $objStatus.Exception = $_.Exception.message 
                            $objStatus.Application = $ApplicationName
                        }
                    }

                               
                }
            }
        }

        [void] $UserRoleAssignmentStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($UserRoleAssignmentStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more users failed the role assignment attempt!"
          
            }
        }

        Return $UserRoleAssignmentStatus

    }
}


Function Remove-HPEGLUserRole {
    <#
    .SYNOPSIS
    Remove user roles in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet removes users' roles and permissions on the HPE GreenLake platformaccount.
    Roles are groups of permissions that grant users access to the HPE GreenLake applications.
 
    Roles are unassigned from an application in all regions.
 
    .PARAMETER Email
    Email address of the user for whom you want to remove roles and permissions (can be retrieved using Get-HPEGLUser).
 
    .PARAMETER ArubaCentralRole
    Name of the Aruba Central role to remove from the user's roles.
    The predefined roles are as follows:
        * Aruba Central Administrator
        * Aruba Central Guest Operator
        * Aruba Central Operator
        * Aruba Central view edit role
        * Aruba Central View Only
        * Netlnsight Campus Admin
        * Netlnsight Campus Viewonly
 
    .PARAMETER ComputeOpsManagementRole
    Name of the Compute Ops Management role to remove from the user's roles.
    The predefined roles are as follows:
        * Administrator
        * Observer
        * Operator
 
    .PARAMETER DataServicesCloudConsoleRole
    Name of the Data Services Cloud Console role to remove from the user's roles.
    The predefined roles are as follows:
        * Administrator
        * Backup and Recovery Administrator
        * Backup and Recovery Operator
        * Data Ops Manager Administrator
        * Data Ops Manager Operator
        * Disaster Recovery Admin
        * Read only
 
    .PARAMETER HPEGreenLakeRole
    Name of the HPE GreenLakeRole role to remove from the user's roles.
    The predefined roles are as follows:
        * Account Administrator
        * Observer
        * Operator
        * Orders Administrator
        * Orders Observer
        * Orders Operator
 
    .PARAMETER RoleName
    Role name of an application to be unassigned (can be retrieved using Get-HPEGLUserRole).
         
    .PARAMETER ApplicationName
    Name of the application to which the role name will be unassigned (can be retrieved using Get-HPEGLUserRole).
 
    .PARAMETER ResourceRestrictionPolicyName
    Name of a resource restriction policy to be removed (can be retrieved with Get-HPEGLUserRole ).
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Remove-HPEGLUserRole -Email richardfeynman@quantummechanics.lab -ComputeOpsManagementRole Observer
 
    Remove the Observer role to richardfeynman@quantummechanics.lab for the "Compute Ops Management" application.
 
    .EXAMPLE
    Remove-HPEGLUserRole -Email richardfeynman@quantummechanics.lab -ApplicationName "Aruba Central" -RoleName 'Aruba Central Administrator'
 
    Remove the Aruba Central Administrator role to richardfeynman@quantummechanics.lab for the "Aruba Central" application.
   
    .EXAMPLE
    Get-HPEGLUserRole -Email richardfeynman@quantummechanics.lab -ApplicationName "Compute Ops Management" | Remove-HPEGLUserRole
   
    Remove all roles to richardfeynman@quantummechanics.lab for the "Compute Ops Management" application.
 
    .EXAMPLE
    Remove-HPEGLUserRole -Email richardfeynman@quantummechanics.lab -ComputeOpsManagementRole Administrator -ResourceRestrictionPolicyName RRP_COM-Location-Texas
 
    Remove the resource restriction policy named 'RRP_COM-Location-Texas' to the user Alexandre Liapounov for the "Compute Ops Management" application with the Administrator role.
         
    .INPUTS
    System.Collections.ArrayList
        List of user role(s) from Get-HPEGLUserRole.
 
    .OUTPUTS
    System.Collections.ArrayList
        A custom status object or array of objects containing the following PsCustomObject keys:
        * Email - Email of the user
        * Role - Name of the role to remove
        * Application - Name of the application
        * ResourceRestrictionPolicyName - Name of the resource restriction policy to remove
        * Status - Status of the role un-assignment attempt (Failed for http error return; Complete if successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLUser
    Remove-HPEGLUser
    Send-HPEGLUserInvitation
    Get-HPEGLRole
    Get-HPEGLUserRole
    Remove-HPEGLUserRole
    Get-HPEGLApplication
    [${Global:HPEGreenLakeSession}]
     
   #>

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

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'ArubaCentral')]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'HPEGreenLake')]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Other')]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,
      
        [Parameter (Mandatory, ParameterSetName = 'ArubaCentral')]
        [ValidateSet ('Aruba Central Administrator', 'Aruba Central Guest Operator', 'Aruba Central Operator', 'Aruba Central view edit role', 'Aruba Central View Only', 'Netlnsight Campus Admin', 'Netlnsight Campus Viewonly')]
        [String]$ArubaCentralRole,

        [Parameter (Mandatory, ParameterSetName = 'HPEGreenLake')]
        [ValidateSet ('Account Administrator', 'Observer', 'Operator', 'Orders Administrator', 'Orders Observer', 'Orders Operator')]
        [String]$HPEGreenLakeRole,

        [Parameter (Mandatory, ParameterSetName = 'ComputeOpsManagement')]
        [ValidateSet ('Administrator', 'Observer', 'Operator')]
        [String]$ComputeOpsManagementRole,

        [Parameter (Mandatory, ParameterSetName = 'DataServicesCloudConsole')]
        [ValidateSet ('Administrator', 'Backup and Recovery Administrator', 'Backup and Recovery Operator', 'Data Ops Manager Administrator', 'Data Ops Manager Operator', 'Disaster Recovery Admin', 'Read only')]
        [String]$DataServicesCloudConsoleRole,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Other')]
        [Alias('Application_name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Other')]
        [Alias('Role')]
        [String]$RoleName,

        [Parameter (ParameterSetName = 'ArubaCentral')]
        [Parameter (ParameterSetName = 'HPEGreenLake')]
        [Parameter (ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (ParameterSetName = 'Other')]
        [String]$ResourceRestrictionPolicyName,

        [Parameter (ParameterSetName = 'ArubaCentral')]
        [Parameter (ParameterSetName = 'HPEGreenLake')]
        [Parameter (ParameterSetName = 'ComputeOpsManagement')]
        [Parameter (ParameterSetName = 'DataServicesCloudConsole')]
        [Parameter (ParameterSetName = 'Other')]
        [Switch]$Whatif
    ) 

    Begin {

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

    }

    Process {

        $UriAdd = $AuthzUsersRolesUri + $Email.ToLower() + "/roles"

        try {
            # Test if user present
            $User = (Get-HPEGLUser).contact | ? email -eq $Email
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Email                         = $Email
            Role                          = $Null
            Application                   = $Null
            ResourceRestrictionPolicyName = $Null
            Status                        = $Null
            Details                       = $Null
            Exception                     = $Null
                  
        }
        
        if (-not $User) {
            # Must return a message if user not found
            "{0}: User not found." -f $Email | Write-Verbose
            $objStatus.Status = "Failed"
            $objStatus.Details = "User cannot be found on the HPE GreenLake platform!"
            $objStatus.Application = $ApplicationName
            
        }

        ############### If RoleName / ApplicationName ###############
        elseif ($RoleName) {

            $objStatus.Role = $RoleName
            $objStatus.Application = $ApplicationName


            try {
                $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName | sort-object -Property application_id  -Unique
                
            }
            catch {    
                Throw $_

            }
            # If ApplicationName not found except if GreenLake application
            if (-not $Application -and $ApplicationName -ne "HPE GreenLake platform") {
                # Must return a message if Application is not provisioned in the region
                "{0}: Application not provisioned in a region!" -f $ApplicationName | Write-Verbose
    
                $objStatus.Status = "Failed"
                $objStatus.Details = "Application not provisioned in a region!"
                $objStatus.Application = $ApplicationName
    
            }
            else {
                
                # Role assigned?
                try {
                   
                    $ExistingUserRoles = Get-HPEGLUserRole -Email $email

                    $ApplicationNameUserRoles = $ExistingUserRoles | ? application_name -eq $ApplicationName

                    $Rolefound = $ApplicationNameUserRoles  | ? role -eq $RoleName

                    $Slug = $Rolefound.slug

                    "Rolefound = {0}" -f $Rolefound | write-verbose

                 

                }
                catch {
                    Throw $_
                }

                # Role found but not RRP modification = DELETE
                if ( $Rolefound -and -not $ResourceRestrictionPolicyName) {

                    "'{0}' role found for '{1}'" -f $Rolename, $ApplicationName | Write-Verbose
                    "Slug = {0}" -f $Slug | write-verbose


                    if ($ApplicationName -eq "HPE GreenLake platform") {

                        $ApplicationID = "00000000-0000-0000-0000-000000000000"

                    }
                    else {
                        $ApplicationID = $Application.application_id
                    }

                    # Build payload
                    $Payload = [PSCustomObject]@{ delete = @( 
                            @{ 
                                slug           = $Slug
                                application_id = $ApplicationID
                            }
                        )
                    } | ConvertTo-Json -Depth 5
                  

                    # Remove user role
                    try {
                        Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                        if (-not $Whatif) {

                            "{0}: Role successfully removed from user: {1}" -f $Role, $Email | Write-Verbose

                            $objStatus.Status = "Complete"
                            $objStatus.Details = "Role successfully removed!"
                            $objStatus.Application = $ApplicationName

                        }

                    }
                    catch {
                        if (-not $Whatif) {
                            $objStatus.Status = "Failed"
                            $objStatus.Details = "Role cannot be removed from user!"
                            $objStatus.Exception = $_.Exception.message 
                            $objStatus.Application = $ApplicationName
                        }
                    }

                }

                # Role found with RRP parameter = MODIFICATION
                elseif ($Rolefound -and $ResourceRestrictionPolicyName) {

                    $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                    # Check if RRP name assigned to the role
                    $RRPAssigned = $Rolefound.resource_restriction_policy
                    
                    # If RRP assigned to role, modification
                    if ($RRPAssigned -eq $ResourceRestrictionPolicyName) {
    
                        $RolesList = [System.Collections.ArrayList]::new()

                        foreach ($ExistingUserRole in $ExistingUserRoles) {
                 
                            $Slug = $ExistingUserRole.slug
                            $ApplicationID = $ExistingUserRole.application_id
         
                            if ($ExistingUserRole.resource_restriction_policy) {

                                $ResourceRestrictionPolicyID = $ExistingUserRole.resource_restriction_policy_id

                                # If ExistingUserRole is the one we want to remove the exisiting RRP and set the default AllScopes RRP back
                                if ($ExistingUserRole.application_name -eq $ApplicationName -and $ExistingUserRole.role -eq $RoleName) {
                        
                                    # Get the AllScopes default resource restriction policy ID of this role
                                    $ResourceRestrictionPolicyID = (Get-HPEGLResourceRestrictionPolicy -Name 'Allscopes' | ? application_name -eq $ApplicationName).resource_restriction_policy_id
              
                                }
                                    
                                $Role = [PSCustomObject]@{
                                    role                          = @{  
                                        slug           = $Slug
                                        application_id = $ApplicationID
                                    }
                                    resource_restriction_policies = @(
                                        $ResourceRestrictionPolicyID
                                    )
                                }

                            }
                            else {                                
          
                                $Role = [PSCustomObject]@{
                                    role                          = @{  
                                        slug           = $Slug
                                        application_id = $ApplicationID
                                    }
                                    resource_restriction_policies = @( )
                                }
                            }

                            $RolesList += $Role

                        }
        

                        # Build payload
                        $Payload = [PSCustomObject]@{ overwrite = @( 
                                $RolesList
                            )
                        } | ConvertTo-Json -Depth 5
        

                        # Set user role with RRP
                        try {
                            Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                            if (-not $Whatif) {

                                "{0}: role with resource restriction policy {1} successfully removed for {2}" -f $RoleName, $ResourceRestrictionPolicyName, $Email | Write-Verbose

                                $objStatus.Status = "Complete"
                                $objStatus.Details = "Resource restriction policy successfully removed!"
                                $objStatus.Application = $ApplicationName

                            }

                        }
                        catch {
                            if (-not $Whatif) {
                                $objStatus.Status = "Failed"
                                $objStatus.Details = "Resource restriction policy cannot be removed!"
                                $objStatus.Exception = $_.Exception.message 
                                $objStatus.Application = $ApplicationName
                            }
                        }


                    }

                    # If RRP name not assigned to the role: ERROR
                    else {
                        # Must return a message if RRP name is not found
                        "{0}: Resource restriction policy name cannot be found for the role {1}!" -f $ResourceRestrictionPolicyName, $Rolename | Write-Verbose

                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Resource restriction policy name cannot be found for this role!"
                    }




                }

                # Role not found = ERROR
                elseif (-not $Rolefound) {
                    # Must return a message if Rolename is not found
                    "{0}: Role name is not assigned to {1} user!" -f $RoleName, $Email | Write-Verbose
    
                    $objStatus.Status = "Warning"
                    $objStatus.Details = "Application role name is not assigned to the user!"
                    $objStatus.Application = $ApplicationName
                }            
            }
            
        }

        ############## If Predefined roles (i.e. -ComputeOpsManagementRole, etc.) ##############
        else {

            try {
                $ExistingUserRoles = Get-HPEGLUserRole -Email $email
            }
            catch {
                Throw $_
            }


            if ($MyInvocation.BoundParameters["ArubaCentralRole"] ) {
            
                $ApplicationName = "Aruba Central"
                $Rolename = $ArubaCentralRole
            
            }
            elseif ($MyInvocation.BoundParameters["HPEGreenLakeRole"] ) {
            
                $ApplicationName = "HPE GreenLake platform"
                $Rolename = $HPEGreenLakeRole
            
            }
            elseif ($MyInvocation.BoundParameters["ComputeOpsManagementRole"] ) {

                $ApplicationName = "Compute Ops Management"
                $Rolename = $ComputeOpsManagementRole
            
            }
            elseif ($MyInvocation.BoundParameters["DataServicesCloudConsoleRole"] ) {
            
                $ApplicationName = "Data Services Cloud Console"
                $Rolename = $DataServicesCloudConsoleRole

            }

            $ApplicationNameUserRoles = $ExistingUserRoles | ? application_name -eq $ApplicationName
            $Rolefound = $ApplicationNameUserRoles  | ? role -eq $RoleName
            $Slug = $Rolefound.slug

            $objStatus.Role = $Rolename
            $objStatus.Application = $ApplicationName
            
            # Role found but not RRP modification = DELETE
            if ($Rolefound -and -not $ResourceRestrictionPolicyName) {
                            
                if (-not $MyInvocation.BoundParameters["HPEGreenLakeRole"]) {

                    try {
                        $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName | sort-object -Property application_id  -Unique
                    
                    }
                    catch {    
                        Throw $_
    
                    }

                    if (-not $Application) {
                        # Must return a message if Application is not provisioned in the region
                        "{0}: Application not provisioned in a region!" -f $ApplicationName | Write-Verbose
        
                        $objStatus.Status = "Failed"
                        $objStatus.Details = "Application not provisioned in a region!"
                        $objStatus.Application = $ApplicationName
        
                    }
                    else {

                        $ApplicationID = $Application.application_id

                        $Payload = [PSCustomObject]@{ delete = @( 
                                @{ 
                                    slug           = $Slug
                                    application_id = $ApplicationID
                                }
                            )
                        } | ConvertTo-Json -Depth 5
                      

                        # Remove user role
                        try {
                            Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                            if (-not $Whatif) {

                                "{0}: Role successfully removed from user: {1}" -f $Rolename, $Email | Write-Verbose

                                $objStatus.Status = "Complete"
                                $objStatus.Details = "Role successfully removed!"
                                $objStatus.Application = $ApplicationName

                            }

                        }
                        catch {
                            if (-not $Whatif) {
                                $objStatus.Status = "Failed"
                                $objStatus.Details = "Role cannot be removed!"
                                $objStatus.Exception = $_.Exception.message 
                                $objStatus.Application = $ApplicationName
                            }
                        }
                    }
                }

                else {

                    $ApplicationID = "00000000-0000-0000-0000-000000000000"

                    # Build payload
                    $Payload = [PSCustomObject]@{ delete = @( 
                            @{ 
                                slug           = $Slug
                                application_id = $ApplicationID
                            }
                        )
                    } | ConvertTo-Json -Depth 5
              

                    # Remove user role
    
                    try {
                        Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                        if (-not $Whatif) {

                            "{0}: Role successfully removed from user: {1}" -f $RoleName, $Email | Write-Verbose

                            $objStatus.Status = "Complete"
                            $objStatus.Details = "Role successfully removed!"
                            $objStatus.Application = $ApplicationName

                        }

                    }
                    catch {
                        if (-not $Whatif) {
                            $objStatus.Status = "Failed"
                            $objStatus.Details = "Role cannot be removed!"
                            $objStatus.Exception = $_.Exception.message 
                            $objStatus.Application = $ApplicationName
                        }
                    }

                }

            }

            # Role found with RRP parameter = MODIFICATION
            elseif ($Rolefound -and $ResourceRestrictionPolicyName) {

                $objStatus.ResourceRestrictionPolicyName = $ResourceRestrictionPolicyName

                # Check if RRP name assigned to the role
                $RRPAssigned = $Rolefound.resource_restriction_policy
                
                # If RRP assigned to role, modification
                if ($RRPAssigned -eq $ResourceRestrictionPolicyName) {

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

                    foreach ($ExistingUserRole in $ExistingUserRoles) {
             
                        $Slug = $ExistingUserRole.slug
                        $ApplicationID = $ExistingUserRole.application_id
     
                        if ($ExistingUserRole.resource_restriction_policy) {

                            $ResourceRestrictionPolicyID = $ExistingUserRole.resource_restriction_policy_id

                            # If ExistingUserRole is the one we want to remove the exisiting RRP and set the default AllScopes RRP back
                            if ($ExistingUserRole.application_name -eq $ApplicationName -and $ExistingUserRole.role -eq $RoleName) {
                    
                                # Get the AllScopes default resource restriction policy ID of this role
                                $ResourceRestrictionPolicyID = (Get-HPEGLResourceRestrictionPolicy -Name 'Allscopes' | ? application_name -eq $ApplicationName).resource_restriction_policy_id
          
                            }
                                
                            $Role = [PSCustomObject]@{
                                role                          = @{  
                                    slug           = $Slug
                                    application_id = $ApplicationID
                                }
                                resource_restriction_policies = @(
                                    $ResourceRestrictionPolicyID
                                )
                            }

                        }
                        else {                                
      
                            $Role = [PSCustomObject]@{
                                role                          = @{  
                                    slug           = $Slug
                                    application_id = $ApplicationID
                                }
                                resource_restriction_policies = @( )
                            }
                        }

                        $RolesList += $Role

                    }
    

                    # Build payload
                    $Payload = [PSCustomObject]@{ overwrite = @( 
                            $RolesList
                        )
                    } | ConvertTo-Json -Depth 5
    

                    # Set user role with RRP
                    try {
                        Invoke-HPEGLWebRequest -Method 'PUT' -Body $Payload -UriAdd $UriAdd -whatifBoolean $WhatIf | Out-Null

                        if (-not $Whatif) {

                            "{0}: role with resource restriction policy {1} successfully removed for {2}" -f $RoleName, $ResourceRestrictionPolicyName, $Email | Write-Verbose

                            $objStatus.Status = "Complete"
                            $objStatus.Details = "Resource restriction policy successfully removed!"
                            $objStatus.Application = $ApplicationName

                        }

                    }
                    catch {
                        if (-not $Whatif) {
                            $objStatus.Status = "Failed"
                            $objStatus.Details = "Resource restriction policy cannot be removed!"
                            $objStatus.Exception = $_.Exception.message 
                            $objStatus.Application = $ApplicationName
                        }
                    }


                }

                # If RRP name not assigned to the role: ERROR
                else {
                    # Must return a message if RRP name is not found
                    "{0}: Resource restriction policy name cannot be found for the role {1}!" -f $ResourceRestrictionPolicyName, $Rolename | Write-Verbose

                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Resource restriction policy name cannot be found for this role!"
                }




            }

            # Role not found = ERROR
            elseif (-not $Rolefound) {
                # Must return a message if Rolename is not found
                "{0} : Role name is not assigned to this user!" -f $RoleName | Write-Verbose
    
                $objStatus.Status = "Warning"
                $objStatus.Details = "Application role name is not assigned to this user!"
                $objStatus.Application = $ApplicationName
              
            }
        }

        [void] $UserRoleUnassignmentStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($UserRoleUnassignmentStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more users failed the role un-assignment attempt!"
          
            }
        }

        Return $UserRoleUnassignmentStatus

    }
}


Function Get-HPEGLResourceRestrictionPolicy {
    <#
    .SYNOPSIS
    View resource restriction policies in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet returns the resource restriction policies on the HPE GreenLake platformaccount.
    Resource restriction policies limit which resources can be accessed by creating customizable resource groupings.
 
    .PARAMETER Name
    Name of the resource restriction policy.
 
    .PARAMETER Application
    Optional parameter to display resource restriction policies for an application name chosen from a predefined list.
    The predefined applications are as follows:
        * Compute Ops Management
        * Data Services Cloud Console
        * Aruba Central
        * HPE GreenLake
 
    .PARAMETER ApplicationName
    Optional parameter to display resource restriction policies for an application name (can be retrieved using Get-HPEGLApplication -Provisioned).
 
    .PARAMETER ApplicationName
    Name of the application to which the role name will be unassigned (can be retrieved using Get-HPEGLApplication -Provisioned).
    
    .PARAMETER Filter
    Switch parameter to get the filters used by a resource restriction policy.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLResourceRestrictionPolicy
 
    Return the resource restriction policies in your HPE GreenLake account.
 
    .EXAMPLE
    Get-HPEGLResourceRestrictionPolicy -Name RRP_COM-Location-Texas
 
    Return the resource restriction policy information with the filter names in use for the 'RRP_COM-Location-Texas' resource restriction policy name.
 
    .EXAMPLE
    Get-HPEGLResourceRestrictionPolicy -ApplicationName 'Compute Ops Management'
 
    Return all resource restriction policies for the Compute Ops Management application instances.
 
    .EXAMPLE
    Get-HPEGLResourceRestrictionPolicy -Name RRP_with_3_COM_filters -Filter
  
    Return all filters used by the 'RRP_with_3_COM_filters' resource restriction policy.
 
    .LINK
    New-HPEGLResourceRestrictionPolicy
    Remove-HPEGLResourceRestrictionPolicy
    Get-HPEGLApplicationResourceRestrictionPolicyFilter
    Get-HPEGLUserRole
    Set-HPEGLUserRole
    Remove-HPEGLUserRole
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Name')]
    Param( 
                    
        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [String]$Name,
            
        [Parameter (Mandatory = $false, ParameterSetName = 'Application')]
        [ValidateSet( 'Compute Ops Management', 'Data Services Cloud Console', 'Aruba Central', 'HPE GreenLake' )]
        [String]$Application,

        [Parameter (Mandatory = $False, ValueFromPipelineByPropertyName, ParameterSetName = 'ApplicationName')]
        [Alias('Application_name')]
        [String]$ApplicationName,

        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [Switch]$Filter,

        [Parameter (Mandatory = $false, ParameterSetName = 'Name')]
        [Parameter (Mandatory = $false, ParameterSetName = 'Application')]
        [Parameter (Mandatory = $false, ParameterSetName = 'ApplicationName')]
        [Switch]$Whatif
       
    ) 

    Begin {

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

        $UriAdd = $ResourceRestrictionsPolicyUri 
        
    }

    Process {

        $ReturnData = @()
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }
   
        
        if ($Null -ne $Collection.policies) {

            if ($Name -and $Filter) {

                $ResourceRestrictionPolicyID = ( $Collection.policies | ? name -eq $Name).resource_restriction_policy_id
                "Resource Restriction Policy ID: {0}" -f $ResourceRestrictionPolicyID | Write-Verbose

                $UriAdd = $ResourceRestrictionPolicyUri + $ResourceRestrictionPolicyID

                "URIAdd: {0} " -f $UriAdd | Write-Verbose

                try {

                    [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf

                }
                catch {
                    Throw $_
                }    

                foreach ($_Filter in $collection.scope_resource_instances) {

                    $Region = (Get-HPEGLApplication -Name $Collection.application_name ) | ? application_instance_id -eq $_Filter.application_instance_id | % region

                    $ReturnData = $Collection  |  Select-Object `
                    @{N = "name"; E = { $_Filter.name } }, `
                    @{N = "description"; E = { $_Filter.description } }, `
                    @{N = "slug"; E = { $_Filter.slug } }, `
                    @{N = "application_instance_id"; E = { $_Filter.application_instance_id } }, `
                    @{N = "region"; E = { $Region } }, `
                    @{N = "application_cid"; E = { $_Filter.application_cid } }, `
                    @{N = "type"; E = { $_Filter.type } }, `
                    @{N = "scope_type_name"; E = { $_Filter.scope_type_name } }, `
                    @{N = "resource_restriction_policy_name"; E = { $Name } }, `
                    @{N = "resource_restriction_policy_id"; E = { $_.resource_restriction_policy_id } }, `
                    @{N = "resource_restriction_policy_description"; E = { $_.description } }, `
                    @{N = "platform_cid"; E = { $_.platform_cid } }, `
                    @{N = "application_id"; E = { $_.application_id } }, `
                    @{N = "application_name"; E = { $_.application_name } }, `
                    @{N = "created_at"; E = { $_.created_at } }, `
                    @{N = "updated_at"; E = { $_.updated_at } }

                    $FilterList += $ReturnData 

                }

                $ReturnData = Invoke-RepackageObjectWithType -RawObject $FilterList -ObjectName "Resource.Restriction.Policy.GetFilter"    
                $ReturnData = $ReturnData | Sort-Object { $_.name }


            }
            elseif ($Name -and -not $Filter) {

                $ResourceRestrictionPolicyID = ( $Collection.policies | ? name -eq $Name).resource_restriction_policy_id
                "Resource Restriction Policy ID: {0}" -f $ResourceRestrictionPolicyID | Write-Verbose

                $UriAdd = $ResourceRestrictionPolicyUri + $ResourceRestrictionPolicyID

                "URIAdd: {0} " -f $UriAdd | Write-Verbose
                
                try {

                    [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf

                }
                catch {
                    Throw $_
                }    
                
                "Number of filters: {0} " -f $collection.scope_resource_instances.Length | write-Verbose
                
                $FilterCount = ($collection.scope_resource_instances).count

                if (-not $FilterCount) {
                    $FilterCount = 1
                }

                $ReturnData = $Collection  |  Select-Object `
                @{N = "resource_restriction_policy_name"; E = { $Name } }, `
                @{N = "resource_restriction_policy_id"; E = { $_.resource_restriction_policy_id } }, `
                @{N = "resource_restriction_policy_description"; E = { $_.description } }, `
                @{N = "platform_cid"; E = { $_.platform_cid } }, `
                @{N = "application_id"; E = { $_.application_id } }, `
                @{N = "application_name"; E = { $_.application_name } }, `
                @{N = "filter_number"; E = { $FilterCount } }, `
                @{N = "created_at"; E = { $_.created_at } }, `
                @{N = "updated_at"; E = { $_.updated_at } }
               

                $ReturnData = Invoke-RepackageObjectWithType -RawObject $ReturnData -ObjectName "Resource.Restriction.Policy"    

            }
            else {

                $CollectionList = $Collection.policies 

                if ($Application) {

                    $CollectionList = $CollectionList | ? application_name -eq $application
                }
            
                if ($ApplicationName) {

                    $CollectionList = $CollectionList | ? application_name -eq $ApplicationName
                }

                $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Resource.Restrictions.Policy"    

                $ReturnData = $ReturnData | Sort-Object { $_.name }


            }

            return $ReturnData 

        }
        else {

            return
            
        }
 
    }
}


Function New-HPEGLResourceRestrictionPolicy {
    <#
    .SYNOPSIS
    Creates a resource restriction policy in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet creates a resource restriction policy for an application instance.
     
    Resource restriction policy can be used to limit the ability of users to perform actions against a selected
    list of resources provided by an application instance.
 
    The resource restriction policy requires that filters be created and saved with the resource restriction policy option enabled
    in the application instance. For Compute Ops Management, New-HPECOMFilter can be used.
 
    .PARAMETER PolicyName
    Name of the resource restriction policy.
 
    .PARAMETER ApplicationName
    Name of the application to which the resource restriction policy will be applied.
 
    .PARAMETER Region
    Name of the application region to which the resource restriction policy will be applied.
 
    .PARAMETER FilterName
    Name of the filter to assign to the resource restriction policy (can be retrieved using Get-HPEGLApplicationResourceRestrictionPolicyFilter).
 
    .PARAMETER Description
    Description of the resource restriction policy.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    New-HPEGLResourceRestrictionPolicy -PolicyName COM-US-West -ApplicationName "Compute Ops Management" -Region us-west -FilterName "RRP_ESXi_Group" -Description "My description"
 
    Define a resource restriction policy named "COM-US-West" for the "Compute Ops Management" application in the US-West region using the filter "RRP_ESXi_Group".
 
    .EXAMPLE
    Get-HPEGLApplicationResourceRestrictionPolicyFilter -ApplicationName "Compute Ops Management" -Region us-west | New-HPEGLResourceRestrictionPolicy -PolicyName RRP_Group_1
 
    Define a resource restriction policy named "RRP_Group_1" for the "Compute Ops Management" application in the US-West region using all available filters in this application instance.
 
    .INPUTS
    System.Collections.ArrayList
        List of resource restriction policy filter(s) from Get-HPEGLApplicationResourceRestrictionPolicyFilter.
 
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - Name of the resource restriction policy object attempted to be created
        * Application - Name of the application to which the resource restriction policy object will be applied
        * Region - Name of the application region to which the resource restriction policy object will be applied
        * Filtername - Name of the filter to assign to the resource restriction policy
        * Status - Status of the creation attempt (Failed for http error return; Complete if the creation is successful )
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLResourceRestrictionPolicy
    Remove-HPEGLResourceRestrictionPolicy
    Get-HPEGLApplicationResourceRestrictionPolicy
    Get-HPEGLApplicationResourceRestrictionPolicyFilter
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
                
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$PolicyName,
            
        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Alias('application_name')]
        [String]$ApplicationName,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [String]$Region,

        [Parameter (Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'Default')]
        [Alias('filter_name')]
        [String]$FilterName,

        [Parameter (Mandatory = $False, ParameterSetName = 'Default')]
        [String]$Description,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif
       
    ) 

    Begin {

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

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

        $objStatus = @{}
        $FilternamesList = [System.Collections.ArrayList]::new()
        $objStatus.Filtername = [System.Collections.ArrayList]::new()


    }

    Process {

        try {
            $Application = Get-HPEGLApplication -Provisioned -Name $ApplicationName -Region $Region
            
        }
        catch {    
            Throw $_

        }

        
        # Build object for the output
        $objStatus = [pscustomobject]@{

            Name        = $PolicyName
            Application = $ApplicationName
            Region      = $Region 
            Filtername  = $FilterName
            Status      = $Null
            Details     = $Null
            Exception   = $Null
                                  
        }


        if ( $ApplicationName -eq "HPE GreenLake platform") {
            # Must return a message if Application is CCS
            "{0}: HPE GreenLake platform application does not support RRP!" -f $ApplicationName | Write-Verbose

            $objStatus.Status = "Failed"
            $objStatus.Details = "HPE GreenLake platform application does not support resource restriction policy!"

        }
        elseif (-not $Application) {
            # Must return a message if Application is not provisioned in the region
            "{0}: Application instance cannot be found!" -f $ApplicationName | Write-Verbose

            $objStatus.Status = "Failed"
            $objStatus.Details = "Application instance cannot be found!"

        }
        else {

            $applicationID = $Application.application_id
            $ApplicatrionCid = $Application.application_customer_id
            $ApplicationInstanceId = $Application.application_instance_id

            $UriAdd = $SetResourceRestrictionPolicyUri + "/" + $applicationID + "/resource_restriction"

            # Get filters
            try {
                $FiltersList = Get-HPEGLApplicationResourceRestrictionPolicyFilter -ApplicationName $ApplicationName -Region $Region
            }
            catch {
                Throw $_
            }
            
            $Filterfound = $FiltersList | ? filter_name -eq $FilterName

            if (-not $Filterfound) {
                # Must return a message if Application is not provisioned in the region
                "{0}: Filter name cannot be found in this application instance!" -f $Filtername | Write-Verbose
    
                $objStatus.Status = "Failed"
                $objStatus.Details = "Filter name cannot be found in this application instance!"
    
            }
            else {

                "Filter {0} found" -f $Filtername | Write-Verbose

                $Slug = $Filterfound.slug
                $ScopeTypeName = $Filterfound.scope_type_name
                $ScopeTypeSlug = $Filterfound.scope_type_slug

                
                # Build object
               
                $FilterList += [PSCustomObject]@{
                    name                    = $Filtername
                    slug                    = $Slug 
                    description             = $Null
                    matcher                 = $Slug 
                    scope_type_name         = $ScopeTypeName
                    scope_type_slug         = $ScopeTypeSlug
                    type                    = $ScopeTypeSlug
                    application_cid         = $ApplicatrionCid
                    application_instance_id = $ApplicationInstanceId
                }
              
         
                # Build payload
                $payload = [PSCustomObject]@{

                    name                     = $PolicyName
                    description              = $Description
                    application_name         = $ApplicationName
                    scope_resource_instances = $FilterList

                } | ConvertTo-Json -Depth 5

                $FilternamesList += $FilterName
              
            
            }
        }
    }

    end {

        $FilternamesList | write-verbose

        foreach ($Item in $FilternamesList) {
  
            $objStatus.filtername += $Item
        }
          

        # Set resource restriction policy

        try {
            Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $payload -WhatIfBoolean $WhatIf | out-Null

            if (-not $Whatif) {

                $objStatus.Status = "Complete"
                $objStatus.Details = "Resource restriction policy successfully created!"

            }

        }
        catch {

            if (-not $Whatif) {

                if ($objStatus.Status -ne "Failed") {
                
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Resource restriction policy cannot be created!"
                    $objStatus.Exception = $_.Exception.message 
                
                }            
            }

        }    
        
        [void] $SetResourceRestrictionPolicyStatus.add($objStatus)

        if (-not $Whatif) {

            if ($SetResourceRestrictionPolicyStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more resource restriction policies failed the creation attempt!"
          
            }
        }

        Return $SetResourceRestrictionPolicyStatus

    }


}


Function Remove-HPEGLResourceRestrictionPolicy {
    <#
    .SYNOPSIS
    Remove resource restriction policies in your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet removes resource restriction policies on the HPE GreenLake platformaccount.
     
    When a resource restriction policy assigned to a user is deleted, the resource access for that user will still show as
    "Limited access" and the user will be in read only on all server resources.
 
    .PARAMETER PolicyName
    Name of the resource restriction policy to delete.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Remove-HPEGLResourceRestrictionPolicy -PolicyName COM-US-West
 
    Remove the resource restriction policy named "COM-US-West".
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * Name - Name of the resource restriction policy object attempted to be deleted
        * Status - Status of the deletion attempt (Failed for http error return; Complete if the deletion is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
 
    .LINK
    Get-HPEGLResourceRestrictionPolicy
    New-HPEGLResourceRestrictionPolicy
    Get-HPEGLApplicationResourceRestrictionPolicy
    Get-HPEGLApplicationResourceRestrictionPolicyFilter
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param( 
                
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [String]$PolicyName,
            
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $DeleteResourceRestrictionPolicyUri

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

    }

    Process {

        try {
            $ResourceRestrictionPolicy = Get-HPEGLResourceRestrictionPolicy -Name $PolicyName
            
        }
        catch {    
            Throw $_

        }

        # Build object for the output
        $objStatus = [pscustomobject]@{

            Name      = $PolicyName
            Status    = $Null
            Details   = $Null
            Exception = $Null
                          
        }


        if ($ResourceRestrictionPolicy) {
                  
            $ID = [System.Collections.ArrayList]@($ResourceRestrictionPolicy.resource_restriction_policy_id)
                         
            # Build payload
            $payload = [PSCustomObject]@{

                ids = $ID
              
            } | ConvertTo-Json -Depth 5


            # Remove resource restriction policy

            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'DELETE' -body $payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Resource restriction policy successfully deleted!"
        
                }
    
            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Resource restriction policy cannot be deleted!"
                    $objStatus.Exception = $_.Exception.message 
                }

            }    

        }
        else {

            # Must return a message if policy not found
            "{0}: Resource Restriction Policy cannot be found!" -f $PolicyName | Write-Verbose
    
            $objStatus.Status = "Failed"
            $objStatus.Details = "Resource restriction policy cannot be found!"

        }
 
        [void]$RemoveResourceRestrictionPolicyStatus.add($objStatus)
    
    }
    end {

        if (-not $Whatif) {

            if ($RemoveResourceRestrictionPolicyStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more resource restriction policies failed the deletion attempt!"
          
            }
        }

        Return $RemoveResourceRestrictionPolicyStatus

    }
}


Function Get-HPEGLAccount {
    <#
    .SYNOPSIS
    Retrieve current HPE GreenLake company account details.
 
    .DESCRIPTION
    This Cmdlet returns the general information of the current HPE GreenLake account.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLAccount
 
    Return your current account's general information.
 
    .EXAMPLE
    Get-HPEGLAccount -ActivationKey
 
    Return the current account's activation key. The activation key is for instance required to connect iLOs to Compute Ops Management.
 
    .LINK
    Get-HPEGLAccounts
    New-HPEGLAccount
    Use-HPEGLAccount
    Set-HPEGLAccount
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 
        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$ActivationKey,

        [Parameter (Mandatory = $false, ParameterSetName = 'Default')]
        [Switch]$Whatif
    ) 


    Begin {

        $UriAdd = $AccountProfileContactUri
        
    }

    Process {

        if ($ActivationKey) {

            if ($HPEGreenLakeSession.customerId) {
                return $HPEGreenLakeSession.customerId
                
            }
            else {
                "Error - No session found! Connect-HPEGL must be executed first!"
                return
            }
        }
        else {
            $ReturnData = @()
        
            try {
                [array]$Collection = Invoke-HPEGLWebRequest -Method GET -UriAdd $UriAdd -whatifBoolean $WhatIf
            }
            catch {
                Throw $_
            }
   
   
            if ($Null -ne $Collection ) {

                $ReturnData = Invoke-RepackageObjectWithType -RawObject $Collection -ObjectName "Account"    
                return $ReturnData  
            }
            else {

                return            
            }
        }
 
    }
}


Function Get-HPEGLAccounts {
    <#
    .SYNOPSIS
    Displays all HPE GreenLake company accounts.
 
    .DESCRIPTION
    This Cmdlet returns a list of all company accounts available on your HPE GreenLake platform.
    The "current" column shows the company name you are currently connected to.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLAccounts
 
    Return all company accounts available on your HPE GreenLake platform.
 
    .LINK
    Get-HPEGLAccount
    Get-HPEGLAccounts
    New-HPEGLAccount
    Use-HPEGLAccount
    Set-HPEGLAccount
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $CustomerAccountsUri
        
    }

    Process {

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

        try {
            [array]$GLCPAccounts = Invoke-HPEGLWebRequest -Method GET -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }

   
        if ($Null -ne $GLCPAccounts.customers ) {

            $Accounts = $GLCPAccounts.customers
            $AllAccounts += $Accounts

            try {
                $Myaccount = Get-HPEGLAccount 
            }
            catch {
                Throw $_
            }

            $AllAccounts += $Myaccount 

            if ($Name) {

                $AllAccounts = $AllAccounts | ? company_name -eq $name
            }
    
            $ReturnData = Invoke-RepackageObjectWithType -RawObject $AllAccounts -ObjectName "Account"    

            $ReturnData = $ReturnData | Sort-Object { $_.company_name }
    
            return $ReturnData  
        }
        else {
            
            return            
        }
 
    }
}


Function Set-HPEGLAccount {
    <#
    .SYNOPSIS
    Update company account details.
 
    .DESCRIPTION
    Updates the HPE GreenLake company account general information.
 
    .PARAMETER CompanyName
    The name of the company.
 
    .PARAMETER CompanyNameRemove
    The CompanyNameRemove directive can be used to remove the company name.
 
    .PARAMETER Country
    The country of origin for the company.
 
    .PARAMETER CountryRemove
    The CountryRemove directive can be used to remove the country information.
 
    .PARAMETER Street
    The postal street address of the company.
 
    .PARAMETER StreetRemove
    The StreetRemove directive can be used to remove the street information.
 
    .PARAMETER City
    The city of the company (optional).
     
    .PARAMETER CityRemove
    The CityRemove directive can be used to remove the city information.
 
    .PARAMETER State
    The state of the company (optional).
     
    .PARAMETER StateRemove
    The StateRemove directive can be used to remove the state information.
 
    .PARAMETER PostalCode
    The postal code of the company (optional).
     
    .PARAMETER PostalCodeRemove
    The PostalCodeRemove directive can be used to remove the postal code information.
 
    .PARAMETER PhoneNumber
    The phone number of the company (optiional).
     
    .PARAMETER PhoneNumberRemove
    The PhoneNumberRemove directive can be used to remove the phone number information.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Set-HPEGLAccount -CompanyName HPE -StreetAddress "1701 E Mossy Oaks Rd Spring" -StateOrRegion TX -Zip 77389 -City Spring -Country US
 
    Set the general information of the HPE GreenLake company account.
 
    .EXAMPLE
    Get-HPEGLAccount | Set-HPEGLAccount -StreetAddress "1701 E Mossy Oaks Rd Spring"
 
    Set a new address for the HPE GreenLake company account.
 
    .EXAMPLE
    Get-HPEGLAccount | Set-HPEGLAccount -StreetAddress2Remove
 
    Remove the street address 2 information.
 
    .INPUTS
    System.Collections.ArrayList
        List of account(s) from Get-HPEGLAccount.
 
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * CompanyName - Name of the Company account object attempted to be set
        * Status - Status of the modification attempt (Failed for http error return; Complete if the account update is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLAccount
    Get-HPEGLAccounts
    New-HPEGLAccount
    Use-HPEGLAccount
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 
        [Parameter (Mandatory = $False, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [object]$InputObject,
        [String]$CompanyName,
        [Switch]$CompanyNameRemove,
        [String]$StreetAddress,
        [Switch]$StreetAddressRemove,
        [String]$StreetAddress2,
        [Switch]$StreetAddress2Remove,
        [String]$StateOrRegion,
        [Switch]$StateOrRegionRemove,
        [String]$Zip,
        [Switch]$ZipRemove,
        [String]$City,
        [Switch]$CityRemove,
        [String]$Country,
        [Switch]$CountryRemove,
        [String]$PhoneNumber,
        [Switch]$PhoneNumberRemove,
        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $AccountProfileContactUri

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

        
    }

    Process {


        if ($InputObject) {

            $AccountDetails = $InputObject
        }
        else {

            try {
                $AccountDetails = Get-HPEGLAccount
            }
            catch {
                Throw $_
            }
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            CompanyName = $AccountDetails.company_name
            Status      = $Null
            Details     = $Null
            Exception   = $Null
                  
        }

           
        if ($CompanyName) {
                
            $AccountDetails.company_name = $CompanyName
        }
        elseif ($CompanyNameRemove  ) {

            $AccountDetails.company_name = $Null
        }

        if ($StreetAddress) {
                
            $AccountDetails.address.street_address = $StreetAddress
        }
        elseif ($StreetAddressRemove  ) {

            $AccountDetails.address.street_address = $Null
        }
      
        if ($StreetAddress2) {

            $AccountDetails.address.street_address_2 = $StreetAddress2
        }
        elseif ($StreetAddress2Remove  ) {

            $AccountDetails.address.street_address_2 = $Null
        }

        if ($StateOrRegion) {
                
            $AccountDetails.address.state_or_region = $StateOrRegion
        }
        elseif ($StateOrRegionRemove  ) {

            $AccountDetails.address.state_or_region = $Null
        }
                   
        if ($Zip) {
                
            $AccountDetails.address.zip = $Zip
        }
        elseif ($ZipRemove  ) {

            $AccountDetails.address.zip = $Null
        }
       
        if ($City) {
                
            $AccountDetails.address.city = $City
        }
        elseif ($CityRemove  ) {

            $AccountDetails.address.city = $Null
        }
       
        if ($Country) {
                
            $AccountDetails.address.country_code = $Country
        }
        elseif ($CountryRemove  ) {

            $AccountDetails.address.country_code = $Null
        }
     
        if ($PhoneNumber) {
                
            $AccountDetails.phone_number = $PhoneNumber
        }
        elseif ($PhoneNumberRemove  ) {

            $AccountDetails.phone_number = $Null
        }
 
       
        # Account modification
        try {
        
            $Response = Invoke-HPEGLWebRequest -Method 'PUT' -Body ($AccountDetails  | ConvertTo-Json -Depth 5) -UriAdd $UriAdd -whatifBoolean $WhatIf
                         
            if (-not $Whatif) {
                $objStatus.Status = "Complete"
                $objStatus.Details = ($Response | % message)
            }

        }
        catch {

            if (-not $Whatif) {
                $objStatus.Status = "Failed"
                $objStatus.Details = ($Response | % message)
                $objStatus.Exception = $_.Exception.message 
            }
        }    

        [void] $SetAccountStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($SetAccountStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more failures to update the account details!"
          
            }
        }

        Return $SetAccountStatus

    }
}


Function New-HPEGLAccount {
    <#
    .SYNOPSIS
    Creates a company account in HPE GreenLake.
 
    .DESCRIPTION
    This Cmdlet creates a company account in HPE GreenLake.
         
    When you have an HPE account and have logged in to the HPE GreenLake platform, you must create an account for your organization.
        
    .PARAMETER CompanyName
    The name of the company.
 
    .PARAMETER Country
    The country of origin for the company.
 
    .PARAMETER Street
    The postal street address of the company.
 
    .PARAMETER City
    The city of the company (optional).
 
    .PARAMETER State
    The state of the company (optional).
 
    .PARAMETER PostalCode
    The postal code of the company (optional).
 
    .PARAMETER PhoneNumber
    The phone number of the company (optiional).
 
    .PARAMETER Email
    The email address of the company (optional).
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
     
    .EXAMPLE
    New-HPEGLAccount -CompanyName "HPE Grenoble" -country France -Address "5 Rue Raymond Chanas" -City Grenoble -PostalCode 38320 -Email Welcome@hpe.com -PhoneNumber "+1 888-342-2156"
     
    Create a new company account "HPE Grenoble" in HPE GreenLake.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
     
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * CompanyName - Name of the Company account object attempted to be created
        * Status - Status of the creation attempt (Failed for http error return; Complete if the creation is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLAccount
    Get-HPEGLAccounts
    Use-HPEGLAccount
    Set-HPEGLAccount
    [${Global:HPEGreenLakeSession}]
#>

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

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$CompanyName,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia", "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard Island and McDonald Islands", "Holy See (Vatican City State)", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran, Islamic Republic of", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan", "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Macedonia, the Former Yugoslav Republic of", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of", "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Palestine, State of", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation", "Rwanda", "Saint Barthelemy", "Saint Helena, Ascension and Tristan da Cunha", "Saint Kitts and Nevis", "Saint Lucia", "Saint Martin (French part)", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Sint Maarten (Dutch part)", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic", "Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Timor-Leste", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela, Bolivarian Republic of", "Viet Nam", "Virgin Islands, British", "Virgin Islands, U.S.", "Wallis and Futuna", "Western Sahara", "Yemen", "Zambia", "Zimbabwe")]
        [String]$Country,

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$Address,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$City,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$State,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$PostalCode,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$PhoneNumber,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [ValidateScript ({ [RegEx]::IsMatch($_, "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") })]
        [String]$Email,       

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $NewAccountUri

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

               
    }

    Process {


        try {
            $Account = Get-HPEGLAccounts -name $CompanyName
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            CompanyName = $CompanyName
            Status      = $Null
            Details     = $Null
            Exception   = $Null
          
        }

        if ($Account) {
            # Must return a message if account found
            "{0}: Company account found!" -f $CompanyName  | Write-Verbose
            $objStatus.Status = "Warning"
            $objStatus.Details = "This company account already exists!"
        }
        else {

            # $User = Get-HPEGLUser -Email $HPEGreenLakeSession.username

            If ( $Country -eq "Afghanistan") { $CountryCode = "AF" }
            If ( $Country -eq "Albania") { $CountryCode = "AL" }
            If ( $Country -eq "Algeria") { $CountryCode = "DZ" }
            If ( $Country -eq "American Samoa") { $CountryCode = "AS" }
            If ( $Country -eq "Andorra") { $CountryCode = "AD" }
            If ( $Country -eq "Angola") { $CountryCode = "AO" }
            If ( $Country -eq "Anguilla") { $CountryCode = "AI" }
            If ( $Country -eq "Antarctica") { $CountryCode = "AQ" }
            If ( $Country -eq "Antigua and Barbuda") { $CountryCode = "AG" }
            If ( $Country -eq "Argentina") { $CountryCode = "AR" }
            If ( $Country -eq "Armenia") { $CountryCode = "AM" }
            If ( $Country -eq "Aruba") { $CountryCode = "AW" }
            If ( $Country -eq "Australia") { $CountryCode = "AU" }
            If ( $Country -eq "Austria") { $CountryCode = "AT" }
            If ( $Country -eq "Azerbaijan") { $CountryCode = "AZ" }
            If ( $Country -eq "Bahamas") { $CountryCode = "BS" }
            If ( $Country -eq "Bahrain") { $CountryCode = "BH" }
            If ( $Country -eq "Bangladesh") { $CountryCode = "BD" }
            If ( $Country -eq "Barbados") { $CountryCode = "BB" }
            If ( $Country -eq "Belarus") { $CountryCode = "BY" }
            If ( $Country -eq "Belgium") { $CountryCode = "BE" }
            If ( $Country -eq "Belize") { $CountryCode = "BZ" }
            If ( $Country -eq "Benin") { $CountryCode = "BJ" }
            If ( $Country -eq "Bermuda") { $CountryCode = "BM" }
            If ( $Country -eq "Bhutan") { $CountryCode = "BT" }
            If ( $Country -eq "Bolivia") { $CountryCode = "BO" }
            If ( $Country -eq "Bosnia and Herzegovina") { $CountryCode = "BA" }
            If ( $Country -eq "Botswana") { $CountryCode = "BW" }
            If ( $Country -eq "Bouvet Island") { $CountryCode = "BV" }
            If ( $Country -eq "Brazil") { $CountryCode = "BR" }
            If ( $Country -eq "British Indian Ocean Territory") { $CountryCode = "IO" }
            If ( $Country -eq "Brunei Darussalam") { $CountryCode = "BN" }
            If ( $Country -eq "Bulgaria") { $CountryCode = "BG" }
            If ( $Country -eq "Burkina Faso") { $CountryCode = "BF" }
            If ( $Country -eq "Burundi") { $CountryCode = "BI" }
            If ( $Country -eq "Cambodia") { $CountryCode = "KH" }
            If ( $Country -eq "Cameroon") { $CountryCode = "CM" }
            If ( $Country -eq "Canada") { $CountryCode = "CA" }
            If ( $Country -eq "Cape Verde") { $CountryCode = "CV" }
            If ( $Country -eq "Cayman Islands") { $CountryCode = "KY" }
            If ( $Country -eq "Central African Republic") { $CountryCode = "CF" }
            If ( $Country -eq "Chad") { $CountryCode = "TD" }
            If ( $Country -eq "Chile") { $CountryCode = "CL" }
            If ( $Country -eq "China") { $CountryCode = "CN" }
            If ( $Country -eq "Christmas Island") { $CountryCode = "CX" }
            If ( $Country -eq "Cocos (Keeling) Islands") { $CountryCode = "CC" }
            If ( $Country -eq "Colombia") { $CountryCode = "CO" }
            If ( $Country -eq "Comoros") { $CountryCode = "KM" }
            If ( $Country -eq "Congo") { $CountryCode = "CG" }
            If ( $Country -eq "Congo, the Democratic Republic of the") { $CountryCode = "CD" }
            If ( $Country -eq "Cook Islands") { $CountryCode = "CK" }
            If ( $Country -eq "Costa Rica") { $CountryCode = "CR" }
            If ( $Country -eq "Cote d'Ivoire") { $CountryCode = "CI" }
            If ( $Country -eq "Croatia") { $CountryCode = "HR" }
            If ( $Country -eq "Cuba") { $CountryCode = "CU" }
            If ( $Country -eq "Cyprus") { $CountryCode = "CY" }
            If ( $Country -eq "Czech Republic") { $CountryCode = "CZ" }
            If ( $Country -eq "Denmark") { $CountryCode = "DK" }
            If ( $Country -eq "Djibouti") { $CountryCode = "DJ" }
            If ( $Country -eq "Dominica") { $CountryCode = "DM" }
            If ( $Country -eq "Dominican Republic") { $CountryCode = "DO" }
            If ( $Country -eq "Ecuador") { $CountryCode = "EC" }
            If ( $Country -eq "Egypt") { $CountryCode = "EG" }
            If ( $Country -eq "El Salvador") { $CountryCode = "SV" }
            If ( $Country -eq "Equatorial Guinea") { $CountryCode = "GQ" }
            If ( $Country -eq "Eritrea") { $CountryCode = "ER" }
            If ( $Country -eq "Estonia") { $CountryCode = "EE" }
            If ( $Country -eq "Ethiopia") { $CountryCode = "ET" }
            If ( $Country -eq "Falkland Islands (Malvinas)") { $CountryCode = "FK" }
            If ( $Country -eq "Faroe Islands") { $CountryCode = "FO" }
            If ( $Country -eq "Fiji") { $CountryCode = "FJ" }
            If ( $Country -eq "Finland") { $CountryCode = "FI" }
            If ( $Country -eq "France") { $CountryCode = "FR" }
            If ( $Country -eq "French Guiana") { $CountryCode = "GF" }
            If ( $Country -eq "French Polynesia") { $CountryCode = "PF" }
            If ( $Country -eq "French Southern Territories") { $CountryCode = "TF" }
            If ( $Country -eq "Gabon") { $CountryCode = "GA" }
            If ( $Country -eq "Gambia") { $CountryCode = "GM" }
            If ( $Country -eq "Georgia") { $CountryCode = "GE" }
            If ( $Country -eq "Germany") { $CountryCode = "DE" }
            If ( $Country -eq "Ghana") { $CountryCode = "GH" }
            If ( $Country -eq "Gibraltar") { $CountryCode = "GI" }
            If ( $Country -eq "Greece") { $CountryCode = "GR" }
            If ( $Country -eq "Greenland") { $CountryCode = "GL" }
            If ( $Country -eq "Grenada") { $CountryCode = "GD" }
            If ( $Country -eq "Guadeloupe") { $CountryCode = "GP" }
            If ( $Country -eq "Guam") { $CountryCode = "GU" }
            If ( $Country -eq "Guatemala") { $CountryCode = "GT" }
            If ( $Country -eq "Guernsey") { $CountryCode = "GG" }
            If ( $Country -eq "Guinea") { $CountryCode = "GN" }
            If ( $Country -eq "Guinea-Bissau") { $CountryCode = "GW" }
            If ( $Country -eq "Guyana") { $CountryCode = "GY" }
            If ( $Country -eq "Haiti") { $CountryCode = "HT" }
            If ( $Country -eq "Heard Island and McDonald Islands") { $CountryCode = "HM" }
            If ( $Country -eq "Holy See (Vatican City State)") { $CountryCode = "VA" }
            If ( $Country -eq "Honduras") { $CountryCode = "HN" }
            If ( $Country -eq "Hong Kong") { $CountryCode = "HK" }
            If ( $Country -eq "Hungary") { $CountryCode = "HU" }
            If ( $Country -eq "Iceland") { $CountryCode = "IS" }
            If ( $Country -eq "India") { $CountryCode = "IN" }
            If ( $Country -eq "Indonesia") { $CountryCode = "ID" }
            If ( $Country -eq "Iran, Islamic Republic of") { $CountryCode = "IR" }
            If ( $Country -eq "Iraq") { $CountryCode = "IQ" }
            If ( $Country -eq "Ireland") { $CountryCode = "IE" }
            If ( $Country -eq "Isle of Man") { $CountryCode = "IM" }
            If ( $Country -eq "Israel") { $CountryCode = "IL" }
            If ( $Country -eq "Italy") { $CountryCode = "IT" }
            If ( $Country -eq "Jamaica") { $CountryCode = "JM" }
            If ( $Country -eq "Japan") { $CountryCode = "JP" }
            If ( $Country -eq "Jersey") { $CountryCode = "JE" }
            If ( $Country -eq "Jordan") { $CountryCode = "JO" }
            If ( $Country -eq "Kazakhstan") { $CountryCode = "KZ" }
            If ( $Country -eq "Kenya") { $CountryCode = "KE" }
            If ( $Country -eq "Kiribati") { $CountryCode = "KI" }
            If ( $Country -eq "Korea, Democratic People's Republic of") { $CountryCode = "KP" }
            If ( $Country -eq "Korea, Republic of") { $CountryCode = "KR" }
            If ( $Country -eq "Kuwait") { $CountryCode = "KW" }
            If ( $Country -eq "Kyrgyzstan") { $CountryCode = "KG" }
            If ( $Country -eq "Lao People's Democratic Republic") { $CountryCode = "LA" }
            If ( $Country -eq "Latvia") { $CountryCode = "LV" }
            If ( $Country -eq "Lebanon") { $CountryCode = "LB" }
            If ( $Country -eq "Lesotho") { $CountryCode = "LS" }
            If ( $Country -eq "Liberia") { $CountryCode = "LR" }
            If ( $Country -eq "Libya") { $CountryCode = "LY" }
            If ( $Country -eq "Liechtenstein") { $CountryCode = "LI" }
            If ( $Country -eq "Lithuania") { $CountryCode = "LT" }
            If ( $Country -eq "Luxembourg") { $CountryCode = "LU" }
            If ( $Country -eq "Macao") { $CountryCode = "MO" }
            If ( $Country -eq "Macedonia, the Former Yugoslav Republic of") { $CountryCode = "MK" }
            If ( $Country -eq "Madagascar") { $CountryCode = "MG" }
            If ( $Country -eq "Malawi") { $CountryCode = "MW" }
            If ( $Country -eq "Malaysia") { $CountryCode = "MY" }
            If ( $Country -eq "Maldives") { $CountryCode = "MV" }
            If ( $Country -eq "Mali") { $CountryCode = "ML" }
            If ( $Country -eq "Malta") { $CountryCode = "MT" }
            If ( $Country -eq "Marshall Islands") { $CountryCode = "MH" }
            If ( $Country -eq "Martinique") { $CountryCode = "MQ" }
            If ( $Country -eq "Mauritania") { $CountryCode = "MR" }
            If ( $Country -eq "Mauritius") { $CountryCode = "MU" }
            If ( $Country -eq "Mayotte") { $CountryCode = "YT" }
            If ( $Country -eq "Mexico") { $CountryCode = "MX" }
            If ( $Country -eq "Micronesia, Federated States of") { $CountryCode = "FM" }
            If ( $Country -eq "Moldova, Republic of") { $CountryCode = "MD" }
            If ( $Country -eq "Monaco") { $CountryCode = "MC" }
            If ( $Country -eq "Mongolia") { $CountryCode = "MN" }
            If ( $Country -eq "Montenegro") { $CountryCode = "ME" }
            If ( $Country -eq "Montserrat") { $CountryCode = "MS" }
            If ( $Country -eq "Morocco") { $CountryCode = "MA" }
            If ( $Country -eq "Mozambique") { $CountryCode = "MZ" }
            If ( $Country -eq "Myanmar") { $CountryCode = "MM" }
            If ( $Country -eq "Namibia") { $CountryCode = "NA" }
            If ( $Country -eq "Nauru") { $CountryCode = "NR" }
            If ( $Country -eq "Nepal") { $CountryCode = "NP" }
            If ( $Country -eq "Netherlands") { $CountryCode = "NL" }
            If ( $Country -eq "New Caledonia") { $CountryCode = "NC" }
            If ( $Country -eq "New Zealand") { $CountryCode = "NZ" }
            If ( $Country -eq "Nicaragua") { $CountryCode = "NI" }
            If ( $Country -eq "Niger") { $CountryCode = "NE" }
            If ( $Country -eq "Nigeria") { $CountryCode = "NG" }
            If ( $Country -eq "Niue") { $CountryCode = "NU" }
            If ( $Country -eq "Norfolk Island") { $CountryCode = "NF" }
            If ( $Country -eq "Northern Mariana Islands") { $CountryCode = "MP" }
            If ( $Country -eq "Norway") { $CountryCode = "NO" }
            If ( $Country -eq "Oman") { $CountryCode = "OM" }
            If ( $Country -eq "Pakistan") { $CountryCode = "PK" }
            If ( $Country -eq "Palau") { $CountryCode = "PW" }
            If ( $Country -eq "Palestine, State of") { $CountryCode = "PS" }
            If ( $Country -eq "Panama") { $CountryCode = "PA" }
            If ( $Country -eq "Papua New Guinea") { $CountryCode = "PG" }
            If ( $Country -eq "Paraguay") { $CountryCode = "PY" }
            If ( $Country -eq "Peru") { $CountryCode = "PE" }
            If ( $Country -eq "Philippines") { $CountryCode = "PH" }
            If ( $Country -eq "Pitcairn") { $CountryCode = "PN" }
            If ( $Country -eq "Poland") { $CountryCode = "PL" }
            If ( $Country -eq "Portugal") { $CountryCode = "PT" }
            If ( $Country -eq "Puerto Rico") { $CountryCode = "PR" }
            If ( $Country -eq "Qatar") { $CountryCode = "QA" }
            If ( $Country -eq "Reunion") { $CountryCode = "RE" }
            If ( $Country -eq "Romania") { $CountryCode = "RO" }
            If ( $Country -eq "Russian Federation") { $CountryCode = "RU" }
            If ( $Country -eq "Rwanda") { $CountryCode = "RW" }
            If ( $Country -eq "Tajikistan") { $CountryCode = "TJ" }
            If ( $Country -eq "Tanzania, United Republic of") { $CountryCode = "TZ" }
            If ( $Country -eq "Thailand") { $CountryCode = "TH" }
            If ( $Country -eq "Timor-Leste") { $CountryCode = "TL" }
            If ( $Country -eq "Togo") { $CountryCode = "TG" }
            If ( $Country -eq "Tokelau") { $CountryCode = "TK" }
            If ( $Country -eq "Tonga") { $CountryCode = "TO" }
            If ( $Country -eq "Trinidad and Tobago") { $CountryCode = "TT" }
            If ( $Country -eq "Tunisia") { $CountryCode = "TN" }
            If ( $Country -eq "Turkey") { $CountryCode = "TR" }
            If ( $Country -eq "Turkmenistan") { $CountryCode = "TM" }
            If ( $Country -eq "Turks and Caicos Islands") { $CountryCode = "TC" }
            If ( $Country -eq "Tuvalu") { $CountryCode = "TV" }
            If ( $Country -eq "Uganda") { $CountryCode = "UG" }
            If ( $Country -eq "Ukraine") { $CountryCode = "UA" }
            If ( $Country -eq "United Arab Emirates") { $CountryCode = "AE" }
            If ( $Country -eq "United Kingdom") { $CountryCode = "GB" }
            If ( $Country -eq "United States") { $CountryCode = "US" }
            If ( $Country -eq "United States Minor Outlying Islands") { $CountryCode = "UM" }
            If ( $Country -eq "Uruguay") { $CountryCode = "UY" }
            If ( $Country -eq "Uzbekistan") { $CountryCode = "UZ" }
            If ( $Country -eq "Vanuatu") { $CountryCode = "VU" }
            If ( $Country -eq "Venezuela, Bolivarian Republic of") { $CountryCode = "VE" }
            If ( $Country -eq "Viet Nam") { $CountryCode = "VN" }
            If ( $Country -eq "Virgin Islands, British") { $CountryCode = "VG" }
            If ( $Country -eq "Virgin Islands, U.S.") { $CountryCode = "VI" }
            If ( $Country -eq "Wallis and Futuna") { $CountryCode = "WF" }
            If ( $Country -eq "Western Sahara") { $CountryCode = "EH" }
            If ( $Country -eq "Yemen") { $CountryCode = "YE" }
            If ( $Country -eq "Zambia") { $CountryCode = "ZM" }
            If ( $Country -eq "Zimbabwe") { $CountryCode = "ZW" }

            # Create payload

            $Payload = [PSCustomObject]@{
                company_name = $CompanyName
                created_by   = $HPEGreenLakeSession.username
                email        = $Email
                phone_number = $PhoneNumber
                address      = @{
                    street_address  = $Address
                    city            = $City
                    state_or_region = $State
                    zip             = $PostalCode
                    country_code    = $CountryCode
                }
            } | ConvertTo-Json -Depth 5


            # Create account

            try {
                Invoke-HPEGLWebRequest -uriadd $UriAdd -method 'POST' -body $Payload -WhatIfBoolean $WhatIf | out-Null

                if (-not $Whatif) {

                    "{0}: Account successfully created!" -f $CompanyName | Write-Verbose

                    $objStatus.Status = "Complete"
                    $objStatus.Details = "Account successfully created!"

                }


            }
            catch {

                if (-not $Whatif) {
                    $objStatus.Status = "Failed"
                    $objStatus.Details = "Account cannot be created!"
                    $objStatus.Exception = $_.Exception.message 

                }
            }
           
        }

        [void] $AccountCreationStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($AccountCreationStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more failures during the attempt to create the account!"
          
            }
        }

        Return $AccountCreationStatus

    }
}


Function Use-HPEGLAccount {
    <#
    .SYNOPSIS
    Switch between HPE GreenLake accounts.
     
    .DESCRIPTION
    When you have multiple HPE GreenLake accounts, you can use this cmdlet to switch between those accounts and manage them independently.
         
    .PARAMETER CompanyName
    Name of the HPE GreenLake account.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Use-HPEGLAccount -CompanyName "DreamCompany"
 
    Switch from the current account to the "DreamCompany" HPE GreenLake account.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
        When an error occurs, a custom status object or array of objects containing the following PsCustomObject keys is displayed:
        * CompanyName - Name of the Company account object attempted to be set
        * Status - Status of the modification attempt (Failed for http error return; Complete if the account change is successful; Warning if no action is needed)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    HPEGreenLakeSession
        When a valid connection is established with a new HPE GreenLake account, ${Global:HPEGreenLakeSession} connection tracker variable is displayed.
 
    .LINK
    Get-HPEGLAccount
    Get-HPEGLAccounts
    New-HPEGLAccount
    Set-HPEGLAccount
    [${Global:HPEGreenLakeSession}]
     
   #>


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

        [Parameter (Mandatory, ParameterSetName = "Default")]
        [ValidateNotNullOrEmpty()]
        [String]$CompanyName,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 


    Begin {

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

        
    }

    Process {

        # Check if the account exists
        try {
            $Account = Get-HPEGLAccounts -Name $CompanyName
        }
        catch {
            Throw $_
        }

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            CompanyName = $CompanyName
            Status      = $Null
            Details     = $Null
            Exception   = $Null
                  
        }

        if (-not $Account) {
            # Must return a message if company not found
            "{0}: Company account not found!" -f $CompanyName | Write-Verbose

            $objStatus.Status = "Failed"
            $objStatus.Details = "Company account cannot be found!"
  
        }
        else {       

            # Check if the account is not the current one
            try {
                $CurrentAccount = Get-HPEGLAccount  
            }
            catch {
                Throw $_
            }
        
            if ( $CurrentAccount.company_name -eq $CompanyName  ) {
                # Must return a message if company is already in use
                "{0}: this account is already the one used!" -f $CompanyName 

                $objStatus.Status = "Warning"
                $objStatus.Details = "Company account is already the one used!"
      
            }
            else {                

                $PlatformCustomerId = $Account.platform_customer_id

                $Url = $HPEGLbaseURL + $UserLoadAccountUri + $PlatformCustomerId
                $Method = "GET"

                $headers = @{} 
                $headers["Accept"] = "application/json"
                $headers["Authorization"] = "Bearer $($HPEGreenLakeSession.oauth2AccessToken)"

                $NewSession = $HPEGreenLakeSession.session


                if ($Whatif) {

                    if ( -not $Body ) {
                        $Body = 'No Body'
                    }
                    write-warning "You have selected the What-IF option, so the call will not be made to HPE GreenLake console, `ninstead you will see a preview of the RestAPI call"
                    Write-host "The URI for this call will be " 
                    write-host  "$Url" -foregroundcolor green
                    Write-host "The Method of this call will be "
                    write-host -foregroundcolor green $Method
    
                    Write-host "The Header for this call will be :"
                    write-host -foregroundcolor green ($Headers | ConvertTo-JSON | Out-String)  

                }
                else {

                    try {
         
                        # Load CCS user account to get cookies session values for CCS User API authentication

                        write-verbose "Load CCS user account"
                        write-verbose "About to make rest call to URL $url"

           
                        Invoke-WebRequest -Method $Method -Uri $url -Headers $headers -WebSession $NewSession  | Out-Null

                        "CCS user account session - Cookies content:" | Write-Verbose
           
                        $cookies = $NewSession.Cookies.GetCookies($url)
                        foreach ($cookie in $cookies) { 
                            Write-Verbose "$($cookie.name) = $($cookie.value)"
                        }

               
                        Write-Verbose "CCS user session creation successful!" 

                        $global:HPEGreenLakeSession.customerId = $PlatformCustomerId
                        $global:HPEGreenLakeSession.companyName = $CompanyName 
                        $global:HPEGreenLakeSession.session = $NewSession

                        return $global:HPEGreenLakeSession
            
                    }
                    catch {         

                        if ($_.ErrorDetails.Message) {
                            $ErrorMsg = "Error: {0} - Error details: {1}" -f $_.Exception.Message, $_.ErrorDetails 
 
                        }
                        else {
                            $ErrorMsg = "Error: {0}" -f $_.Exception.Message | Write-Warning
 
                        }

            
                        "CCS user session creation - Headers content: {0}" -f ($headers | Out-String) | Write-Verbose

                        if (-not $Whatif) {
                            $objStatus.Status = "Failed"
                            $objStatus.Details = $ErrorMsg
                            $objStatus.Exception = $_.Exception.message 
                        }
            
                    }
                }
            }
        }

        [void] $UseAccountStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($UseAccountStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more failures to use this company account!"
          
            }
        }

        Return $UseAccountStatus

    }
}


Function Get-HPEGLUserPreference {
    <#
    .SYNOPSIS
    Displays HPE GreenLake user preferences.
 
    .DESCRIPTION
    This Cmdlet returns the HPE GreenLake user profile preferences, such as language and session timeout.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLUserPreference
 
    Return language and session timeout of the current HPE GreenLake user profile.
 
    .LINK
    Set-HPEGLUserPreference
    Get-HPEGLUser
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 

        [Parameter (Mandatory = $False)]
        [Switch]$Whatif
    ) 

    Begin {

        $UriAdd = $UserPreferencesUri
        
    }

    Process {

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

        try {
            [array]$UserPreferences = Invoke-HPEGLWebRequest -Method GET -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }

   
        if ($Null -ne $UserPreferences ) {

    
            $ReturnData = Invoke-RepackageObjectWithType -RawObject $UserPreferences -ObjectName "User.Preference"    
    
            return $ReturnData  
        }
        else {
            
            return            
        }
 
    }
}


Function Set-HPEGLUserPreference {
    <#
    .SYNOPSIS
    Update HPE GreenLake user preferences.
 
    .DESCRIPTION
    Cmdlet can be used to update the HPE GreenLake user preferences such as session timeout and Language.
 
    .PARAMETER Language
    The Language directive can be used to set the language to use in the HPE GreenLake UI.
    Supported languages: Chinese, English, French, German, Japanese, Korean, Portuguese, Russian, Spanish, ltalian
 
    .PARAMETER SessionTimeoutInMinutes
    The SessionTimeoutInMinutes directive can be used to set the session timeout (in minutes).
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Set-HPEGLUserPreference -Language French
 
    Sets the language of the HPE GreenLake user interface to French.
 
    .EXAMPLE
    Set-HPEGLUserPreference -SessionTimeout 120
 
    Set the session timeout of the HPE GreenLake user interface to 120 minutes.
 
    .INPUTS
    None. You cannot pipe objects to this Cmdlet.
 
    .OUTPUTS
    System.Collections.ArrayList
    A custom status object or array of objects containing the following PsCustomObject keys:
        * Email - Email address of the user
        * Status - Status of the modification attempt (Failed for http error return; Complete if the update of the user preferences is successful)
        * Details - More information about the status
        * Exception - Exception information of the error generated
 
    .LINK
    Get-HPEGLAccount
    Get-HPEGLAccounts
    New-HPEGLAccount
    Use-HPEGLAccount
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 

        [ValidateNotNullOrEmpty()]
        [ValidateSet('Chinese', 'English', 'French', 'German', 'Japanese', 'Korean', 'Portuguese', 'Russian', 'Spanish', 'ltalian')]
        [String]$Language,
        
        [Int]$SessionTimeoutInMinutes,

        [Switch]$Whatif
       
    ) 

    Begin {

        $UriAdd = $UserPreferencesUri

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

        
    }

    Process {

        try {
            $UserPreferences = Get-HPEGLUserPreference 
        }
        catch {
            Throw $_
        }
    

        # Build object for the output
        $objStatus = [pscustomobject]@{
  
            Email     = $HPEGreenLakeSession.username
            Status    = $Null
            Details   = $Null
            Exception = $Null
                  
        }

               
        if ($Language) {

            if ($Language -eq 'Chinese') {
                $LanguageSet = 'cn'
            }  
            if ($Language -eq 'English') {
                $LanguageSet = 'en'
            }  
            if ($Language -eq 'French') {
                $LanguageSet = 'fr'
            }  
            if ($Language -eq 'German') {
                $LanguageSet = 'de'
            }  
            if ($Language -eq 'Japanese') {
                $LanguageSet = 'jp'
            }  
            if ($Language -eq 'Korean') {
                $LanguageSet = 'ko'
            }  
            if ($Language -eq 'Portuguese') {
                $LanguageSet = 'br'
            }  
            if ($Language -eq 'Russian') {
                $LanguageSet = 'ru'
            }  
            if ($Language -eq 'Spanish') {
                $LanguageSet = 'es'
            }  
            if ($Language -eq 'ltalian') {
                $LanguageSet = 'it'
            }

            $UserPreferences.language = $LanguageSet
        }

 
        if ($SessionTimeoutInMinutes) {
                
            $UserPreferences.idle_timeout = $SessionTimeoutInMinutes * 60
        }

        if (-Not $Language -and -Not $SessionTimeoutInMinutes) {
            $objStatus.Status = "Failed"
            $objStatus.Details = "At least one parameter must be provided!"
            [void] $SetUserPreferenceStatus.add($objStatus)
            return
        }

       
        # User Preferences modification
        try {
        
            $Response = Invoke-HPEGLWebRequest -Method 'PUT' -Body ($UserPreferences  | ConvertTo-Json -Depth 5) -UriAdd $UriAdd -whatifBoolean $WhatIf
                         
            if (-not $Whatif) {
   
                $Global:HPEGreenLakeSession.userSessionIdleTimeout = $SessionTimeoutInMinutes

                $objStatus.Status = "Complete"
                $objStatus.Details = ($Response | % message)
            }

        }
        catch {

            if (-not $Whatif) {
                $objStatus.Status = "Failed"
                $objStatus.Details = ($Response | % message)
                $objStatus.Exception = $_.Exception.message 
            }
        }    

        [void] $SetUserPreferenceStatus.add($objStatus)

    }

    end {

        if (-not $Whatif) {

            if ($SetUserPreferenceStatus | Where-Object { $_.Status -eq "Failed" }) {
  
                write-error "One or more failures to update the user preferences!"
          
            }
        }


        Return $SetUserPreferenceStatus

    }
}


############################ LOGS ###################################


Function Get-HPEGLAuditLog {
    <#
    .SYNOPSIS
    View changes and processes within your HPE GreenLake account.
 
    .DESCRIPTION
    This Cmdlet returns the last 50 audit logs of the HPE GreenLake account.
 
    .PARAMETER Category
    Optional parameter that can be used to filter audit logs for a certain category. A predefined list of categories is provided.
 
    .PARAMETER Limit
    Parameter to change the limit of audit logs to return.
 
    .PARAMETER SearchString
    Optional parameter that can be used to filter audit logs with a search string, can be the email address of a given user, an IP address, etc.
 
    .PARAMETER WhatIf
    The WhatIf directive will show you the RAW RestAPI call that would be made to GLCP instead of sending the request.
    This option is very helpful when trying to understand the inner workings of the native RestAPI calls that GLCP uses.
 
    .EXAMPLE
    Get-HPEGLAuditLog
 
    Return the last fifty audit logs of the HPE GreenLake account.
 
    .EXAMPLE
    Get-HPEGLAuditLog -Category 'Subscription Management'
 
    Return the last fifty audit logs of the 'Subscription Management' category.
 
    .EXAMPLE
    Get-HPEGLAuditLog -Category Authorization -Limit 5
 
    Return the last five audit logs of the "Authorization" category.
 
    .EXAMPLE
    Get-HPEGLAuditLog -SearchString Leonhard.Euler@mathematician.com -Category 'Customer Management'
 
    Return Leonhard Euler's last fifty audit logs for the "Customer Management" category.
 
    .LINK
    Connect-HPEGL
    [${Global:HPEGreenLakeSession}]
     
   #>

    [CmdletBinding()]
    Param( 
        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [validateSet(
            "API Gateway",
            "App Management",
            "Authorization",
            "Configuration",
            "Customer Management",
            "Delete Device",
            "Delete Fingerprint",
            "Device Direct",
            "Device Management",
            "Federated User Activity",
            "Firmware Registry",
            "Gateway Management",
            "General Settings",
            "Global Trade Export License Check",
            "Groups",
            "Inventory",
            "Licensing",
            "Location Management",
            "Network Device",
            "Notifications Service",
            "Order Processor",
            "Orders",
            "Others",
            "Reboot",
            "Rbac",
            "SAML SSO",
            "Subscription Management",
            "System Setup",
            "User Activity",
            "User and Customer Account",
            "Management",
            "User Management",
            "Organization"            
        )]
        [String]$Category,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Int]$Limit = 50,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [String]$SearchString,

        [Parameter (Mandatory = $False, ParameterSetName = "Default")]
        [Switch]$Whatif
    ) 


    Begin {

        $UriAdd = $AuditLogsUri + "&limit=$Limit"

        if ($category) {
            $UriAdd = $UriAdd + "&category=$Category"
        }

        if ($SearchString) {
            $UriAdd = $UriAdd + "&_all=$SearchString"
        }
        
    }

    Process {

        $ReturnData = @()
        
        try {
            [array]$Collection = Invoke-HPEGLWebRequest -Method Get -UriAdd $UriAdd -whatifBoolean $WhatIf
        }
        catch {
            Throw $_
        }
   
   
        if ($Null -ne $Collection.audits) {

            $CollectionList = $Collection.audits 
            
           
            $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "Auditlog"    

            $ReturnData = $ReturnData | Sort-Object -Descending { $_.audit_created_at }

            return $ReturnData 
        }
        else {

            return
            
        }
 
    }
}



# Set $HPEGLLibraryVersion Global variable

# $versionMajorMinorBuild = "{0}.{1}.{2}" -f $ModuleVersion.Major, $ModuleVersion.Minor, $ModuleVersion.Build

$LibraryVersion = New-Object -TypeName PSObject -Property @{
    LibraryVersion = $ModuleVersion
    
}

$LibraryVersion = Invoke-RepackageObjectWithType -RawObject $LibraryVersion -ObjectName "Library.Version"     

New-Variable -Name HPEGLLibraryVersion -Scope Global -Value $LibraryVersion -Option Constant -ErrorAction SilentlyContinue






# SIG # Begin signature block
# MIIsFAYJKoZIhvcNAQcCoIIsBTCCLAECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCALzteNgEd+KlCt
# H0jDY+jodsSrAM9sWnpvr51RfesRiqCCEXYwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggXhMIIESaADAgECAhEAiC+b
# fqa5zZMYuwvoX6mNzTANBgkqhkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYG
# A1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBD
# b2RlIFNpZ25pbmcgQ0EgUjM2MB4XDTIyMDYwNzAwMDAwMFoXDTIzMDYwNzIzNTk1
# OVowdzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMSswKQYDVQQKDCJIZXds
# ZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBDb21wYW55MSswKQYDVQQDDCJIZXdsZXR0
# IFBhY2thcmQgRW50ZXJwcmlzZSBDb21wYW55MIIBojANBgkqhkiG9w0BAQEFAAOC
# AY8AMIIBigKCAYEAqIB+RRqpvViU6X7T3tvLHdNIaeNHDUnXfD7xhowfy+KUq435
# SXm/l06TZhINORIskT7NzXeGQ0GOH9E/fi75I8DvaqpNP2+/KNqjoKN4/b9lg3Yy
# guQhHbozA9LceUEcJuqoMVP8ISJlNf04UUuBbu/qOi98+fZsTLERF8616e8cxZOn
# Bl5qWXcWj9TgiLaxQ0O3rG6Uvk0xK5i9CV/drChAxwIHl+gQial9ZSy3U5xbQMk5
# OXRxb21I3iPW7ZwqGwzlZbThGZHZ3mSHWkgTClwf5nOecwphVLl7lpHlmr2Tk4qa
# UhfsyGBN6i3BaVf2d2hLgPQ9Qg0Of9odHyapIfty2jjFv0hqcPRzOR5oaCPd+4JZ
# jE8WTRVkdXHUc+od4SkbvGhSFS/VoVfJHdIAMRytokkbh5CvVOgRqB7JbhEdPYLk
# j9byRyU9oJ9tmQR4pvWhXgp5hiaG8Hkviq4b0WDb8ABa2cPQjISvF0rT71j7BHB4
# Z1o4RSSobHDrRDldAgMBAAGjggGJMIIBhTAfBgNVHSMEGDAWgBQPKssghyi47G9I
# ritUpimqF6TNDDAdBgNVHQ4EFgQUGehhFjHaeyHCjpnhdDVt2htnGHQwDgYDVR0P
# AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwSgYD
# VR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9z
# ZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6
# Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYu
# Y3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0cDovL2NydC5zZWN0
# aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcnQwIwYIKwYB
# BQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4IB
# gQArQbT5SgTXP0rCqiEwmyhjWiPx3j/dn75m7RDo/UtFPmmN76/0JJCufXHZZZb3
# 7wxfTz+q524nZzWdGy8SLgl7k2o9H1hbzc6qeOUJssqIPD8GFlrpAgay8W74Q4On
# 1NtV5qijkOeeNH1Dqk3E8/u/oOjz1GC5NMB9tYIbRqeO8ACpoJDRWMGG90RHM7rh
# BCQ4AOtDt1k9XyITdlw41UgFd51zXJhDGqIEeBNgJ4xDDuPvAQCY8uacZSvn+WGn
# sdroqWiSJVGm4lHe4OoTaDLnClMNh6trM4QLqpqt20QfmQM73tUzmF7eBmGRGFoC
# R8O0UlxE2MKXpeI6+K14VRZ1ew+j/BcrQwWQInuI9zHjC7dvvdicNyvxkmAep1WN
# 3AoVGbQW/m4T2mO8G0UI+7CECbcCLBtO7X9Le/GL2h32O20863V8A35wRN3Gmri/
# SZsPm5BGJRtK30d8qpjo1v/vwz/aycp8plSA4XtaeNUvYl36XmB6RQ1fl/l7w9Lp
# R3EwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUA
# MFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNV
# BAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAz
# MjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQK
# Ew9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUg
# U2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCb
# K51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZ
# UKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYk
# wmMv0b/83nbeECbiMXhSOtbam+/36F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE2
# 15wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+
# 8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9
# JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+
# EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9
# o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sC
# AwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0G
# A1UdDgQWBBQPKssghyi47G9IritUpimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYD
# VR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDAS
# MAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwu
# c2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmww
# ewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28u
# Y29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUF
# BzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA
# Bv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug
# 2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCy
# KppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099i
# ChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj
# 1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO3
# 7PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqm
# KL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTq
# lLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQ
# ZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWU
# H3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63
# Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5a4CH2Rwxghn0MIIZ8AIBATBpMFQx
# CzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMT
# IlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYCEQCIL5t+prnNkxi7
# C+hfqY3NMA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
# ARUwLwYJKoZIhvcNAQkEMSIEIMsFruRtggqKY0RZ0jW1u/YN8P325HgosIvFWYvX
# J5+rMA0GCSqGSIb3DQEBAQUABIIBgKXokolvVL/ISoim+UTnhqG9w5MrkmIapTLj
# 7Xn+e5bwpSZqelKXSJhsAlxiQzqeZGkuVjh38XUmUm3mkJfnG7hYOwJLmlUgHd8G
# MGc3wkmYxiym3MsgK97AjwYlzE+M4QAVhCojsOhcAyYgjjDnjJ6KWHXjWRzofaGM
# G+tptrxtlsB6nT9pNiA8jhH4sVehUQFFxY3v2ShMXSJxYOWZDiDg0ZVpsEh98IX9
# VMsMyhcsTFqV4yZnf6/i4w7Yc7DaJ6O21Wz5w+yrCqgyyvMgcc1fJcqWI8r1K+cr
# tMWqZpEMbxdTnZtzy/Sa5RFPr5aCERX6NjLM4tksvPdKzKQH82rzlFjmbh15P08S
# e5GJ7Jz8IU/kOTZKPp7RNPc3KLrZikVrqD9ZCfLeeP0zvMCutGnP154IuNhH1Qa8
# u8dRVWSfUxOr5Ls5tFZqOSbIgtjegi6Ie80iPjQ3Ddu7RiMVdwO9ILDt71Iw1LP9
# +ZhUZwQbRSgprizx5twTIOPI4JcHlKGCF14wghdaBgorBgEEAYI3AwMBMYIXSjCC
# F0YGCSqGSIb3DQEHAqCCFzcwghczAgEDMQ8wDQYJYIZIAWUDBAICBQAwgYcGCyqG
# SIb3DQEJEAEEoHgEdjB0AgEBBglghkgBhv1sBwEwQTANBglghkgBZQMEAgIFAAQw
# fIGEnT5DOorq7XIrFOdlrFO1fwTIDRzVzR/RIyRCQQZ7r2yuyIFtrKxfzsyzoDKT
# AhBPVCrg83oj6qmMrdhYD+PGGA8yMDIzMDUxOTE1MjYwOFqgghMHMIIGwDCCBKig
# AwIBAgIQDE1pckuU+jwqSj0pB4A9WjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQG
# EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0
# IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIy
# MDkyMTAwMDAwMFoXDTMzMTEyMTIzNTk1OVowRjELMAkGA1UEBhMCVVMxETAPBgNV
# BAoTCERpZ2lDZXJ0MSQwIgYDVQQDExtEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMiAt
# IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDP7KUmOsap8mu7jcEN
# mtuh6BSFdDMaJqzQHFUeHjZtvJJVDGH0nQl3PRWWCC9rZKT9BoMW15GSOBwxApb7
# crGXOlWvM+xhiummKNuQY1y9iVPgOi2Mh0KuJqTku3h4uXoW4VbGwLpkU7sqFudQ
# SLuIaQyIxvG+4C99O7HKU41Agx7ny3JJKB5MgB6FVueF7fJhvKo6B332q27lZt3i
# XPUv7Y3UTZWEaOOAy2p50dIQkUYp6z4m8rSMzUy5Zsi7qlA4DeWMlF0ZWr/1e0Bu
# bxaompyVR4aFeT4MXmaMGgokvpyq0py2909ueMQoP6McD1AGN7oI2TWmtR7aeFgd
# Oej4TJEQln5N4d3CraV++C0bH+wrRhijGfY59/XBT3EuiQMRoku7mL/6T+R7Nu8G
# RORV/zbq5Xwx5/PCUsTmFntafqUlc9vAapkhLWPlWfVNL5AfJ7fSqxTlOGaHUQhr
# +1NDOdBk+lbP4PQK5hRtZHi7mP2Uw3Mh8y/CLiDXgazT8QfU4b3ZXUtuMZQpi+ZB
# pGWUwFjl5S4pkKa3YWT62SBsGFFguqaBDwklU/G/O+mrBw5qBzliGcnWhX8T2Y15
# z2LF7OF7ucxnEweawXjtxojIsG4yeccLWYONxu71LHx7jstkifGxxLjnU15fVdJ9
# GSlZA076XepFcxyEftfO4tQ6dwIDAQABo4IBizCCAYcwDgYDVR0PAQH/BAQDAgeA
# MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkw
# FzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaa
# L3WMaiCPnshvMB0GA1UdDgQWBBRiit7QYfyPMRTtlwvNPSqUFN9SnDBaBgNVHR8E
# UzBRME+gTaBLhklodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcB
# AQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFgG
# CCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3
# DQEBCwUAA4ICAQBVqioa80bzeFc3MPx140/WhSPx/PmVOZsl5vdyipjDd9Rk/BX7
# NsJJUSx4iGNVCUY5APxp1MqbKfujP8DJAJsTHbCYidx48s18hc1Tna9i4mFmoxQq
# RYdKmEIrUPwbtZ4IMAn65C3XCYl5+QnmiM59G7hqopvBU2AJ6KO4ndetHxy47JhB
# 8PYOgPvk/9+dEKfrALpfSo8aOlK06r8JSRU1NlmaD1TSsht/fl4JrXZUinRtytIF
# Zyt26/+YsiaVOBmIRBTlClmia+ciPkQh0j8cwJvtfEiy2JIMkU88ZpSvXQJT657i
# nuTTH4YBZJwAwuladHUNPeF5iL8cAZfJGSOA1zZaX5YWsWMMxkZAO85dNdRZPkOa
# GK7DycvD+5sTX2q1x+DzBcNZ3ydiK95ByVO5/zQQZ/YmMph7/lxClIGUgp2sCovG
# SxVK05iQRWAzgOAj3vgDpPZFR+XOuANCR+hBNnF3rf2i6Jd0Ti7aHh2MWsgemtXC
# 8MYiqE+bvdgcmlHEL5r2X6cnl7qWLoVXwGDneFZ/au/ClZpLEQLIgpzJGgV8unG1
# TnqZbPTontRamMifv427GFxD9dAq6OJi7ngE273R+1sKqHB+8JeEeOMIA11HLGOo
# JTiXAdI/Otrl5fbmm9x+LMz/F0xNAKLY1gEOuIvu5uByVYksJxlh9ncBjDCCBq4w
# ggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4X
# DTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAV
# BgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVk
# IEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5M
# om2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE
# 2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWN
# lCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFo
# bjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhN
# ef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3Vu
# JyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtz
# Q87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4O
# uGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5
# sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm
# 4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIz
# tM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6
# FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qY
# rhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYB
# BQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w
# QQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZ
# MBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmO
# wJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H
# 6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/
# R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzv
# qLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/ae
# sXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdm
# kfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3
# EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh
# 3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA
# 3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8
# BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsf
# gPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwggWNMIIEdaADAgECAhAOmxiO
# +dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD
# VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAi
# BgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAw
# MDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERp
# Z2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsb
# hA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iT
# cMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGb
# NOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclP
# XuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCr
# VYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFP
# ObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTv
# kpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWM
# cCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls
# 5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBR
# a2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6
# MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qY
# rhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8E
# BAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDig
# NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCg
# v0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQT
# SnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh
# 65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSw
# uKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAO
# QGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjD
# TZ9ztwGpn1eqXijiuZQxggOGMIIDggIBATB3MGMxCzAJBgNVBAYTAlVTMRcwFQYD
# VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBH
# NCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAxNaXJLlPo8Kko9KQeA
# PVowDQYJYIZIAWUDBAICBQCggeEwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
# MBwGCSqGSIb3DQEJBTEPFw0yMzA1MTkxNTI2MDhaMCsGCyqGSIb3DQEJEAIMMRww
# GjAYMBYEFPOHIk2GM4KSNamUvL2Plun+HHxzMDcGCyqGSIb3DQEJEAIvMSgwJjAk
# MCIEIMf04b4yKIkgq+ImOr4axPxP5ngcLWTQTIB1V6Ajtbb6MD8GCSqGSIb3DQEJ
# BDEyBDCmcaTL5HdCuCixYENR/D7MRH+yHC4XSRG/UsMZHT0rvaXUgzNF3nYufE8f
# zhqD2c0wDQYJKoZIhvcNAQEBBQAEggIAC8jn8x1LvRDoEQRaSDEqjeBsPlE9Wq80
# 9pqRPBzK9A5DQc5zeKwbgOiAcMC2VNMY8lQPiFzD+KJRQ4VQrzWBpHFedELrvSPA
# kAzkg5ad40rHaOf1/trHphN0Lm9cb5Va0Wxbo8fcPQCM7UStEjY7RnNvK09ewuPo
# wDaGDAgnAnoAWYtP+GR8fO856O+aQgiEt0CCjO1og9LWz4Jbt3wwI4+gMou5zKpV
# 4IgLITqDihCuiyC2CU1k7PRunw8XDM8coz01yuHPkvcQ3CN8mgaaxwdjhKpQuFWf
# 2mwpGANvDLs3Wa58g2OfhQgV73y1286rregQQaIwdSnrjSrD3ZeczyGNVRRn21hE
# YbSt/Tepzoox4DervOuVsWQl7seL+9UI6hVRMdxGDkFqr3yjdvLoNa4iI85GPpDM
# xYgCtuvxU+2DP0E0ovWCP/6x/3UVtg09jk1wrreG9K/J59fMheSOugoh7M+8B9AA
# Skfb/88hr4W87n8TVCuY9lKvwOnC/caB3gLKCz+in6sIyDHV8E8j7MZP2qzqlGrJ
# xQPdPqcqP/SiTBJoZ3pwafoP/8BZPILGKGhUWjBp4T5KllBQvWspuWqi6OQILHbB
# RMyYFvG1Cqen5sTa7hOiy6NvsspcDTLsBU+xDLAhr1JAyLQXYaaOzS35xAJEmL1u
# b0OOoUYx6OQ=
# SIG # End signature block