feat(launcher): tenant picker with name resolution in TUI
- Start-IntuneToolkit.ps1 now shows a tenant picker as the first step when -TenantId is not provided. - Lists saved tenants from Settings.json, attempting to display cached tenant names alongside GUIDs. - Offers '[+ Onboard new tenant]' option for entering new tenants. - Automatically resolves unknown tenant names via Graph /organization and caches them back to Settings.json for future use.
This commit is contained in:
@@ -86,6 +86,183 @@ function Select-MenuItem
|
||||
|
||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
|
||||
#region Tenant selection
|
||||
function Get-DefaultSettingsPath
|
||||
{
|
||||
if($IsWindows -or $env:OS -eq "Windows_NT")
|
||||
{
|
||||
if($env:LOCALAPPDATA) { return (Join-Path $env:LOCALAPPDATA "macOS_IntuneManagement\Settings.json") }
|
||||
return (Join-Path $env:USERPROFILE "AppData\Local\macOS_IntuneManagement\Settings.json")
|
||||
}
|
||||
if($IsMacOS) { return (Join-Path $HOME "Library/Application Support/macOS_IntuneManagement/Settings.json") }
|
||||
return (Join-Path $HOME ".local/share/macOS_IntuneManagement/Settings.json")
|
||||
}
|
||||
|
||||
function Get-SavedTenants
|
||||
{
|
||||
param([string]$SettingsPath)
|
||||
if(-not (Test-Path $SettingsPath)) { return @() }
|
||||
try
|
||||
{
|
||||
$raw = Get-Content $SettingsPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop
|
||||
$tenants = @()
|
||||
foreach($key in $raw.Keys)
|
||||
{
|
||||
if($key -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$')
|
||||
{
|
||||
$name = $null
|
||||
if($raw[$key] -is [hashtable] -and $raw[$key].ContainsKey('TenantName'))
|
||||
{
|
||||
$name = $raw[$key]['TenantName']
|
||||
}
|
||||
elseif($raw[$key] -is [psobject] -and $raw[$key].PSObject.Properties['TenantName'])
|
||||
{
|
||||
$name = $raw[$key].TenantName
|
||||
}
|
||||
$display = if($name) { "$name ($key)" } else { $key }
|
||||
$tenants += [PSCustomObject]@{ TenantId = $key; TenantName = $name; Display = $display }
|
||||
}
|
||||
}
|
||||
return $tenants | Sort-Object Display
|
||||
}
|
||||
catch
|
||||
{
|
||||
return @()
|
||||
}
|
||||
}
|
||||
|
||||
function Update-TenantNameCache
|
||||
{
|
||||
param([string]$SettingsPath, [string]$TenantId, [string]$TenantName)
|
||||
if(-not (Test-Path $SettingsPath)) { return }
|
||||
try
|
||||
{
|
||||
$raw = Get-Content $SettingsPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop
|
||||
if($raw[$TenantId] -is [hashtable])
|
||||
{
|
||||
$raw[$TenantId]['TenantName'] = $TenantName
|
||||
}
|
||||
else
|
||||
{
|
||||
$raw[$TenantId] = @{ TenantName = $TenantName }
|
||||
}
|
||||
$raw | ConvertTo-Json -Depth 10 | Set-Content -Path $SettingsPath -Force
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
function Resolve-TenantName
|
||||
{
|
||||
param([string]$TenantId, [string]$SettingsPath)
|
||||
$settingsObj = $null
|
||||
try
|
||||
{
|
||||
$settingsObj = Get-Content $SettingsPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop
|
||||
}
|
||||
catch { return $null }
|
||||
|
||||
$tenantNode = $settingsObj[$TenantId]
|
||||
if(-not $tenantNode) { return $null }
|
||||
|
||||
$appId = $tenantNode['GraphAzureAppId']
|
||||
if(-not $appId) { return $null }
|
||||
|
||||
$secret = $tenantNode['GraphAzureAppSecret']
|
||||
$cert = $tenantNode['GraphAzureAppCert']
|
||||
|
||||
if(-not $secret -and $IsMacOS)
|
||||
{
|
||||
try
|
||||
{
|
||||
$keychainSecret = security find-generic-password -a "IntuneManagement" -s "IntuneMgmt-$AppId" -w 2>$null
|
||||
if($keychainSecret) { $secret = $keychainSecret }
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
$runtimeModule = Join-Path $projectRoot "Runtime/IntuneManagement.Runtime.psd1"
|
||||
if(-not (Test-Path $runtimeModule)) { return $null }
|
||||
|
||||
$invokeParams = @{
|
||||
Silent = $true
|
||||
JSonSettings = $true
|
||||
JSonFile = $SettingsPath
|
||||
TenantId = $TenantId
|
||||
AppId = $appId
|
||||
AuthMode = "AppOnly"
|
||||
}
|
||||
if($secret) { $invokeParams.Secret = $secret }
|
||||
elseif($cert) { $invokeParams.Certificate = $cert }
|
||||
|
||||
try
|
||||
{
|
||||
Import-Module $runtimeModule -Force | Out-Null
|
||||
Initialize-IntuneManagementRuntime -View "IntuneGraphAPI" @invokeParams | Out-Null
|
||||
if(Get-Command Invoke-GraphRequest -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$org = Invoke-GraphRequest "/organization" -ErrorAction Stop
|
||||
if($org.value -and $org.value[0].displayName)
|
||||
{
|
||||
return $org.value[0].displayName
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return $null
|
||||
}
|
||||
|
||||
$settingsPath = $SettingsFile
|
||||
if(-not $settingsPath) { $settingsPath = Get-DefaultSettingsPath }
|
||||
|
||||
if(-not $TenantId)
|
||||
{
|
||||
$tenants = Get-SavedTenants -SettingsPath $settingsPath
|
||||
$tenantOptions = @()
|
||||
foreach($t in $tenants)
|
||||
{
|
||||
$tenantOptions += $t.Display
|
||||
}
|
||||
$tenantOptions += "[+ Onboard new tenant]"
|
||||
$tenantOptions += "[Exit]"
|
||||
|
||||
$selectedTenantDisplay = Select-MenuItem -Items $tenantOptions -Header "Select a tenant"
|
||||
if(-not $selectedTenantDisplay -or $selectedTenantDisplay -eq "[Exit]")
|
||||
{
|
||||
exit 0
|
||||
}
|
||||
elseif($selectedTenantDisplay -eq "[+ Onboard new tenant]")
|
||||
{
|
||||
$TenantId = Read-Host "Enter the new Tenant ID (GUID)"
|
||||
if(-not $TenantId)
|
||||
{
|
||||
Write-Host "No tenant ID provided. Exiting." -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$TenantId = $selectedTenantDisplay -replace '.*\(([0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12})\)$', '$1'
|
||||
if(-not $TenantId)
|
||||
{
|
||||
$TenantId = $selectedTenantDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$currentTenant = (Get-SavedTenants -SettingsPath $settingsPath) | Where-Object { $_.TenantId -eq $TenantId } | Select-Object -First 1
|
||||
if(-not $currentTenant -or -not $currentTenant.TenantName)
|
||||
{
|
||||
Write-Host "`nResolving tenant name..." -ForegroundColor Cyan
|
||||
$resolvedName = Resolve-TenantName -TenantId $TenantId -SettingsPath $settingsPath
|
||||
if($resolvedName)
|
||||
{
|
||||
Update-TenantNameCache -SettingsPath $settingsPath -TenantId $TenantId -TenantName $resolvedName
|
||||
Write-Host "Cached tenant name: $resolvedName" -ForegroundColor Green
|
||||
$currentTenant = [PSCustomObject]@{ TenantId = $TenantId; TenantName = $resolvedName; Display = "$resolvedName ($TenantId)" }
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
# Build common parameter hashtable
|
||||
$commonParams = @{
|
||||
TenantId = $TenantId
|
||||
@@ -119,6 +296,14 @@ while($true)
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host " macOS Intune Toolkit" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
if($currentTenant -and $currentTenant.TenantName)
|
||||
{
|
||||
Write-Host " Tenant: $($currentTenant.TenantName) ($TenantId)" -ForegroundColor Green
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host " Tenant: $TenantId" -ForegroundColor Green
|
||||
}
|
||||
Write-Host " Press Esc to go back, Space to select" -ForegroundColor DarkGray
|
||||
|
||||
$selection = Select-MenuItem -Items $menuItems -Header "Select a tool to launch"
|
||||
|
||||
Reference in New Issue
Block a user