functions/Get-BapTenant.ps1
|
<# .SYNOPSIS Retrieves information about the available azure tenant. .DESCRIPTION This function retrieves information about the available azure tenants based on cached credentials in the local Azure PowerShell context. .PARAMETER Upn Specifies the User Principal Name (UPN) of the user account to filter the results. Supports wildcard patterns. Defaults to "*" which means all UPNs. .PARAMETER TenantId Specifies the Tenant ID to filter the results. Supports wildcard patterns. Defaults to "*" which means all Tenant IDs. .PARAMETER AsExcelOutput Instructs the function to export the results to an Excel file. .PARAMETER AsHashTable Instructs the function to export the results to a hashtable. .EXAMPLE PS C:\> Get-BapTenant This will retrieve all available tenants based on cached Azure PowerShell credentials. .EXAMPLE PS C:\> Get-BapTenant -Upn "alex@contoso.com" This will retrieve the tenant information for the specified UPN. It will only return results where the UPN matches "alex@contoso.com". .EXAMPLE PS C:\> Get-BapTenant -TenantId "12345678-90ab-cdef-1234-567890abcdef" This will retrieve the tenant information for the specified Tenant ID. It will only return results where the Tenant ID matches "12345678-90ab-cdef-1234-567890abcdef". .EXAMPLE PS C:\> Get-BapTenant -AsExcelOutput This will export the retrieved tenant information to an Excel file. .EXAMPLE PS C:\> Get-BapTenant -AsHashTable This will export the retrieved tenant information to a hashtable. .NOTES Author: Mötz Jensen (@Splaxi) #> function Get-BapTenant { [CmdletBinding(DefaultParameterSetName = 'Default')] [OutputType('System.Object[]')] param ( [Parameter()] [Alias("Login")] [Alias("User")] [Alias("Username")] [string] $Upn = "*", [Parameter()] [string] $TenantId = "*", [Parameter(ParameterSetName = 'Excel')] [switch] $AsExcelOutput, [Parameter(ParameterSetName = 'HashTable')] [switch] $AsHashTable ) begin { try { $tenantDomains = @(Get-AzTenant -ErrorAction Stop) } catch { Write-PSFMessage -Level Verbose -Message "Get-AzTenant failed with: $($_.Exception.Message). Tenant names will be empty." $tenantDomains = @() } } process { $azContexts = $null try { $azContexts = @(Get-AzContext -ListAvailable -ErrorAction Stop) } catch { # Az.Accounts (seen in 2.17.0) throws NullReferenceException from # Get-AzContext -ListAvailable when any cached context has no # subscription (e.g. a tenant-only login created via # Connect-AzAccount -Tenant ... -SkipContextPopulation $true). # It sorts by Subscription.Name without a null check, so one # subscription-less entry breaks the whole listing. Fall back to # the cached profile file, which contains the same Account/Tenant # pairs Get-BapTenant needs. Write-PSFMessage -Level Verbose -Message "Get-AzContext -ListAvailable failed with: $($_.Exception.Message). Falling back to cached Azure profile." $azContexts = @() $contextFiles = @() if (-not [string]::IsNullOrWhiteSpace($env:AZURE_CONFIG_DIR)) { $contextFiles += Join-Path $env:AZURE_CONFIG_DIR "AzureRmContext.json" } if ($HOME) { $contextFiles += Join-Path (Join-Path $HOME ".Azure") "AzureRmContext.json" } if ($env:USERPROFILE) { $contextFiles += Join-Path (Join-Path $env:USERPROFILE ".Azure") "AzureRmContext.json" } $contextFile = $contextFiles | Where-Object { -not [string]::IsNullOrWhiteSpace($_) -and (Test-Path $_) } | Select-Object -First 1 if ($contextFile) { try { $cachedProfile = Get-Content -Raw -Path $contextFile -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop foreach ($prop in $cachedProfile.Contexts.PSObject.Properties) { $entry = $prop.Value if ($null -eq $entry -or $null -eq $entry.Tenant -or [string]::IsNullOrWhiteSpace($entry.Tenant.Id)) { continue } if ($null -eq $entry.Account -or [string]::IsNullOrWhiteSpace($entry.Account.Id)) { continue } $azContexts += [PSCustomObject]@{ Account = [PSCustomObject]@{ Id = $entry.Account.Id } Tenant = [PSCustomObject]@{ Id = $entry.Tenant.Id } } } } catch { Write-PSFMessage -Level Verbose -Message "Failed to read cached Azure contexts from '$contextFile': $($_.Exception.Message)" } } if ($azContexts.Count -eq 0) { # Last resort: at least return the current context so the # cmdlet still works when the cache file is missing. try { $current = Get-AzContext -ErrorAction Stop if ($null -ne $current -and $null -ne $current.Tenant -and $current.Tenant.Id) { $azContexts = @($current) } } catch { Write-PSFMessage -Level Verbose -Message "Get-AzContext (current) also failed with: $($_.Exception.Message)" } } } $cachedCreds = @( ($azContexts | ` Where-Object { $null -ne $_.Tenant.Id } | ` Group-Object { $_.Tenant.Id }, { $_.Account.Id }) | ` ForEach-Object { $_.Group[0] } ) $resCol = @( foreach ($credObj in $cachedCreds) { if (-not ($credObj.Account.Id -like $Upn)) { continue } if (-not ($credObj.Tenant.Id -like $TenantId)) { continue } $credObj | Select-PSFObject -TypeName "D365Bap.Tools.TenantCredential" ` -Property @{ Name = "Upn"; Expression = { $_.Account.Id } }, @{ Name = "TenantId"; Expression = { $_.Tenant.Id } }, @{ Name = "TenantName"; Expression = { $tenantDomains | Where-Object id -eq $_.Tenant.Id | Select-Object -ExpandProperty name -First 1 } } } ) if ($AsExcelOutput) { $resCol | Export-Excel -WorksheetName "Get-BapTenant" return } elseif ($AsHashTable) { $resCol | ConvertTo-PSFHashtable return } $resCol } end { } } |