Public/Add-PartnerCenterAccounts.ps1
|
function Add-PartnerCenterAccounts { [CmdletBinding(DefaultParameterSetName = 'Interactive')] param ( [Parameter(ParameterSetName = 'CSV')] [string]$CsvPath, [Parameter(Mandatory = $true, ParameterSetName = 'KeyVault')] [Parameter(Mandatory = $true, ParameterSetName = 'KeyVaultCSV')] [Parameter(Mandatory = $true, ParameterSetName = 'SAMConfig')] [ValidateSet('KeyVault', 'ConfigFile', 'SAMConfig')] [string]$CredentialSource = 'ConfigFile', [Parameter(Mandatory = $true, ParameterSetName = 'KeyVault')] [Parameter(Mandatory = $true, ParameterSetName = 'KeyVaultCSV')] [string]$KeyVaultName, [Parameter(Mandatory = $true, ParameterSetName = 'SAMConfig')] [PSObject]$SAMCredentials, [Parameter()] [switch]$Force, [Parameter()] [string[]]$ExcludeTenants, [Parameter()] [int]$ThrottleLimit = 4, [Parameter()] [ValidateSet('NewADDS', 'ExistingADDS', 'ExistingADFSFed', 'AzureAD')] [string]$ActiveDirectoryType = 'AzureAD', [Parameter()] [bool]$LimitedAccessEnabled = $false, [Parameter()] [bool]$EnableWVD = $false, [Parameter()] [bool]$EnableSelfManagedCloudPC = $false, [Parameter()] [bool]$EnableEndpointManagedCloudPC = $false, [Parameter()] [bool]$EnableEndpointManagedWithIntune = $true, [Parameter(ParameterSetName = 'SingleTenant')] [string]$TenantId ) begin { Write-Verbose "Initializing tenant provisioning using $CredentialSource" # Get SAM credentials try { $samCredentials = switch ($CredentialSource) { 'KeyVault' { Get-SecureApplicationModel -Source KeyVault -KeyVaultName $KeyVaultName } 'SAMConfig' { $SAMCredentials } default { Get-SecureApplicationModel -Source ConfigFile } } } catch { throw "Failed to retrieve SAM credentials: $_" } # Initialize collections $tenantsToProcess = [System.Collections.Generic.List[object]]::new() $results = [System.Collections.Generic.List[object]]::new() # Create deployment options object $deploymentOptions = @{ wvd = $EnableWVD selfManagedCloudPc = $EnableSelfManagedCloudPC endpointManagedCloudPc = $EnableEndpointManagedCloudPC endpointManagedWithIntune = $EnableEndpointManagedWithIntune } # Ensure all necessary variables are initialized if (-not $samCredentials) { throw "SAM credentials are not initialized." } $applicationId = $samCredentials.ApplicationId $applicationSecret = $samCredentials.ApplicationSecret $refreshToken = $samCredentials.RefreshToken if (-not $applicationId -or -not $applicationSecret -or -not $refreshToken) { throw "One or more SAM credential components are not initialized." } } process { try { # Get existing accounts first Write-Verbose "Getting existing accounts" $existingAccounts = Get-NMMAccount $existingTenantIds = $existingAccounts.tenantId Write-Verbose "Found these accounts in NMM: $($existingAccounts)" # Get Graph token for MSP tenant Write-Verbose "Getting Graph token for MSP tenant" if (-not $Script:GraphHeader) { Write-Verbose "No existing Graph token found, connecting to Graph API" $graphParams = @{ ApplicationId = $samCredentials.ApplicationId ApplicationSecret = $samCredentials.ApplicationSecret TenantID = $samCredentials.TenantId RefreshToken = $samCredentials.RefreshToken } $graphToken = Connect-GraphApiSAM @graphParams } else { Write-Verbose "Using existing Graph token" $graphToken = $Script:GraphHeader } # Get tenants to process if ($PSCmdlet.ParameterSetName -eq 'CSV') { Write-Verbose "Processing tenants from CSV: $CsvPath" $tenantsToProcess.AddRange(@(Import-Csv -Path $CsvPath)) } else { Write-Verbose "Retrieving customers from Graph API" $params = @{ Uri = "https://graph.microsoft.com/v1.0/contracts?`$top=999" Method = "GET" Headers = $graphToken } $tenants = Invoke-RestMethod @params Write-Verbose "Found these Tenants `n $($tenants)" if ($TenantId) { Write-Verbose "Filtering for specific tenant: $TenantId" $newTenants = @($tenants.value | Where-Object { $_.customerId -eq $TenantId -and $_.customerId -notin $existingTenantIds }) } else { # Filter out existing tenants and add the rest $newTenants = @($tenants.value | Where-Object { $_.customerId -notin $existingTenantIds }) } Write-Verbose "Found $($tenants.value.Count) total tenants, $($newTenants.Count) new tenants to process" if ($newTenants.Count -gt 0) { $tenantsToProcess.AddRange($newTenants) } } # Filter out excluded tenants if ($ExcludeTenants) { $tenantsToProcess = $tenantsToProcess | Where-Object { $_.defaultDomainName -notin $ExcludeTenants } } Write-Verbose "Processing $($tenantsToProcess.Count) tenants" # Early exit if no tenants to process if ($tenantsToProcess.Count -eq 0) { Write-Output "No new tenants to process. Exiting..." return } $modulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\NMM-ps.psm1' $tenantsToProcess | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { # Import the module in the parallel runspace Import-Module -Name $using:modulePath -Force $tenant = $_ $result = [PSCustomObject]@{ TenantId = $tenant.customerId Domain = $tenant.defaultDomainName Status = 'Processing' Error = $null } try { # Get Graph token for the tenant $graphCustomerTokenParams = @{ TenantId = $tenant.customerId ApplicationSecret = $using:applicationSecret ApplicationId = $using:applicationId RefreshToken = $using:refreshToken Scope = 'https://graph.microsoft.com/Directory.AccessAsUser.All' } $graphCustomerToken = Connect-GraphApiSAM @graphCustomerTokenParams # Get Azure token for the tenant $azureTokenParams = @{ TenantId = $tenant.customerId ApplicationSecret = $using:applicationSecret ApplicationId = $using:applicationId RefreshToken = $using:refreshToken } $azureToken = Connect-AzureApiSAM @azureTokenParams $body = @{ subscriptionId = $null azureAccessToken = $azureToken.Authorization.Replace("Bearer ", "") graphAccessToken = $graphCustomerToken.Authorization.Replace("Bearer ", "") companyName = $tenant.displayName activeDirectoryType = $using:ActiveDirectoryType limitedAccessEnabled = $using:LimitedAccessEnabled desktopDeploymentOptions = $using:deploymentOptions } $null = Invoke-APIRequest -Method 'POST' -Endpoint 'accountprovisioning/LinkTenant' -Body $body $result.Status = 'Success' } catch { $result.Status = 'Failed' $result.Error = $_.Exception.Message } # Add each result to the results collection ($using:results).Add($result) } } catch { Write-Error "Failed to process tenant accounts: $_" } } end { # Output results Write-Output $results } } |