Functions/Public/Users.ps1
|
# User, account, admin, and business unit management functions Function Get-NectarUserAccountSettings { <# .SYNOPSIS Returns information about the current logged in user's UI settings. .DESCRIPTION Returns information about the current logged in user's UI settings. .EXAMPLE Get-NectarUserAccountSettings .NOTES Version 1.0 #> [Alias("gnas")] Param () Begin { Connect-NectarCloud } Process { $URI = "https://$Global:NectarCloud/aapi/user" Write-Verbose $URI Try { $JSON = Invoke-RestMethod -Method GET -Uri $URI -Headers $Global:NectarAuthHeader Return $JSON } Catch { Write-Error "Unable to obtain user's UI settings. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function Get-NectarUserAccountMapping { <# .SYNOPSIS Return user account mapping information .DESCRIPTION Return user account mapping information .PARAMETER MappingSource The source for the user mapping. Choose from 'Endpoint', 'WebRTC' or 'Jabra' .PARAMETER SearchQuery A string to search for. Will search for match against all fields .PARAMETER OrderByField Sort the output by the selected field .PARAMETER OrderDirection Sort ordered output in ascending or descending order .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .PARAMETER PageSize The size of the page used to return data. Defaults to 10000 .PARAMETER ResultSize The total number of results to return. Maximum result size is 9,999,999 results .EXAMPLE Get-NectarUserAccountMapping -MappingSource WebRTC Return all WebRTC account mappings .EXAMPLE Get-NectarUserAccountMapping -MappingSource Endpoint -SearchQuery TFerguson Find a endpoint account mapping for TFerguson .NOTES Version 1.0 #> Param ( [Parameter(Mandatory=$True)] [ValidateSet('Endpoint','WebRTC','Jabra', IgnoreCase=$True)] [string]$MappingSource = 'Endpoint', [Parameter(Mandatory=$False)] [string]$SearchQuery, [Parameter(Mandatory=$False)] [string]$OrderByField, [Parameter(Mandatory=$False)] [ValidateSet('asc', 'desc', IgnoreCase=$True)] [string]$OrderDirection = 'asc', [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(Mandatory=$False)] [ValidateRange(1,999999)] [int]$PageSize = 10000, [Parameter(Mandatory=$False)] [ValidateRange(1,999999)] [int]$ResultSize, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$Name ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } # Take care of any cases that don't match the above rule Switch ($MappingSource) { 'Endpoint' { $URLPath = 'testing/entities' $OrderByField = 'name' break } 'WebRTC' { $URLPath = 'webrtc/user/entities' $OrderByField = 'loginId' break } 'Jabra' { $URLPath = 'jabra/user/entities' $OrderByField = 'domainName' break } } # Set the page size to the result size if -ResultSize switch is used to limit the number of returned items # Otherwise, set page size (defaults to 1000) If ($ResultSize) { $PageSize = $ResultSize } $Params = @{ 'pageNumber' = 1 'pageSize' = $PageSize 'orderByField' = $OrderByField 'orderDirection' = $OrderDirection 'tenant' = $TenantName } If ($SearchQuery) { $Params.Add('q', $SearchQuery) } $URI = "https://$Global:NectarCloud/aapi/$URLPath" Write-Verbose $URI $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader -Body $Params $TotalPages = $JSON.totalPages If ($TenantName) { $JSON.elements | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty } $JSON.elements If ($TotalPages -gt 1 -and !($ResultSize)) { $PageNum = 2 Write-Verbose "Page size: $PageSize" While ($PageNum -le $TotalPages) { Write-Verbose "Working on page $PageNum of $TotalPages" $Params.PageNumber = $PageNum $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader -Body $Params If ($TenantName) { $JSON.elements | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty } $JSON.elements $PageNum++ } } } } Function Set-NectarUserAccountMapping { <# .SYNOPSIS Return user account mapping information .DESCRIPTION Return user account mapping information .PARAMETER MappingSource The source for the user mapping. Choose from 'Endpoint', 'WebRTC' or 'Jabra' .PARAMETER SourceSearchQuery A string to search for. Will search for match against all fields .PARAMETER SourceID The ID of the source entity to map. Used to specify a unique source entity when multiple entities match the SourceSearchQuery .PARAMETER MapSearchQuery A string to search for to map the source account to. Will search for match against all fields .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .EXAMPLE Get-NectarUserAccountMapping -MappingSource WebRTC Return all WebRTC account mappings .EXAMPLE Get-NectarUserAccountMapping -MappingSource Endpoint -SearchQuery TFerguson Find a endpoint account mapping for TFerguson .NOTES Version 1.0 #> Param ( [Parameter(Mandatory=$True)] [ValidateSet('Endpoint','WebRTC','Jabra', IgnoreCase=$True)] [string]$MappingSource, [Parameter(Mandatory=$False)] [string]$SourceSearchQuery, [Parameter(Mandatory=$False)] [int]$SourceID, [Parameter(Mandatory=$False)] [string]$MapSearchQuery, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$Name ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } # Take care of any cases that don't match the above rule Switch ($MappingSource) { 'Endpoint' { $URLPath = 'testing/entity' break } 'WebRTC' { $URLPath = 'webrtc/user/entity' break } 'Jabra' { $URLPath = 'jabra/user/entity' break } } # Get the source entity $SourceEntity = Get-NectarUserAccountMapping -MappingSource $MappingSource -SearchQuery $SourceSearchQuery -TenantName $TenantName If ($PSBoundParameters.ContainsKey('SourceID')) { $SourceEntity = @($SourceEntity | Where-Object { $_.id -eq $SourceID }) } If ($SourceEntity.Count -gt 1) { Throw "Multiple source entities found matching '$SourceSearchQuery'. Please refine your search." } ElseIf ($SourceEntity.Count -eq 0) { Throw "No source entity found matching '$SourceSearchQuery'." } # Get the map entity If ($MapSearchQuery) { $MapEntity = Get-NectarUser -SearchQuery $MapSearchQuery -TenantName $TenantName } If ($MapEntity.Count -gt 1) { Throw "Multiple map entities found matching '$MapSearchQuery'. Please refine your search." } ElseIf ($MapSearchQuery -ne '' -and $MapEntity.Count -eq 0) { Throw "No map entity found matching '$MapSearchQuery'." } # Strip unnecessary properties $SourceEntity = $SourceEntity | Select-Object -Property $WantedProps $Params = [PSCustomObject]@{ email = $MapEntity.email id = $SourceEntity.id ipAddress = $SourceEntity.ipAddress isHub = $SourceEntity.isHub location = $SourceEntity.location mappedSource = $MapEntity.platform name = $SourceEntity.name phone = $MapEntity.phone platformUserName = $MapEntity.platformUserName userDisplayName = $MapEntity.displayName userName = $MapEntity.userName userPbxNumber = $MapEntity.userPbxNumber uuid = $SourceEntity.uuid } $JSONBody = $Params | ConvertTo-Json Write-Verbose $JSONBody $URI = "https://$Global:NectarCloud/aapi/$($URLPath)?tenant=$TenantName" Write-Verbose $URI $JSON = Invoke-RestMethod -Method PUT -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONBody -ContentType 'application/json' Return $JSON } } Function Get-NectarWebRTCUser { <# .SYNOPSIS Return information about WebRTC users in the environment .DESCRIPTION Return information about WebRTC users in the environment. Returns a list of all WebRTC users and their current status. .PARAMETER SearchQuery A string to search for. Will search for match against all fields .PARAMETER OrderByField Sort the output by the selected field .PARAMETER OrderDirection Sort ordered output in ascending or descending order .PARAMETER PageSize The size of the page used to return data. Defaults to 10000 .PARAMETER ResultSize The total number of results to return. Maximum result size is 9,999,999 results .EXAMPLE Get-NectarWebRTCUser Returns information about all service providers in the environment .EXAMPLE Get-NectarWebRTCUser -SearchQuery TFerguson Returns information about users that match the query 'TFerguson' .NOTES Version 1.0 #> Param ( [Parameter(Mandatory=$False)] [string]$SearchQuery, [Parameter(Mandatory=$False)] [ValidateSet('firstName', 'lastName', 'email', 'lastLoginDate', 'extensionVersion', IgnoreCase=$True)] [string]$OrderByField = 'email', [Parameter(Mandatory=$False)] [ValidateSet('asc', 'desc', IgnoreCase=$True)] [string]$OrderDirection = 'asc', [Parameter(Mandatory=$False)] [ValidateRange(1,999999)] [int]$PageSize = 10000, [Parameter(Mandatory=$False)] [ValidateRange(1,999999)] [int]$ResultSize, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { # Set the page size to the result size if -ResultSize switch is used to limit the number of returned items # Otherwise, set page size (defaults to 1000) # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } If ($ResultSize) { $PageSize = $ResultSize } $Params = @{ 'pageNumber' = 1 'pageSize' = $PageSize 'orderByField' = $OrderByField 'orderDirection' = $OrderDirection 'tenant' = $TenantName } If ($SearchQuery) { $Params.Add('searchQuery', $SearchQuery) } $URI = "https://$Global:NectarCloud/aapi/users/webrtc" Write-Verbose $URI $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader -Body $Params $TotalPages = $JSON.totalPages $JSON.elements If ($TotalPages -gt 1 -and !($ResultSize)) { $PageNum = 2 Write-Verbose "Page size: $PageSize" While ($PageNum -le $TotalPages) { Write-Verbose "Working on page $PageNum of $TotalPages" $Params.PageNumber = $PageNum $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader -Body $Params $JSON.elements $PageNum++ } } } } Function Get-NectarPinnedUsers { <# .SYNOPSIS Returns information about the signed in user's Pinned Users list .DESCRIPTION Users can be "pinned" to the Users screen. This command will return information about all pinned users .EXAMPLE Get-NectarPinnedUsers .NOTES Version 1.0 #> [Alias("gnpu")] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(Mandatory=$False)] [ValidateRange(1,100000)] [int]$PageSize = 1000, [Parameter(Mandatory=$False)] [ValidateRange(1,9999999)] [int]$ResultSize ) Begin { Connect-NectarCloud $Params = @{} # Set the page size to the result size if -ResultSize switch is used to limit the number of returned items # Otherwise, set page size (defaults to 1000) If ($ResultSize) { $Params.Add('pageSize',$ResultSize) } Else { $Params.Add('pageSize',$PageSize) } } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } If ($TenantName) { $Params.Add('Tenant',$TenantName) } $URI = "https://$Global:NectarCloud/dapi/user/pinned" Write-Verbose $URI Try { $JSON = Invoke-RestMethod -Method GET -Uri $URI -Headers $Global:NectarAuthHeader -Body $Params $TotalPages = $JSON.totalPages # Add the tenant name to the output which helps pipelining If ($TenantName) {$JSON.elements | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty} # Remove the Photo element, which takes a lot of room on the page and isn't necessary $JSON.elements | Select-Object -Property * -ExcludeProperty Photo If ($TotalPages -gt 1 -and !($ResultSize)) { $PageNum = 2 Write-Verbose "Page size: $PageSize" While ($PageNum -le $TotalPages) { Write-Verbose "Working on page $PageNum of $TotalPages" $PagedURI = $URI + "?pageNumber=$PageNum" $JSON = Invoke-RestMethod -Method GET -Uri $PagedURI -Headers $Global:NectarAuthHeader -Body $Params # Remove the Photo element, which takes a lot of room on the page and isn't necessary $JSON.elements | Select-Object -Property * -ExcludeProperty Photo $PageNum++ } } } Catch { Write-Error "Error getting pinned user list. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function Add-NectarPinnedUser { <# .SYNOPSIS Adds a user to the signed in user's Pinned Users list .DESCRIPTION Users can be "pinned" to the Users screen. This command will add a user to the signed in user's Pinned users list .EXAMPLE Add-NectarPinnedUser tferguson@contoso.com Adds the user TFerguson@contoso.com to the signed in Pinned Users list .EXAMPLE Import-Csv .\Users.csv | Add-NectarPinnedUser Adds users to pinned user list using a CSV file of email addresses as input. CSV file must have a header called EmailAddress .NOTES Version 1.0 #> [Alias("anpu")] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)] [string]$EmailAddress, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } # Get the current preference settings and get the pinned user list $Preferences = (Get-NectarUserAccountSettings).Preferences [System.Collections.ArrayList]$PinnedUserList = $Preferences.pinnedUserIds $URI = "https://$Global:NectarCloud/aapi/user/preferences?tenant=$TenantName" Write-Verbose $URI } Process { Try { # Get the ID of the desired user and add to the Pinned User List [string]$UserID = (Get-NectarUser $EmailAddress -ErrorAction Stop).Id If ($PinnedUserList.Contains($UserID)) { Write-Error "$EmailAddress already in Pinned User list" } Else { $Null = $PinnedUserList.Add($UserID) } # Re-insert pinned user list to user preferences $Preferences.pinnedUserIds = $PinnedUserList # Convert Preferences back to JSON $JSONPrefs = $Preferences | ConvertTo-JSON -Depth 10 # Save the updated preferences $NULL = Invoke-RestMethod -Method POST -Uri $URI -Headers $Global:NectarAuthHeader -Body $JSONPrefs -ContentType "application/json" } Catch { Write-Error "Error adding $EmailAddress to pinned user list. $($_.Exception.Message)" } } End { Try { # Re-insert pinned user list to user preferences $Preferences.pinnedUserIds = $PinnedUserList # Convert Preferences back to JSON $JSONPrefs = $Preferences | ConvertTo-JSON -Depth 10 # Save the updated preferences $NULL = Invoke-RestMethod -Method POST -Uri $URI -Headers $Global:NectarAuthHeader -Body $JSONPrefs -ContentType "application/json" } Catch { Write-Error "Error adding $EmailAddress to pinned user list. $($_.Exception.Message)" } } } Function Remove-NectarPinnedUser { <# .SYNOPSIS Remove a user from the signed in user's Pinned Users list .DESCRIPTION Users can be "pinned" to the Users screen. This command will remove a user from the signed in user's Pinned users list .EXAMPLE Remove-NectarPinnedUsers tferguson@contoso.com Removes the user TFerguson@contoso.com from the signed in Pinned Users list .NOTES Version 1.0 #> [Alias("rnpu")] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias('Email')] [string]$EmailAddress, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$ID, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } # Get the current preference settings and get the pinned user list $Preferences = (Get-NectarUserAccountSettings).Preferences [System.Collections.ArrayList]$PinnedUserList = $Preferences.pinnedUserIds $URI = "https://$Global:NectarCloud/aapi/user/preferences?tenant=$TenantName" Write-Verbose $URI } Process { Try { # Get the ID of the desired user and remove from the Pinned User List If (!$ID) { [string]$ID = (Get-NectarUser $EmailAddress).Id } $PinnedUserList.Remove($ID) } Catch { Write-Error "Error removing $EmailAddress from pinned user list. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } End { Try { # Re-insert pinned user list to user preferences $Preferences.pinnedUserIds = $PinnedUserList # Convert Preferences back to JSON $JSONPrefs = $Preferences | ConvertTo-JSON -Depth 10 # Save the updated preferences $NULL = Invoke-RestMethod -Method POST -Uri $URI -Headers $Global:NectarAuthHeader -Body $JSONPrefs -ContentType "application/json" } Catch { Write-Error "Error updating user preferences $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } ################################################################################################################################################# # # # Tenant Email Domain Functions # # # ################################################################################################################################################# Function Get-NectarEmailDomain { <# .SYNOPSIS Returns a list of Nectar DXP allowed email domains that can be used for login IDs. .DESCRIPTION Returns a list of Nectar DXP allowed email domains that can be used for login IDs. .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .PARAMETER ResultSize The number of results to return. Defaults to 1000. .EXAMPLE Get-NectarEmailDomain Returns all the allowed email domains for the logged in tenant. .NOTES Version 1.1 #> [Alias("gne")] Param ( [Parameter(Mandatory=$False)] [string]$SearchQuery, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(Mandatory=$False)] [ValidateRange(1,100000)] [int]$ResultSize = 1000 ) Begin { Connect-NectarCloud } Process { Try { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } $URI = "https://$Global:NectarCloud/aapi/client/domains?searchQuery=$SearchQuery&tenant=$TenantName&pageSize=$ResultSize" Write-Verbose $URI $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader If ($JSON.domainNames) { Return $JSON.domainNames } If ($JSON.elements) { Return $JSON.elements } } Catch { Write-Error "No email domains found or insufficient permissions. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function New-NectarEmailDomain { <# .SYNOPSIS Add a new allowed email domain that can be used for login IDs. .DESCRIPTION Add a new allowed email domain that can be used for login IDs. .PARAMETER EmailDomain The email domain to add to the tenant. .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .EXAMPLE New-NectarEmailDomain -EmailDomain contoso.com Adds the contoso.com email domain to the logged in Nectar DXP tenant. .NOTES Version 1.1 #> [Alias("nne")] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)] [string]$EmailDomain, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } $URI = "https://$Global:NectarCloud/aapi/client/domains?tenant=$TenantName" Write-Verbose $URI $JSONBody = $EmailDomain Try { $NULL = Invoke-RestMethod -Method POST -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONBody -ContentType 'application/json; charset=utf-8' Write-Verbose "Successfully added $EmailDomain as an allowed email domain." } Catch { Write-Error "Unable to add $EmailDomain to list of allowed email domains. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function Remove-NectarEmailDomain { <# .SYNOPSIS Remove an allowed email domain that can be used for login IDs. .DESCRIPTION Remove an allowed email domain that can be used for login IDs. .PARAMETER EmailDomain The email domain to remove from the tenant. .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .EXAMPLE Remove-NectarEmailDomain -EmailDomain contoso.com Removes the contoso.com email domain from the list of allowed domains on the logged in Nectar DXP tenant. .NOTES Version 1.1 #> [Alias("rne")] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("domainName")] [string]$EmailDomain, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("id")] [int]$Identity ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } If ($EmailDomain -and !$Identity) { $Identity = (Get-NectarEmailDomain -TenantName $TenantName -SearchQuery $EmailDomain -ResultSize 1 -ErrorVariable GetDomainError).ID } If (!$GetDomainError) { $URI = "https://$Global:NectarCloud/aapi/client/domains/$Identity/?tenant=$TenantName" Write-Verbose $URI Try { $NULL = Invoke-RestMethod -Method DELETE -URI $URI -Headers $Global:NectarAuthHeader Write-Verbose "Successfully deleted $EmailDomain from list of allowed email account domains." } Catch { Write-Error "Unable to delete email domain $EmailDomain. Ensure you typed the name of the email domain correctly. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } } ################################################################################################################################################# # # # Tenant Admin Functions # # # ################################################################################################################################################# Function Get-NectarUserAccount { <# .SYNOPSIS Get information about one or more Nectar DXP user accounts. .DESCRIPTION Get information about one or more Nectar DXP user accounts. .PARAMETER SearchQuery A full or partial match of the user's first or last name or email address .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .PARAMETER ResultSize The number of results to return. Defaults to 10000. .EXAMPLE Get-NectarUserAccount -SearchQuery tferguson@contoso.com Returns information about the user tferguson@contoso.com .NOTES Version 1.1 #> [Alias('gna', 'Get-NectarAdmin')] Param ( [Parameter(Mandatory=$False)] [string]$SearchQuery, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(Mandatory=$False)] [ValidateRange(1,100000)] [int]$ResultSize = 10000 ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } $URI = "https://$Global:NectarCloud/aapi/users?searchQuery=$SearchQuery&tenant=$TenantName&pageSize=$ResultSize" Write-Verbose $URI Try { $JSON = Invoke-RestMethod -Method POST -URI $URI -Headers $Global:NectarAuthHeader If ($TenantName) {$JSON.elements | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty} # Add the tenant name to the output which helps pipelining Return $JSON.elements } Catch { Write-Error "Unable to get user details. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function Set-NectarUserAccount { <# .SYNOPSIS Update one or more Nectar DXP user accounts. .DESCRIPTION Update one or more Nectar DXP user accounts. .PARAMETER FirstName The first name of the user .PARAMETER LastName The last name of the user .PARAMETER EmailAddress The email address of the user .PARAMETER AdminStatus True if Admin, False if not. Used when importing many user accounts via CSV .PARAMETER IsAdmin Include if user is to be an admin. If not present, then user will be read-onl .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .PARAMETER Identity The numerical identity of the user .NOTES Version 1.1 #> [Alias('sna', 'Set-NectarAdmin')] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("name")] [string]$FirstName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$LastName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("email")] [string]$EmailAddress, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("admin")] [string]$AdminStatus, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [switch]$IsAdmin, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$Role, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("id")] [String]$Identity ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } # If ($IsAdmin -and !$AdminStatus) { # $AdminStatus = "true" # } # ElseIf (!$IsAdmin -and !$AdminStatus) { # $AdminStatus = "false" # } If ($EmailAddress -And !$Identity) { $UserInfo = Get-NectarUserAccount -SearchQuery $EmailAddress -Tenant $TenantName -ResultSize 1 $Identity = $UserInfo.id } If (-not $FirstName) {$FirstName = $UserInfo.firstName} If (-not $LastName) {$LastName = $UserInfo.lastName} If (-not $EmailAddress) {$EmailAddress = $UserInfo.email} If (-not $IsAdmin -and !$AdminStatus) {$AdminStatus = $UserInfo.admin} $URI = "https://$Global:NectarCloud/aapi/user/$Identity/?tenant=$TenantName" Write-Verbose $URI $Body = @{ id = $Identity email = $EmailAddress firstName = $FirstName lastName = $LastName # isAdmin = $AdminStatus userRoleName = $Role # userStatus = "ACTIVE" } $JSONBody = $Body | ConvertTo-Json Try { Write-Verbose $JSONBody $NULL = Invoke-RestMethod -Method PUT -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONBody -ContentType 'application/json; charset=utf-8' } Catch { Write-Error "Unable to apply changes for user $EmailAddress. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function New-NectarUserAccount { <# .SYNOPSIS Create a new Nectar DXP user account. .DESCRIPTION Create a new Nectar DXP user account. .PARAMETER FirstName The user's first name .PARAMETER LastName The user's last name .PARAMETER EmailAddress The user's email address .PARAMETER Password The password to assign to the new account .PARAMETER AdminStatus True if Admin, False if not. Used when importing many admin accounts via CSV .PARAMETER IsAdmin Include if user is to be an admin. If not present, then user will be read-only .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .EXAMPLE New-NectarUser -FirstName Turd -LastName Ferguson -Email tferguson@contoso.com -Password VeryStrongPassword -IsAdmin Creates a new admin user called Turd Ferguson .EXAMPLE Import-Csv .\Users.csv | New-NectarUser Creates user accounts using a CSV file as input. CSV file must have the following headers: FirstName,LastName,Password,Email,AdminStatus (Use True/False for AdminStatus) .NOTES Version 1.2 #> [Alias('nna', 'New-NectarAdmin')] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$FirstName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$LastName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)] [Alias("email")] [string]$EmailAddress, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [SecureString]$Password, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$AdminStatus, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [switch]$IsAdmin, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$Role, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { If ($IsAdmin -and !$AdminStatus) { $AdminStatus = "true" } ElseIf (!$IsAdmin -and !$AdminStatus) { $AdminStatus = "false" } # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } $URI = "https://$Global:NectarCloud/aapi/user?tenant=$TenantName" Write-Verbose $URI $Body = @{ email = $EmailAddress firstName = $FirstName lastName = $LastName isAdmin = $AdminStatus userRoleName = $Role userStatus = "ACTIVE" } If ($Password) { $Body.Add('password',$Password) } $JSONBody = $Body | ConvertTo-Json Try { Write-Verbose $JSONBody $NULL = Invoke-RestMethod -Method POST -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONBody -ContentType 'application/json; charset=utf-8' } Catch { Write-Error "Unable to create user account $EmailAddress. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function Remove-NectarUserAccount { <# .SYNOPSIS Removes one or more Nectar DXP user account. .DESCRIPTION Removes one or more Nectar DXP user account. .PARAMETER EmailAddress The email address of the user account to remove. .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .PARAMETER Identity The numerical ID of the user account to remove. Can be obtained via Get-NectarUserAccount and pipelined to Remove-NectarUser .EXAMPLE Remove-NectarUserAccount tferguson@nectarcorp.com Removes the user account tferguson@nectarcorp.com .NOTES Version 1.1 #> [Alias('rna', 'Remove-NectarAdmin')] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("email")] [string]$EmailAddress, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("id")] [string]$Identity ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } If ($EmailAddress -and !$Identity) { $Identity = (Get-NectarUserAccount -SearchQuery $EmailAddress -Tenant $TenantName -ResultSize 1 -ErrorVariable GetUserError).ID } If (!$GetUserError) { $URI = "https://$Global:NectarCloud/aapi/user/$Identity/?tenant=$TenantName" Write-Verbose $URI Try { $NULL = Invoke-RestMethod -Method DELETE -URI $URI -Headers $Global:NectarAuthHeader Write-Verbose "Successfully deleted $EmailAddress from user account list." } Catch { Write-Error "Unable to delete user $EmailAddress. Ensure you typed the name of the user correctly. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } } Function Get-NectarAdminRole { <# .SYNOPSIS Returns a list of admin roles .DESCRIPTION Returns a list of admin roles .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .EXAMPLE Get-NectarAdminRole Returns a list of admin roles associated with the current tenant .NOTES Version 1.0 #> Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } $URI = "https://$Global:NectarCloud/aapi/user/roles?pageSize=9999&pageNumber=1&tenant=$TenantName" Write-Verbose $URI $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader Return $JSON.elements } } Function New-NectarAdminRole { <# .SYNOPSIS Creates a new admin role .DESCRIPTION Creates a new admin role .PARAMETER Name The name to give to the role .PARAMETER Description The role description .PARAMETER PermissionList A list of permissions (authorities) to assign to the new role. This determines what the role can view or configure in the dashboard. .PARAMETER ServiceProviderName The name of the service provider associated with this role. Must be used with -TenantList. Required in the 'ServiceProvider' parameter set. .PARAMETER TenantList A list of tenant names associated with the service provider. Must be used with -ServiceProviderName. Required in the 'ServiceProvider' parameter set. .PARAMETER LockMinutes The number of minutes a user is locked out after exceeding the maximum login attempts. Default is 15. .PARAMETER ManualUnlock Indicates whether a manual unlock is required after a lockout. Default is $False. .PARAMETER MaxLoginAttempts The number of failed login attempts allowed before a lockout occurs. Default is 5. .PARAMETER TenantName The name of a single tenant. Used in the 'Tenant' parameter set. Optional. .NOTES Version 1.0 #> [CmdletBinding(DefaultParameterSetName = 'Tenant')] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)] [string]$Name, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$Description, [Parameter(Mandatory=$True)] [ValidateSet( 'DASHBOARD_ANALYTICS_SELF_SERVICE', 'DASHBOARD_ANALYTICS_VIEWER', 'DASHBOARD_EVENTS_VIEWER', 'DASHBOARD_HISTORIC_CALL_DETAILS_QUALITY_VIEWER', 'DASHBOARD_HISTORIC_CALL_DETAILS_VIEWER', 'DASHBOARD_HISTORIC_CONFERENCE_PARTICIPANTS_VIEWER', 'DASHBOARD_HISTORIC_CONFERENCE_SUMMARY_VIEWER', 'DASHBOARD_HISTORIC_CONFERENCE_TIMELINE_VIEWER', 'DASHBOARD_HISTORIC_SESSION_LIST_VIEWER', 'DASHBOARD_HISTORIC_SESSION_SUMMARY_ADVANCED_VIEWER', 'DASHBOARD_HISTORIC_SESSION_SUMMARY_DETAILS_VIEWER', 'DASHBOARD_HISTORIC_SESSION_SUMMARY_VIEWER', 'DASHBOARD_ITEMS_CONFIGURATOR', 'DASHBOARD_ITEMS_VIEWER', 'DASHBOARD_LIVE_CALL_DETAILS_VIEWER', 'DASHBOARD_NUMBERS_CONFIGURATOR', 'DASHBOARD_NUMBERS_VIEWER', 'DASHBOARD_PLATFORM_AVAYA_VIEWER', 'DASHBOARD_PLATFORM_CISCO_VIEWER', 'DASHBOARD_PLATFORM_ENDPOINT_CLIENT_VIEWER', 'DASHBOARD_PLATFORM_INVENTORY_VIEWER', 'DASHBOARD_REPORTS_VIEWER', 'DASHBOARD_ROOMS_DEVICES_VIEWER', 'DASHBOARD_SERVICES_VIEWER', 'DASHBOARD_SUMMARY_VIEWER', 'DASHBOARD_USERS_ADVANCED_VIEWER', 'DASHBOARD_USERS_VIEWER', 'DASHBOARD_VIEWER' )] [string[]]$PermissionList, [Parameter(ParameterSetName = 'ServiceProvider', Mandatory=$True)] [string]$ServiceProviderName, [Parameter(ParameterSetName = 'ServiceProvider', Mandatory=$True)] [string[]]$TenantList, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [int]$LockMinutes = 15, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [bool]$ManualUnlock = $False, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [int]$MaxLoginAttempts = 5, [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'Tenant', Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } # Convert TenantList to ClientIDs $ClientIDs = @() If ($TenantList) { $TenantName = $ServiceProviderName # Use ServiceProviderName as TenantName for Service Provider roles $AvailableTenants = Get-NectarServiceProviderTenants -ServiceProviderName $ServiceProviderName # Validate the tenants exist and add to ClientIDs ForEach ($Tenant in $TenantList) { $TenantInfo = $AvailableTenants | Where-Object { $_.Name -eq $Tenant } If ($TenantInfo) { $ClientIDs += $TenantInfo.Id } Else { Throw "Tenant $Tenant not found in service provider $ServiceProviderName. Available tenants are: $($AvailableTenants.Name -join ', ')" } } } $URI = "https://$Global:NectarCloud/aapi/user/role?tenant=$TenantName" Write-Verbose $URI $Body = @{ name = $Name description = $Description authorities = $PermissionList reportTagIds = @() reportCatalogIds = @() clientIds = $ClientIDs assignAllClients = $false userRoleLockSettings = @{ lockMinutes = $LockMinutes manualUnlock = $ManualUnlock maxLoginAttempts = $MaxLoginAttempts } } $JSONBody = $Body | ConvertTo-Json -Depth 10 Write-Verbose $JSONBody Try { $Response = Invoke-RestMethod -Uri $URI -Method POST -Body $JSONBody -Headers $Global:NectarAuthHeader -ContentType "application/json" Write-Host "Role created successfully:" -ForegroundColor Green $Response } Catch { Write-Error "Failed to create role: $_" } } } ################################################################################################################################################# # # # Tenant Location Functions # # # Function Get-NectarUser { <# .SYNOPSIS Get information about 1 or more users via Nectar DXP. .DESCRIPTION Get information about 1 or more users via Nectar DXP. .PARAMETER SearchQuery A full or partial match of the user name. Will do an 'includes' type search by default. So searching for user@domain.com would return Auser@domain.com, Buser@domain.com etc. For a specific match, enclose the name in square brackets IE: [user@domain.com] .PARAMETER FilterSearch Uses an alternate API for returning users. Has better searching capabilities and should be used in conjunction with commands that allow user filtering .PARAMETER TenantName The name of the Nectar DXP tenant. Used in multi-tenant configurations. .PARAMETER ResultSize The number of results to return. Defaults to 1000. .EXAMPLE Get-NectarUser -SearchQuery tferguson .NOTES Version 1.2 #> [Alias("gnu")] Param ( [Parameter(Mandatory=$True)] [string]$SearchQuery, [Parameter(Mandatory=$False)] [switch]$FilterSearch, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName, [Parameter(Mandatory=$False)] [ValidateSet('DEFAULT','USERS','ENDPOINT_CLIENT','CALL_DETAILS_HISTORIC','QUALITY_DETAILS', IgnoreCase=$True)] [string]$Scope = 'DEFAULT', [Parameter(Mandatory=$False)] [ValidateRange(1,999999)] [int]$ResultSize = 10000 ) Begin { Connect-NectarCloud # Get the encoding for resolving special characters $TextEncoding = [System.Text.Encoding]::GetEncoding('ISO-8859-1') } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } $EncodedSearchQuery = [System.Web.HttpUtility]::UrlEncode($SearchQuery) # Filtersearch query should be used in support of a filter query for use in session searches. Has better searching ability than the other method. # For example, the FilterSearch API allows for searching with alternate characters like periods, while the other method seems to ignore it selectively # The other method presents more data, which may be useful for other purposes. If ($FilterSearch) { $URI = "https://$Global:NectarCloud/dapi/info/session/users?q=$EncodedSearchQuery&usersForAlerts=false&pageSize=$ResultSize&tenant=$TenantName" $UserFilterSession = Set-NectarFilterParams -Scope $Scope $WebContent = Invoke-WebRequest -Method GET -URI $URI -UseBasicParsing -Headers $Global:NectarAuthHeader -WebSession $UserFilterSession } Else { $URI = "https://$Global:NectarCloud/dapi/user/search?q=$EncodedSearchQuery&pageSize=$ResultSize&tenant=$TenantName" $WebContent = Invoke-WebRequest -Method GET -URI $URI -UseBasicParsing -Headers $Global:NectarAuthHeader } Write-Verbose $URI Try { $JSON = ([System.Text.Encoding]::UTF8).GetString($TextEncoding.GetBytes($WebContent.Content)) | ConvertFrom-Json If ($JSON.totalElements -eq 0) { Write-Error "Cannot find user with name $SearchQuery." } If ($TenantName) { # Add the tenant name to the output which helps pipelining $JSON.elements | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty } Return $JSON.elements } Catch { Write-Error "Cannot find user with name $SearchQuery. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } Function Get-NectarUserOverview { <# .SYNOPSIS Returns a usage overview about a given user .DESCRIPTION Returns a usage overview about a given user .PARAMETER EmailAddress The email address of the user. .PARAMETER Identity The numerical ID of the user. Can be obtained via Get-NectarUser and pipelined to Get-NectarUserOverview .PARAMETER ExcludeBaseInfo Exclude basic user information from the output. Saves an API call. .PARAMETER ExcludeCallCount Exclude call count information from the output. Saves an API call. .PARAMETER ExcludeHealth Exclude user health information from the output. Saves an API call. .EXAMPLE Get-NectarUserOverview tferguson@nectarcorp.com .NOTES Version 1.2 #> [Alias("Get-NectarUserDetails")] Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias('name')] [string]$SearchQuery, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias('userId')] [string]$Identity, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$Email, [Parameter(Mandatory=$False)] [switch]$ExcludeBaseInfo, [Parameter(Mandatory=$False)] [switch]$ExcludeCallCount, [Parameter(Mandatory=$False)] [switch]$ExcludeHealth, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } Write-Verbose "Search Query: $SearchQuery" If ($SearchQuery -and !$Identity) { Write-Verbose "Searching..." $UserInfo = Get-NectarUser -SearchQuery $SearchQuery -Tenant $TenantName -ResultSize 1 -ErrorVariable GetUserError $Identity = $UserInfo.UserId If ($UserInfo.email) { $Email = $UserInfo.email } Write-Verbose "Identity: $Identity Email: $Email" } If (!$GetUserError) { $BaseURI = "https://$Global:NectarCloud/dapi/user/$($Identity)?tenant=$TenantName" $CallCountURI = "https://$Global:NectarCloud/dapi/user/$($Identity)/summary/calls?tenant=$TenantName" $HealthURI = "https://$Global:NectarCloud/dapi/user/$($Identity)/health/score?tenant=$TenantName" Try { If (!$ExcludeBaseInfo) { $JSON = Invoke-RestMethod -Method GET -URI $BaseURI -Headers $Global:NectarAuthHeader } Else { $JSON = [pscustomobject]@{} } If (!$ExcludeCallCount) { $CallCountJSON = Invoke-RestMethod -Method GET -URI $CallCountURI -Headers $Global:NectarAuthHeader } If (!$ExcludeHealth) { $HealthJSON = Invoke-RestMethod -Method GET -URI $HealthURI -Headers $Global:NectarAuthHeader } # Add the call count info to the output If ($CallCountJSON) { If ($ExcludeBaseInfo) { $JSON | Add-Member -Name 'Id' -Value $Identity -MemberType NoteProperty $JSON | Add-Member -Name 'Email' -Value $Email -MemberType NoteProperty } $CallCountJSON.psobject.Properties | ForEach-Object { $JSON | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value -Force } } # Add the health info to the output If ($HealthJSON) { If ($ExcludeBaseInfo) { $JSON | Add-Member -Name 'Id' -Value $Identity -MemberType NoteProperty -ErrorAction SilentlyContinue $JSON | Add-Member -Name 'Email' -Value $Email -MemberType NoteProperty -ErrorAction SilentlyContinue } $HealthJSON.psobject.Properties | ForEach-Object { $JSON | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value -Force } } If ($TenantName) {$JSON | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty} # Add the tenant name to the output which helps pipelining $Identity = $NULL Return $JSON } Catch { Write-Error "Unable to find user $EmailAddress. Ensure you typed the name of the user correctly. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } } Function Get-NectarUserAdvancedInfo { <# .SYNOPSIS Returns a usage overview about a given user .DESCRIPTION Returns a usage overview about a given user .PARAMETER EmailAddress The email address of the user. .PARAMETER Identity The numerical ID of the user. Can be obtained via Get-NectarUser and pipelined to Get-NectarUserAdvanced .EXAMPLE Get-NectarUserAdvancedInfo tferguson@nectarcorp.com .NOTES Version 1.1 #> Param ( [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("email")] [string]$EmailAddress, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [Alias("userId")] [string]$Identity, [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)] [string]$TenantName ) Begin { Connect-NectarCloud } Process { # Use globally set tenant name, if one was set and not explicitly included in the command If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { $TenantName = $Global:NectarTenantName } ElseIf ($TenantName) { If ($TenantName -NotIn $Global:NectarTenantList) { $TList = $Global:NectarTenantList -join ', ' Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)" } } If ($EmailAddress -and !$Identity) { $Identity = (Get-NectarUser -SearchQuery $EmailAddress -Tenant $TenantName -ResultSize 1 -ErrorVariable GetUserError).UserId Write-Verbose "Identity: $Identity" } If (!$GetUserError) { $URI = "https://$Global:NectarCloud/dapi/user/$($Identity)/advanced?tenant=$TenantName" Write-Verbose $URI Try { $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader If ($TenantName) {$JSON | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty} # Add the tenant name to the output which helps pipelining Return $JSON } Catch { Write-Error "Unable to find user $EmailAddress. Ensure you typed the name of the user correctly. $($_.Exception.Message)" If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ } } } } } # SIG # Begin signature block # MIIfjAYJKoZIhvcNAQcCoIIffTCCH3kCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCbww8WYSZFHE5H # rQda6spFnyPY+HwiwUnVJGi/cagIPaCCDRIwggZyMIIEWqADAgECAghkM1HTxzif # CDANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx # EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8G # A1UEAwwoU1NMLmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAe # Fw0xNjA2MjQyMDQ0MzBaFw0zMTA2MjQyMDQ0MzBaMHgxCzAJBgNVBAYTAlVTMQ4w # DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENv # cnAxNDAyBgNVBAMMK1NTTC5jb20gQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBD # QSBSU0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCfgxNzqrDG # bSHL24t6h3TQcdyOl3Ka5LuINLTdgAPGL0WkdJq/Hg9Q6p5tePOf+lEmqT2d0bKU # Vz77OYkbkStW72fL5gvjDjmMxjX0jD3dJekBrBdCfVgWQNz51ShEHZVkMGE6ZPKX # 13NMfXsjAm3zdetVPW+qLcSvvnSsXf5qtvzqXHnpD0OctVIFD+8+sbGP0EmtpuNC # GVQ/8y8Ooct8/hP5IznaJRy4PgBKOm8yMDdkHseudQfYVdIYyQ6KvKNc8HwKp4WB # wg6vj5lc02AlvINaaRwlE81y9eucgJvcLGfE3ckJmNVz68Qho+Uyjj4vUpjGYDdk # jLJvSlRyGMwnh/rNdaJjIUy1PWT9K6abVa8mTGC0uVz+q0O9rdATZlAfC9KJpv/X # gAbxwxECMzNhF/dWH44vO2jnFfF3VkopngPawismYTJboFblSSmNNqf1x1KiVgMg # Lzh4gL32Bq5BNMuURb2bx4kYHwu6/6muakCZE93vUN8BuvIE1tAx3zQ4XldbyDge # VtSsSKbt//m4wTvtwiS+RGCnd83VPZhZtEPqqmB9zcLlL/Hr9dQg1Zc0bl0EawUR # 0tOSjAknRO1PNTFGfnQZBWLsiePqI3CY5NEv1IoTGEaTZeVYc9NMPSd6Ij/D+KNV # t/nmh4LsRR7Fbjp8sU65q2j3m2PVkUG8qQIDAQABo4H7MIH4MA8GA1UdEwEB/wQF # MAMBAf8wHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwMAYIKwYBBQUH # AQEEJDAiMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAE # CjAIMAYGBFUdIAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwOwYDVR0fBDQwMjAwoC6g # LIYqaHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLXJzYS1Sb290Q0EuY3JsMB0G # A1UdDgQWBBRUwv4QlQCTzWr158DX2bJLuI8M4zAOBgNVHQ8BAf8EBAMCAYYwDQYJ # KoZIhvcNAQELBQADggIBAPUPJodwr5miyvXWyfCNZj05gtOII9iCv49UhCe204MH # 154niU2EjlTRIO5gQ9tXQjzHsJX2vszqoz2OTwbGK1mGf+tzG8rlQCbgPW/M9r1x # xs19DiBAOdYF0q+UCL9/wlG3K7V7gyHwY9rlnOFpLnUdTsthHvWlM98CnRXZ7WmT # V7pGRS6AvGW+5xI+3kf/kJwQrfZWsqTU+tb8LryXIbN2g9KR+gZQ0bGAKID+260P # Z+34fdzZcFt6umi1s0pmF4/n8OdX3Wn+vF7h1YyfE7uVmhX7eSuF1W0+Z0duGwdc # +1RFDxYRLhHDsLy1bhwzV5Qe/kI0Ro4xUE7bM1eV+jjk5hLbq1guRbfZIsr0WkdJ # LCjoT4xCPGRo6eZDrBmRqccTgl/8cQo3t51Qezxd96JSgjXktefTCm9r/o35pNfV # HUvnfWII+NnXrJlJ27WEQRQu9i5gl1NLmv7xiHp0up516eDap8nMLDt7TAp4z5T3 # NmC2gzyKVMtODWgqlBF1JhTqIDfM63kXdlV4cW3iSTgzN9vkbFnHI2LmvM4uVEv9 # XgMqyN0eS3FE0HU+MWJliymm7STheh2ENH+kF3y0rH0/NVjLw78a3Z9UVm1F5VPz # iIorMaPKPlDRADTsJwjDZ8Zc6Gi/zy4WZbg8Zv87spWrmo2dzJTw7XhQf+xkR6Od # MIIGmDCCBICgAwIBAgIQIc+kRkn+AQupTThE+j58IjANBgkqhkiG9w0BAQsFADB4 # MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x # ETAPBgNVBAoMCFNTTCBDb3JwMTQwMgYDVQQDDCtTU0wuY29tIENvZGUgU2lnbmlu # ZyBJbnRlcm1lZGlhdGUgQ0EgUlNBIFIxMB4XDTI1MDgwODIwMTMzNFoXDTI2MDgw # ODIwMTMzNFowfzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRAwDgYD # VQQHDAdKZXJpY2hvMR4wHAYDVQQKDBVOZWN0YXIgU2VydmljZXMgQ29ycC4xCzAJ # BgNVBAsMAklUMR4wHAYDVQQDDBVOZWN0YXIgU2VydmljZXMgQ29ycC4wggGiMA0G # CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCJXN3SkHk8zvqqnHkfyImA6vDVtGrO # zTVO6nlzNe85eCoGRBk5ToZ+/uUwcFyjcxSV+jbR29y4O6azNBmwvEw96ukUVKUh # J+0NIQoH2DJqtkp4v3EppsevtxxwarqC1fvMXMhz2NVBZS6moStIiFyeGTBgyR7P # gdU+JRqiG1muq5QiSZWjCyBLN6DTDimz5YdX1nhc/64V/oT0g79tYmZm7UEw1rN8 # HZgk46Gezt3IIQGX22ng1nh/3vy1Q46T/8mCT3UANrd3l/jS0XUmYgW8Z91nYlrl # iNH3nHbONGNFFN8WLPAakt3ITeGmqhZkHyyXmlxKlkLHiR8XewRHn7PpD/DT03x7 # ngKS5Ie0fUM1ZAdXDoghvQ6uNuQ5Q3TAjL2ukJs9u5VmvWyFL1l9ujuKCiNGfy1D # cS7u1WlcCIXdrX4Hpe2lt/M7fZFkSMeS1TD2gM2+a/7xK5MWwmbV6qK27nKlRpbG # Q6Yj0VmqJmcgekSrCKPFudNAsDyD6rUYxlUCAwEAAaOCAZUwggGRMAwGA1UdEwEB # /wQCMAAwHwYDVR0jBBgwFoAUVML+EJUAk81q9efA19myS7iPDOMwegYIKwYBBQUH # AQEEbjBsMEgGCCsGAQUFBzAChjxodHRwOi8vY2VydC5zc2wuY29tL1NTTGNvbS1T # dWJDQS1Db2RlU2lnbmluZy1SU0EtNDA5Ni1SMS5jZXIwIAYIKwYBBQUHMAGGFGh0 # dHA6Ly9vY3Nwcy5zc2wuY29tMFEGA1UdIARKMEgwCAYGZ4EMAQQBMDwGDCsGAQQB # gqkwAQMDATAsMCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9z # aXRvcnkwEwYDVR0lBAwwCgYIKwYBBQUHAwMwTQYDVR0fBEYwRDBCoECgPoY8aHR0 # cDovL2NybHMuc3NsLmNvbS9TU0xjb20tU3ViQ0EtQ29kZVNpZ25pbmctUlNBLTQw # OTYtUjEuY3JsMB0GA1UdDgQWBBQoc8kxtmxEx1bpEE+bhb8JNyGrHTAOBgNVHQ8B # Af8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAD1Wlyoz/oOVnzXFQKuv29SQ9J6G # lqSNMvPzF6204eydcEDLwKh5IpZ7iGo6Km5AoVGNzYwJWyWaTwZpaxOoh+M+NK+E # /QIOH+mItAaHhKogn96pHL7ZG9oD23s+/EP9jqNpenOZ0HSBWNHc4PO0e7Ys5zyQ # 0a63PF83kU6hqkny0hca7Mr4gZoFyt6ynEJvv/TIkNCE5tqo/cBW94EpjQBfXTd4 # ycDoQ5Be1gbLboBoEjyrnPl0n+5dQgXSCg25hgf37iTfg+sCXzw3SKeiFauf4s8o # h3wyXvNGzW4q0ZoE+ZNInk/puRVGnGmGZUr6iKuplqey1vneOOAv5we2hryR8PaA # eqo6OqxyEw6a+nmRwf3lsp9k6Aml6ary1bdGjRY+ysScAxbeCvC9yS/EzwtaU3Z8 # R+2qLqh7cX8gztflHxrsV7Ql0nE3MrM0ry2bAWYzthbdwYtIuoeGHibng/qxuHOI # uRLSTzddpXDdLSmw+G116kaxxHCBM+wf6K0nvehm08pXNyzAolNIJrVjsll9YHDT # wws15kpojCglZsMIDYAlrFzF9MI0dRdiaj7/ttGSdblKZJoDOdfPrWMuBlSmjamk # 5VxgKKHPQ9mHTP1Q5baEuotRYqJLgTWV1ZzCF+MYH2vmmuyjm4sSEjVfetLaYwIk # RYAx7I+e9wcfhciSMYIR0DCCEcwCAQEwgYwweDELMAkGA1UEBhMCVVMxDjAMBgNV # BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMREwDwYDVQQKDAhTU0wgQ29ycDE0 # MDIGA1UEAwwrU1NMLmNvbSBDb2RlIFNpZ25pbmcgSW50ZXJtZWRpYXRlIENBIFJT # QSBSMQIQIc+kRkn+AQupTThE+j58IjANBglghkgBZQMEAgEFAKB8MBAGCisGAQQB # gjcCAQwxAjAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC # AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBtAerrAGnFMIEKAUfk # zTediDIFYQan0LXmY/0PKAxM3zANBgkqhkiG9w0BAQEFAASCAYCGCuApnGQ10aEY # VFhAnHQwM6wBSJ4+Ykk0J9mnczyLpTvJkJzj0HGuHs2ZjmYU+bCPG08QZzE7IlxX # WKGnB+CzU1sxq5A9FOh0iM1fQVZOvMGgOTHlJQ2v7vplBvOYXqfyMQmjaRKByFmX # gqcntS6jOoztCWTySOM8OCRMVGEkPNnaRFjJJ9/938OiF42GtSZZn4s0OUY3rjAl # NyabMy2vQBANCJOSYsCGgjkIkvogSxarbqiC67cKYSB6R0Eyce5c7qZwrsIwDQDH # Gs0tSYGvTUVLNUskjotD8TIUHCxARghTlgPAif3h5utfln8F/TBkNBD30A96bZ7e # /V1hNZiNAJJzl0yx9bZNk5QrOcYF+6/8LOMmBb+ryvrK3Q7vTrIPrluHTHupnYRD # q8xZD1bA23G9cB74SsoIv29uIDlq5bgiA3BkFW3RkhC0UvBihFEJN/6/Q2XUMGFH # t/LAytePOOa6CPdluuKYgci8wrEMgqY+8skGlY+FLGpybfwIljahgg8WMIIPEgYK # KwYBBAGCNwMDATGCDwIwgg7+BgkqhkiG9w0BBwKggg7vMIIO6wIBAzENMAsGCWCG # SAFlAwQCATB3BgsqhkiG9w0BCRABBKBoBGYwZAIBAQYMKwYBBAGCqTABAwYBMDEw # DQYJYIZIAWUDBAIBBQAEIMNX2MxkPYmQI67tWwV4kyn9rYrNz06kG5Z/58y8uGQA # AghR04K0O98sWRgPMjAyNjA2MDMxNDA5NTRaMAMCAQGgggwAMIIE/DCCAuSgAwIB # AgIQH2sWYtIuG2xd8cDBoGAOODANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJV # UzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNT # TCBDb3JwMS8wLQYDVQQDDCZTU0wuY29tIFRpbWVzdGFtcGluZyBJc3N1aW5nIFJT # QSBDQSBSMTAeFw0yNTAyMTgxNjMyMDJaFw0zNDExMTIxODUwMDVaMG4xCzAJBgNV # BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UE # CgwIU1NMIENvcnAxKjAoBgNVBAMMIVNTTC5jb20gVGltZXN0YW1waW5nIFVuaXQg # MjAyNSBFMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBv7UVHHb+ZVluxPXlfE # 3M6tg0Xnq8dic+O3vPOCRpalUM1vO9A+GRzSVVjyygHhYrBw62XLFh1kv7e+yRd/ # aTajggFaMIIBVjAfBgNVHSMEGDAWgBQMnRAljpqnG5mHQ88IfuG9gZD0zzBRBggr # BgEFBQcBAQRFMEMwQQYIKwYBBQUHMAKGNWh0dHA6Ly9jZXJ0LnNzbC5jb20vU1NM # LmNvbS10aW1lU3RhbXBpbmctSS1SU0EtUjEuY2VyMFEGA1UdIARKMEgwPAYMKwYB # BAGCqTABAwYBMCwwKgYIKwYBBQUHAgEWHmh0dHBzOi8vd3d3LnNzbC5jb20vcmVw # b3NpdG9yeTAIBgZngQwBBAIwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwRgYDVR0f # BD8wPTA7oDmgN4Y1aHR0cDovL2NybHMuc3NsLmNvbS9TU0wuY29tLXRpbWVTdGFt # cGluZy1JLVJTQS1SMS5jcmwwHQYDVR0OBBYEFM582cAEgMUkEGoJ6hyrJT0R/ajS # MA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAgHN1JIW9ZlNip07F # fY9r1LJwLKTl1h/y9r1BjDgHMEz7U7J7mAy32JxA1KLyjCCJqNkuRfhDHGFEfZtj # TOru7AQMDSDiUDvCCc3jaz5py9jGvwIe5npkLbXqXhA+SqCzG719USigwhHkYr7v # 8NiXoaY0Xu03p0BiZZreZlpngmGB9+86N94FqIFx2I5Z5iuu7d4j7aAOZBNxfU9j # FDIIGDtWfWeCpF0Q8rLE/3DHDlzJKs5Il3i/VoOl7rTU938oSrxMwww6GDBlKX8r # GHxvkjgIb9MXkVglJSDHsNAZDeCS/inaxKHA+ChuB8K4OxIxa6k1e+eHBypakAY3 # wuN7w7PlPmhN6k5IdqZn3HZHs2VjoR841Z9wmVPFdGDdkBZ7XOmb5OZUaKufsvtE # R0VbY2DkzaqAaItt1kc+I+FUz7PiVz2PUzpegkftRRxvrPyIL08blJTnbMQ0XrqD # N0rEfuTLv4XhhnKyJaXhxCUdjO/cRumMzZ35QTUMItBWy1xGp0iyoFVnAya2pPsV # MuAI+sy1zxlOS9l5iSxvKJ8gpnpOgjqYTa7u1eyZo+4JlcGoiiR17LthMTrF1q62 # tO5xOpI8txUZ6gtKGtkJV6wdj+vZLcwKZ2M93GqVpOo6UBlGjx1sKsVZ7AIUzJZl # i4NJ0M2KYcrfNnlebkYKpDnSqWwwggb8MIIE5KADAgECAhBtUhhwh+gjTYVgANCA # j5NWMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhh # czEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTEw # LwYDVQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNB # MB4XDTE5MTExMzE4NTAwNVoXDTM0MTExMjE4NTAwNVowczELMAkGA1UEBhMCVVMx # DjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMREwDwYDVQQKDAhTU0wg # Q29ycDEvMC0GA1UEAwwmU1NMLmNvbSBUaW1lc3RhbXBpbmcgSXNzdWluZyBSU0Eg # Q0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCuURAT0vk8IKAg # hd7JUBxkyeH9xek0/wp/MUjoclrFXqhh/fGH91Fc+7fm0MHCE7A+wmOiqBj9ODrJ # AYGq3rm33jCnHSsCBNWAQYyoauLq8IjqsS1JlXL29qDNMMdwZ8UNzQS7vWZMDJ40 # JSGNphMGTIA2qn2bohGtgRc4p1395ESypUOaGvJ3t0FNL3BuKmb6YctMcQUF2sqo # oMzd89h0E6ujdvBDo6ZwNnWoxj7YmfWjSXg33A5GuY9ym4QZM5OEVgo8ebz/B+gy # hyCLNNhh4Mb/4xvCTCMVmNYrBviGgdPZYrym8Zb84TQCmSuX0JlLLa6WK1aO6qlw # ISbb9bVGh866ekKblC/XRP20gAu1CjvcYciUgNTrGFg8f8AJgQPOCc1/CCdaJSYw # hJpSdheKOnQgESgNmYZPhFOC6IKaMAUXk5U1tjTcFCgFvvArXtK4azAWUOO1Y3fd # ldIBL6LjkzLUCYJNkFXqhsBVcPMuB0nUDWvLJfPimstjJ8lF4S6ECxWnlWi7OElV # wTnt1GtRqeY9ydvvGLntU+FecK7DbqHDUd366UreMkSBtzevAc9aqoZPnjVMjvFq # V1pYOjzmTiVHZtAc80bAfFe5LLfJzPI6DntNyqobpwTevQpHqPDN9qqNO83r3kaw # 8A9j+HZiSw2AX5cGdQP0kG0vhzfgBwIDAQABo4IBgTCCAX0wEgYDVR0TAQH/BAgw # BgEB/wIBADAfBgNVHSMEGDAWgBTdBAkHovV6fVJTEpKV7jiAJQ2mWTCBgwYIKwYB # BQUHAQEEdzB1MFEGCCsGAQUFBzAChkVodHRwOi8vd3d3LnNzbC5jb20vcmVwb3Np # dG9yeS9TU0xjb21Sb290Q2VydGlmaWNhdGlvbkF1dGhvcml0eVJTQS5jcnQwIAYI # KwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMD8GA1UdIAQ4MDYwNAYEVR0g # ADAsMCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkw # EwYDVR0lBAwwCgYIKwYBBQUHAwgwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2Ny # bHMuc3NsLmNvbS9zc2wuY29tLXJzYS1Sb290Q0EuY3JsMB0GA1UdDgQWBBQMnRAl # jpqnG5mHQ88IfuG9gZD0zzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD # ggIBAJIZdQ2mWkLPGQfZ8vyU+sCb8BXpRJZaL3Ez3VDlE3uZk3cPxPtybVfLuqac # i0W6SB22JTMttCiQMnIVOsXWnIuAbD/aFTcUkTLBI3xys+wEajzXaXJYWACDS47B # RjDtYlDW14gLJxf8W6DQoH3jHDGGy8kGJFOlDKG7/YrK7UGfHtBAEDVe6lyZ+FtC # srk7dD/IiL/+Q3Q6SFASJLQ2XI89ihFugdYL77CiDNXrI2MFspQGswXEAGpHuaQD # THUp/LdR3TyrIsLlnzoLskUGswF/KF8+kpWUiKJNC4rPWtNrxlbXYRGgdEdx8SMj # UTDClldcrknlFxbqHsVmr9xkT2QtFmG+dEq1v5fsIK0vHaHrWjMMmaJ9i+4qGJSD # 0stYfQ6v0PddT7EpGxGd867Ada6FZyHwbuQSadMb0K0P0OC2r7rwqBUe0BaMqTa6 # LWzWItgBjGcObXeMxmbQqlEz2YtAcErkZvh0WABDDE4U8GyV/32FdaAvJgTfe9Mi # L2nSBioYe/g5mHUSWAay/Ip1RQmQCvmF9sNfqlhJwkjy/1U1ibUkTIUBX3HgymyQ # vqQTZLLys6pL2tCdWcjI9YuLw30rgZm8+K387L7ycUvqrmQ3ZJlujHl3r1hgV76s # 3WwMPgKk1bAEFMj+rRXimSC+Ev30hXZdqyMdl/il5Ksd0vhGMYICWDCCAlQCAQEw # gYcwczELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3Vz # dG9uMREwDwYDVQQKDAhTU0wgQ29ycDEvMC0GA1UEAwwmU1NMLmNvbSBUaW1lc3Rh # bXBpbmcgSXNzdWluZyBSU0EgQ0EgUjECEB9rFmLSLhtsXfHAwaBgDjgwCwYJYIZI # AWUDBAIBoIIBYTAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcN # AQkFMQ8XDTI2MDYwMzE0MDk1NFowKAYJKoZIhvcNAQk0MRswGTALBglghkgBZQME # AgGhCgYIKoZIzj0EAwIwLwYJKoZIhvcNAQkEMSIEIHgVmO746c0Cd5nLGGhKLfVj # CxeWfxAdtKfgnT4tLlhrMIHJBgsqhkiG9w0BCRACLzGBuTCBtjCBszCBsAQgVCr5 # oWqNci5mEUl4iumUwYqaruWmXLNEolSa+Wx5x4swgYswd6R1MHMxCzAJBgNVBAYT # AlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwI # U1NMIENvcnAxLzAtBgNVBAMMJlNTTC5jb20gVGltZXN0YW1waW5nIElzc3Vpbmcg # UlNBIENBIFIxAhAfaxZi0i4bbF3xwMGgYA44MAoGCCqGSM49BAMCBEcwRQIhAJZm # vWNXnUupX+3j16tpdY5p4QSrcZ3r6jiPfUICmvOZAiAJbAIPnn/iCt1NSKIf4zrI # UTxv/FLkehuLMHvSH5MxFg== # SIG # End signature block |