source/Public/Update-RJTenant.ps1
|
function Update-RJTenant { <# .SYNOPSIS Updates an existing RealmJoin tenant by updating service principal permissions and removing legacy applications. .DESCRIPTION This cmdlet updates an existing RealmJoin tenant by: 1. Installing mandatory features if not present (same as New-RJTenant) 2. Adding/removing permissions to align with current configuration 3. Removing legacy applications that are no longer needed This is essentially the same as New-RJTenant but includes cleanup of legacy applications. .PARAMETER Features Optional array of feature names to enable. Available features can be viewed using Show-RJFeatureInfo. Mandatory features are automatically included and don't need to be specified. Default: @('IntuneLAPS', 'ShowSignin', 'Autopilot', 'DeviceIntuneActions', 'DeviceHealthScript') Use @() to enable only mandatory features. Cannot be used together with AddFeatures or RemoveFeatures. .PARAMETER AddFeatures Optional array of feature names to add to the current configuration. Existing features remain unchanged. Available features can be viewed using Show-RJFeatureInfo. Cannot be used together with Features or All. .PARAMETER RemoveFeatures Optional array of feature names to remove from the current configuration. Existing features (except those being removed) remain unchanged. Cannot be used together with Features or All. Mandatory features cannot be removed. .PARAMETER All When specified, enables all available features (both mandatory and optional). Cannot be used together with AddFeatures or RemoveFeatures. .PARAMETER ReadOnly When specified, assigns read-only permissions instead of full permissions where available. For example, Group.ReadWrite.All becomes Group.Read.All. In incremental mode (AddFeatures/RemoveFeatures), only applies to new features being added. .PARAMETER Token Optional token for RealmJoin customer API integration. When provided, sends the configured optional features to the RealmJoin customer API after successful tenant update. .PARAMETER WhatIf Shows what would be done without actually performing the tenant update. .EXAMPLE Update-RJTenant Updates the tenant with mandatory features plus default optional features and removes legacy apps. .EXAMPLE Update-RJTenant -AddFeatures @('Client') Adds the Client feature to the current tenant configuration while keeping existing features unchanged. .EXAMPLE Update-RJTenant -RemoveFeatures @('DeviceHealthScript') Removes the DeviceHealthScript feature from the current tenant configuration while keeping other features. .EXAMPLE Update-RJTenant -AddFeatures @('Client') -RemoveFeatures @('ShowSignin') Adds Client feature and removes ShowSignin feature in a single operation. .EXAMPLE Update-RJTenant -AddFeatures @('Client') -ReadOnly Adds the Client feature with read-only permissions while keeping existing features unchanged. .EXAMPLE Update-RJTenant -Features @() Updates the tenant with only mandatory features and removes legacy apps. .EXAMPLE Update-RJTenant -Features @('DeviceHealthScript') Updates the tenant with mandatory features plus only DeviceHealthScript and removes legacy apps. .EXAMPLE Update-RJTenant -All Updates the tenant with all available features enabled and removes legacy apps. .EXAMPLE Update-RJTenant -ReadOnly Updates the tenant with default features using read-only permissions and removes legacy apps. .EXAMPLE Update-RJTenant -All -ReadOnly Updates the tenant with all available features using read-only permissions and removes legacy apps. .EXAMPLE Update-RJTenant -WhatIf Shows what permissions would be updated and what legacy apps would be removed. .EXAMPLE Update-RJTenant -Features @('DeviceHealthScript') -Verbose Updates tenant with detailed verbose output showing the update process. .EXAMPLE Update-RJTenant -Token "abc123" Updates the tenant with default features and sends configuration to RealmJoin customer API. .EXAMPLE Complete-RJTenantOnboarding -Features @('DeviceHealthScript') Same as Update-RJTenant - completes tenant onboarding using the alias. .EXAMPLE Complete-RJTenantOnboarding -All -ReadOnly Completes tenant onboarding with all available features using read-only permissions using the alias. .NOTES This cmdlet requires appropriate Azure AD permissions to create/update service principals, assign app roles, and delete service principals. Mandatory features are always enabled regardless of the Features parameter. Use either -Features/-All or -AddFeatures/-RemoveFeatures, but not both. The -ReadOnly switch applies to all selected features in traditional mode, or only to new features in incremental mode. The alias Complete-RJTenantOnboarding can be used interchangeably with Update-RJTenant. #> [Alias('Complete-RJTenantOnboarding')] [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Features')] param( [Parameter(ParameterSetName = 'Features')] [string[]]$Features, [Parameter(ParameterSetName = 'Incremental')] [string[]]$AddFeatures = @(), [Parameter(ParameterSetName = 'Incremental')] [string[]]$RemoveFeatures = @(), [Parameter(ParameterSetName = 'All')] [switch]$All, [switch]$ReadOnly, [string]$Token ) begin { Write-Verbose "Updating RealmJoin tenant" } process { Write-Information "Initializing required modules" if (-not (Initialize-RequiredModule)) { # Modules are not ready - exit gracefully without throwing Write-Verbose "Module initialization failed - function cannot proceed" return } Write-Information "All required modules are initialized" Write-Information "Logging in" $null = Invoke-GraphLogin Write-Information "Getting tenant information" $tenantInfo = Get-TenantInfo Write-Information "Tenant: $($tenantInfo.DisplayName) ($($tenantInfo.TenantId))" # Validate parameter combinations and determine mode switch ($PSCmdlet.ParameterSetName) { 'Incremental' { # Validate that at least one incremental parameter is provided if ($AddFeatures.Count -eq 0 -and $RemoveFeatures.Count -eq 0) { throw "At least one of AddFeatures or RemoveFeatures must be specified in incremental mode" } Write-Verbose "Using incremental mode: Add=$($AddFeatures.Count), Remove=$($RemoveFeatures.Count), ReadOnly=$($ReadOnly.IsPresent)" # Get current configuration $currentConfig = Get-RJCurrentConfiguration $featureResolution = Resolve-RJFeature -CurrentConfig $currentConfig -FeaturesToAdd $AddFeatures -FeaturesToRemove $RemoveFeatures -ReadOnly:$ReadOnly $operationParts = @() if ($AddFeatures.Count -gt 0) { $operationParts += "adding $($AddFeatures.Count) feature$(if($AddFeatures.Count -ne 1){'s'})" } if ($RemoveFeatures.Count -gt 0) { $operationParts += "removing $($RemoveFeatures.Count) feature$(if($RemoveFeatures.Count -ne 1){'s'})" } $permissionMode = if ($ReadOnly) { "read-only for new features" } else { "full for new features" } Write-Information "Incremental update: $($operationParts -join ', ') with $permissionMode" } default { # Traditional mode: determine selected features based on parameter set $selectedFeatures = switch ($PSCmdlet.ParameterSetName) { 'All' { if ($All) { # No action needed, just for clarity } Write-Verbose "Using -All switch: enabling all available features" (Get-RJFeatureDefinitionList).Name } 'Features' { if($Features.Count -eq 0){ $Features = $DefaultSelectedFeatures Write-Verbose "Parameter 'Features' specified but empty, using default features" } Write-Verbose "Using specified features: $($Features -join ', ')" $Features } default { Write-Verbose "No parameters specified, using default features" $DefaultSelectedFeatures } } $featureResolution = Resolve-RJFeature -SelectedFeatures $selectedFeatures -ReadOnly:$ReadOnly $permissionMode = if ($ReadOnly) { "read-only" } else { "full" } Write-Information "Selected features: $($featureResolution.FeatureNames -join ', ') with $permissionMode permissions" } } # Get analysis $analysis = Get-RJTenantPermissionAnalysis -FeatureResolution $featureResolution # Determine which command was used for ShouldProcess message $commandUsed = if ($MyInvocation.InvocationName -eq 'Complete-RJTenantOnboarding') { 'Complete-RJTenantOnboarding' } else { 'Update-RJTenant' } if ($PSCmdlet.ShouldProcess("Tenant: $($tenantInfo.DisplayName) ($($tenantInfo.TenantId))", $commandUsed)) { # Step 1: Service Principal Operations $permissionResults = Set-RJTenantServicePrincipal -FeatureResolution $featureResolution if (-not $permissionResults.Success) { throw "Failed to configure service principals" } # Step 2: Legacy Applications Write-Information "" Write-Information "=== Cleaning Up Legacy Applications ===" $legacyApps = Get-RJLegacyAppList if (-not $legacyApps -or $legacyApps.Count -eq 0) { Write-Information "No legacy applications configured for cleanup." $cleanupResults = @{ ProcessedApps = @(); Success = $true } } else { $cleanupResults = Remove-RJLegacyApplication if (-not $cleanupResults.Success) { Write-Warning "Legacy application cleanup encountered issues but continuing" } } # Send token to customer API if provided if ($Token) { $optionalFeatures = $permissionResults.FeatureResolution.FeatureNames | Where-Object { $_ -notin (Get-RJMandatoryFeatureList).Name } Invoke-RJTenantRefresh -Token $Token -OptionalFeatures $optionalFeatures } # Open RealmJoin Portal if new service principal was created Open-RJPortalIfNewServicePrincipal -ProcessedApps $permissionResults.ProcessedApps # Final summary Write-Information "" Write-Information "=== Update Summary ===" $cleanupApps = $cleanupResults.ProcessedApps | Where-Object { $_.Action -eq 'Removed' } Write-Information "Legacy apps processed: $($cleanupResults.ProcessedApps.Count) checked, $($cleanupApps.Count) removed" Write-Information "" if ($featureResolution.IsIncrementalMode) { $permissionMode = if ($ReadOnly) { "read-only for new features" } else { "full for new features" } Write-Information "Successfully updated RealmJoin tenant using incremental mode with $permissionMode" Write-Information "Final features: $($permissionResults.FeatureResolution.FeatureNames -join ', ')" if ($AddFeatures -and $AddFeatures.Count -gt 0) { Write-Information "Added features: $($AddFeatures -join ', ')" } if ($RemoveFeatures -and $RemoveFeatures.Count -gt 0) { Write-Information "Removed features: $($RemoveFeatures -join ', ')" } } else { $permissionMode = if ($ReadOnly) { "read-only" } else { "full" } Write-Information "Successfully updated RealmJoin tenant with $($permissionResults.FeatureResolution.FeatureNames.Count) features using $permissionMode permissions" Write-Information "Enabled features: $($permissionResults.FeatureResolution.FeatureNames -join ', ')" } if ($cleanupApps.Count -gt 0) { Write-Information "Removed legacy applications: $($cleanupApps.DisplayName -join ', ')" } } else { # Show analysis for all service principals (WhatIf mode) Write-Verbose "Showing analysis in WhatIf mode" Show-RJFeatureAnalysis -FeatureAnalysis $analysis.FeatureAnalysis -OrphanedServicePrincipals $analysis.OrphanedServicePrincipals # Show analysis for all legacy apps (WhatIf mode) $legacyApps = Get-RJLegacyAppList if ($legacyApps -and $legacyApps.Count -gt 0) { Write-Verbose "Getting analysis for all legacy applications using shared diff logic" $legacyDiffs = @() foreach ($legacyApp in $legacyApps) { $legacyDiffs += Get-RJLegacyAppDiff -LegacyApp $legacyApp } Show-RJLegacyAppAnalysis -Analysis $legacyDiffs } } } end { Write-Verbose "RealmJoin tenant update completed" } } |