Public/License/Set-CloudLicense.ps1
function Set-CloudLicense { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] Param ( [Parameter(Mandatory = $false)] [switch] $RemoveSkus, [Parameter(Mandatory = $false)] [switch] $AddSkus, [Parameter(Mandatory = $false)] [switch] $RemoveOptions, [Parameter(Mandatory = $false)] [switch] $AddOptions, [Parameter(Mandatory = $false)] [switch] $MoveOptionsFromOneSkuToAnother, [Parameter(Mandatory = $false)] [switch] $MoveOptionsSourceOptionsToIgnore, [Parameter(Mandatory = $false)] [switch] $MoveOptionsDestOptionsToAdd, [Parameter(Mandatory = $false)] [switch] $TemplateMode, [Parameter(Mandatory = $false)] [switch] $ReportUserLicenses, [Parameter(Mandatory = $false)] [switch] $ReportUserLicensesEnabled, [Parameter(Mandatory = $false)] [switch] $ReportUserLicensesDisabled, [Parameter(Mandatory = $false)] [switch] $DisplayTenantsSkusAndOptions, [Parameter(Mandatory = $false)] [switch] $DisplayTenantsSkusAndOptionsFriendlyNames, [Parameter(Mandatory = $false)] [switch] $DisplayTenantsSkusAndOptionsLookup, [Parameter(Mandatory = $false)] [string[]] $ExternalOptionsToAdd, [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string[]] $UserPrincipalName ) # Begin Block Begin { # Create hashtable from Name to SkuId lookup $skuIdHash = @{ } $licenses = Get-AzureADSubscribedSku $licenses | Select SkuPartNumber, SkuId | ForEach-Object { $skuIdHash[$_.SkuPartNumber] = $_.SkuId } $planId = @{ } foreach ($license in $licenses) { foreach ($row in $($license.ServicePlans)) { $planId[$row.serviceplanId] = $row.serviceplanname } } # Assign Tenant and Location to a variable $tenant = ((Get-AzureADTenantDetail).verifiedDomains | where { $_.initial -eq "$true" }).name.split(".")[0] $location = "US" # Friendly 2 Ugly hashtable Lookups $f2uSku = @{ "Azure Advanced Threat Protection for Users" = "ATA" "Microsoft Cloud App Security" = "ADALLOM_STANDALONE" "AZURE INFORMATION PROTECTION PLAN 1" = "RIGHTSMANAGEMENT" "OFFICE 365 ADVANCED THREAT PROTECTION (PLAN 2)" = "THREAT_INTELLIGENCE" "AX ENTERPRISE USER" = "AX_ENTERPRISE_USER"; "AX SELF-SERVE USER" = "AX_SELF-SERVE_USER"; "AX_SANDBOX_INSTANCE_TIER2" = "AX_SANDBOX_INSTANCE_TIER2"; "AX_TASK_USER" = "AX_TASK_USER"; "Azure Active Directory Premium P1" = "AAD_PREMIUM"; "Azure Active Directory Rights Management" = "RMS_S_ENTERPRISE"; "Azure Rights Management Services Ad-hoc" = "RIGHTSMANAGEMENT_ADHOC"; "Dynamics CRM Online Plan 2" = "CRMPLAN2"; "Enterprise Mobility + Security E3" = "EMS"; "Enterprise Mobility + Security E5" = "EMSPREMIUM"; "ENTERPRISEPACK_B_PILOT" = "ENTERPRISEPACK_B_PILOT"; "Exch Online Plan 2 for Faculty" = "EXCHANGEENTERPRISE_FACULTY"; "Exchange Online (Plan 1)" = "EXCHANGE_L_STANDARD"; "Exchange Online Advanced Threat Protection" = "ATP_ENTERPRISE_FACULTY"; "Exchange Online ATP" = "ATP_ENTERPRISE"; "Exchange Online Plan 1" = "EXCHANGESTANDARD"; "Exchange Online Plan 2 S" = "EXCHANGE_S_ENTERPRISE"; "Exchange Online Plan 2" = "EXCHANGEENTERPRISE"; "Information Rights Management for Faculty" = "RIGHTSMANAGEMENT_STANDARD_FACULTY"; "Information Rights Management for Students" = "RIGHTSMANAGEMENT_STANDARD_STUDENT"; "Intune (Volume License)" = "INTUNE_A_VL"; "Lync Online (Plan 1)" = "MCOLITE"; "Microsoft Dynamics CRM Online Additional Storage" = "CRMSTORAGE"; "Microsoft Flow Free" = "FLOW_FREE"; "Microsoft Imagine Academy" = "IT_ACADEMY_AD"; "Microsoft PowerApps and Logic flows" = "POWERAPPS_INDIVIDUAL_USER"; "Microsoft Stream" = "STREAM"; "MICROSOFT_BUSINESS_CENTER" = "MICROSOFT_BUSINESS_CENTER"; "Minecraft Education Edition Faculty" = "MEE_FACULTY"; "Minecraft Education Edition Student" = "MEE_STUDENT"; "O365 Education E1 for Students" = "STANDARDWOFFPACK_STUDENT"; "O365 Education for Faculty" = "STANDARDWOFFPACK_IW_FACULTY"; "O365 Education for Students" = "STANDARDWOFFPACK_IW_STUDENT"; "Office 365 (Plan A1) for Students" = "STANDARDPACK_STUDENT"; "Office 365 (Plan E3)" = "ENTERPRISEPACKLRG"; "Office 365 Advanced Compliance for faculty" = "EQUIVIO_ANALYTICS_FACULTY"; "Office 365 Education E1 for Faculty" = "STANDARDWOFFPACK_FACULTY"; "Office 365 Education E4 for Faculty" = "ENTERPRISEWITHSCAL_FACULTY"; "Office 365 Education E4 for Students" = "ENTERPRISEWITHSCAL_STUDENT"; "Office 365 Enterprise E1" = "STANDARDPACK"; "Office 365 Enterprise E2" = "STANDARDWOFFPACK"; "Office 365 Enterprise E3 without ProPlus Add-on" = "ENTERPRISEPACKWITHOUTPROPLUS"; "Office 365 Enterprise E3" = "ENTERPRISEPACK"; "Office 365 Enterprise E4" = "ENTERPRISEWITHSCAL"; "Office 365 Enterprise E5" = "ENTERPRISEPREMIUM"; "Office 365 Enterprise K1 with Yammer" = "DESKLESSPACK_YAMMER"; "Office 365 Enterprise K1 without Yammer" = "DESKLESSPACK"; "Office 365 Enterprise K2" = "DESKLESSWOFFPACK"; "Office 365 Midsize Business" = "MIDSIZEPACK"; "Office 365 Plan A2 for Faculty" = "STANDARDWOFFPACKPACK_FACULTY"; "Office 365 Plan A2 for Students" = "STANDARDWOFFPACKPACK_STUDENT"; "Office 365 Plan A3 for Faculty" = "ENTERPRISEPACK_FACULTY"; "Office 365 Plan A3 for Students" = "ENTERPRISEPACK_STUDENT"; "Office 365 ProPlus for Faculty" = "OFFICESUBSCRIPTION_FACULTY"; "Office 365 Small Business Premium" = "LITEPACK_P2"; "Office Online STD" = "WACSHAREPOINTSTD"; "Office Online" = "SHAREPOINTWAC"; "Office ProPlus Student Benefit" = "OFFICESUBSCRIPTION_STUDENT"; "Office ProPlus" = "OFFICE_PRO_PLUS_SUBSCRIPTION_SMBIZ"; "Power BI for Office 365 Individual" = "POWER_BI_INDIVIDUAL_USER"; "Power BI for Office 365 Standalone" = "POWER_BI_STANDALONE"; "Power BI for Office 365 Standard" = "POWER_BI_STANDARD"; "POWER_BI_PRO" = "POWER_BI_PRO"; "Project Lite" = "PROJECTESSENTIALS"; "Project Online for Faculty Plan 1" = "PROJECTONLINE_PLAN_1_FACULTY"; "Project Online for Faculty Plan 2" = "PROJECTONLINE_PLAN_2_FACULTY"; "Project Online for Students Plan 1" = "PROJECTONLINE_PLAN_1_STUDENT"; "Project Online for Students Plan 2" = "PROJECTONLINE_PLAN_2_STUDENT"; "Project Online Premium" = "PROJECTPREMIUM"; "Project Online Professional" = "PROJECTPROFESSIONAL"; "Project Online with Project for Office 365" = "PROJECTONLINE_PLAN_1"; "Project Pro for Office 365" = "PROJECTCLIENT"; "PROJECT_MADEIRA_PREVIEW_IW" = "PROJECT_MADEIRA_PREVIEW_IW_SKU"; "MICROSOFT 365 E3" = "SPE_E3"; "MICROSOFT 365 E5" = "SPE_E5"; "SharePoint Online (Plan 1) Lite" = "SHAREPOINTLITE"; "SharePoint Online (Plan 1) MidMarket" = "SHAREPOINTENTERPRISE_MIDMARKET"; "SharePoint Online (Plan 2)" = "SHAREPOINTENTERPRISE"; "SharePoint Online Plan 1" = "SHAREPOINTSTANDARD"; "STANDARD_B_PILOT" = "STANDARD_B_PILOT"; "STANDARDPACK_FACULTY" = "STANDARDPACK_FACULTY"; "Visio Pro for Office 365" = "VISIOCLIENT"; "Yammer Enterprise" = "YAMMER_ENTERPRISE"; "Yammer Midsize" = "YAMMER_MIDSIZE"; "Microsoft 365 Business" = "SPB" } $f2uOpt = @{ "Flow Free" = "FLOW_P2_VIRAL" "Common Data Service" = "DYN365_CDS_VIRAL" "Azure Advanced Threat Protection" = "ATA" "Azure Active Directory Premium P2" = "AAD_PREMIUM_P2"; "Azure Active Directory Premium Plan 1" = "AAD_PREMIUM"; "Azure Information Protection Plan 1" = "RMS_S_PREMIUM"; "Azure Information Protection Premium P2" = "RMS_S_PREMIUM2"; "Azure Multi-Factor Authentication" = "MFA_PREMIUM"; "Azure Rights Management" = "RMS_S_ENTERPRISE"; "CRM for Partners" = "CRMIUR"; "CRM Online" = "CRMSTANDARD"; "CRM Test Instance" = "CRMTESTINSTANCE"; "Customer Lockbox" = "LOCKBOX_ENTERPRISE"; "Exchange Foundation for certain SKUs" = "EXCHANGE_S_FOUNDATION"; "Exchange Kiosk" = "EXCHANGE_S_DESKLESS_GOV"; "Exchange Online (Plan 1) for Students" = "EXCHANGESTANDARD_STUDENT"; "Exchange Online (Plan 1)" = "EXCHANGE_S_STANDARD_MIDMARKET"; "Exchange Online (Plan 2) Ent" = "EXCHANGE_S_ENTERPRISE"; "Exchange Online (Plan 2)" = "EXCHANGE_S_STANDARD"; "Exchange Online Advanced Threat Protection" = "ATP_ENTERPRISE"; "Exchange Online Archiving Govt" = "EXCHANGE_S_ARCHIVE_ADDON_GOV"; "Exchange Online Archiving" = "EXCHANGEARCHIVE"; "Exchange Online Kiosk" = "EXCHANGE_S_DESKLESS"; "Exchange Online POP" = "EXCHANGETELCO"; "Exchange Online Protection for Faculty" = "EOP_ENTERPRISE_FACULTY"; "Exchange Online Protection" = "EOP_ENTERPRISE"; "Exchange Plan 2G" = "EXCHANGE_S_ENTERPRISE_GOV"; "Flow for Office 365" = "FLOW_O365_P3"; "Flow" = "FLOW_O365_P2"; "Intune for Office 365" = "INTUNE_A"; "Lync Online (Plan 1)" = "MCOSTANDARD_MIDMARKET"; "Lync Online (Plan 3)" = "MCVOICECONF"; "Lync Plan 2G" = "MCOSTANDARD_GOV"; "Microsoft Business Center" = "MICROSOFT_BUSINESS_CENTER"; "Microsoft Cloud App Security" = "ADALLOM_S_STANDALONE"; "Microsoft Dynamics CRM Online Additional Storage" = "CRMSTORAGE"; "Microsoft Dynamics Marketing Sales Collaboration" = "MDM_SALES_COLLABORATION"; "Microsoft Forms (Plan 2)" = "OFFICE_FORMS_PLAN_2"; "Microsoft Forms (Plan E3)" = "FORMS_PLAN_E3"; "Microsoft Forms (Plan E5)" = "FORMS_PLAN_E5"; "Microsoft Imagine Academy" = "IT_ACADEMY_AD"; "Microsoft MyAnalytics" = "EXCHANGE_ANALYTICS"; "Microsoft Office 365 (Plan A1) for Faculty" = "STANDARDPACK_FACULTY"; "Microsoft Office 365 (Plan A1) for Students" = "STANDARDPACK_STUDENT"; "Microsoft Office 365 (Plan A2) for Students" = "STANDARDWOFFPACK_STUDENT"; "Microsoft Office 365 (Plan E1)" = "STANDARDPACK"; "Microsoft Office 365 (Plan E2)" = "STANDARDWOFFPACK"; "Microsoft Office 365 (Plan G1) for Government" = "STANDARDPACK_GOV"; "Microsoft Office 365 (Plan G2) for Government" = "STANDARDWOFFPACK_GOV"; "Microsoft Office 365 (Plan G3) for Government" = "ENTERPRISEPACK_GOV"; "Microsoft Office 365 (Plan G4) for Government" = "ENTERPRISEWITHSCAL_GOV"; "Microsoft Office 365 (Plan K1) for Government" = "DESKLESSPACK_GOV"; "Microsoft Office 365 (Plan K2) for Government" = "DESKLESSWOFFPACK_GOV"; "Microsoft Office 365 Exchange Online (Plan 1) only for Government" = "EXCHANGESTANDARD_GOV"; "Microsoft Office 365 Exchange Online (Plan 2) only for Government" = "EXCHANGEENTERPRISE_GOV"; "Microsoft Planner" = "PROJECTWORKMANAGEMENT"; "Microsoft Social Listening Professional" = "NBPROFESSIONALFORCRM"; "Microsoft StaffHub" = "Deskless"; "Microsoft Stream for O365 E3 SKU" = "STREAM_O365_E3"; "Microsoft Stream for O365 E5 SKU" = "STREAM_O365_E5"; "Microsoft Teams" = "TEAMS1"; "Minecraft Education Edition Faculty" = "MINECRAFT_EDUCATION_EDITION"; "Mobile Device Management for Office 365" = "INTUNE_O365"; "Office 365 (Plan P1)" = "LITEPACK"; "Office 365 Advanced eDiscovery" = "EQUIVIO_ANALYTICS"; "Office 365 Advanced Security Management" = "ADALLOM_S_O365"; "Office 365 Education E1 for Faculty" = "STANDARDWOFFPACK_FACULTY"; "Office 365 Education for Faculty" = "STANDARDWOFFPACK_IW_FACULTY"; "Office 365 Education for Students" = "STANDARDWOFFPACK_IW_STUDENT"; "Office 365 ProPlus" = "OFFICESUBSCRIPTION"; "Office 365 Threat Intelligence" = "THREAT_INTELLIGENCE"; "Office Online for Education" = "SHAREPOINTWAC_EDU"; "Office Online for Government" = "SHAREPOINTWAC_GOV"; "Office Online" = "SHAREPOINTWAC"; "Office ProPlus Student Benefit" = "OFFICESUBSCRIPTION_STUDENT"; "Office ProPlus" = "OFFICESUBSCRIPTION_GOV"; "OneDrive Pack" = "WACONEDRIVESTANDARD"; "OneDrive" = "ONEDRIVESTANDARD"; "Power BI (free)" = "BI_AZURE_P0"; "Power BI Information Services" = "SQL_IS_SSIM"; "Power BI Pro" = "BI_AZURE_P2"; "Power BI Reporting and Analytics" = "BI_AZURE_P1"; "PowerApps for Office 365" = "POWERAPPS_O365_P3"; "PowerApps" = "POWERAPPS_O365_P2"; "Project Lite" = "PROJECT_ESSENTIALS"; "Project Online (Plan 1)" = "PROJECTONLINE_PLAN_1"; "Project Online (Plan 2)" = "PROJECTONLINE_PLAN_2"; "Project Online Service for Education" = "SHAREPOINT_PROJECT_EDU"; "Project Pro for Office 365" = "PROJECT_CLIENT_SUBSCRIPTION"; "School Data Sync (Plan 1)" = "SCHOOL_DATA_SYNC_P1"; "SharePoint Online (Plan 1)" = "SHAREPOINTENTERPRISE_MIDMARKET"; "SharePoint Online (Plan 2) Project" = "SHAREPOINT_PROJECT"; "SharePoint Online (Plan 2)" = "SHAREPOINTENTERPRISE"; "SharePoint Online Kiosk Gov" = "SHAREPOINTDESKLESS_GOV"; "SharePoint Online Kiosk" = "SHAREPOINTDESKLESS"; "SharePoint Online Partner Access" = "SHAREPOINTPARTNER"; "SharePoint Online Storage" = "SHAREPOINTSTORAGE"; "SharePoint Plan 1 for EDU" = "SHAREPOINTSTANDARD_EDU"; "SharePoint Plan 2 for EDU" = "SHAREPOINTENTERPRISE_EDU"; "SharePoint Plan 2G" = "SHAREPOINTENTERPRISE_GOV"; "Skype for Business Cloud PBX" = "MCOEV"; "Skype for Business Online (Plan 2)" = "MCOSTANDARD"; "Skype for Business PSTN Conferencing" = "MCOMEETADV"; "Sway" = "SWAY"; "Visio Pro for Office 365 Subscription" = "VISIO_CLIENT_SUBSCRIPTION"; "Visio Pro for Office 365" = "VISIOCLIENT"; "Windows 10 Enterprise E3" = "WIN10_PRO_ENT_SUB"; "Windows Azure Active Directory Rights Management" = "RMS_S_ENTERPRISE_GOV"; "Yammer Enterprise" = "YAMMER_ENTERPRISE"; "Yammer for Academic" = "YAMMER_EDU"; "Yammer" = "YAMMER_MIDSIZE" } # Based on Runtime switches, Out-GridView(s) are presented for user input if ($RemoveSkus) { [string[]]$skusToRemove = (Get-CloudSku | Out-GridView -Title "SKUs to Remove" -PassThru) } if ($AddSkus) { $skusToAdd = (Get-CloudSku | Out-GridView -Title "SKUs to Add" -PassThru) } if ($RemoveOptions) { [string[]]$optionsToRemove = (Get-CloudSkuTable -all | Out-GridView -Title "Options to Remove" -PassThru) } if ($AddOptions) { [string[]]$optionsToAdd = (Get-CloudSkuTable -all | Out-GridView -Title "Options to Add" -PassThru) } if ($MoveOptionsFromOneSkuToAnother) { $swapSource = (Get-CloudSku | Out-GridView -Title "Swap Sku - SOURCE" -PassThru) $swapDest = (Get-CloudSku | Out-GridView -Title "Swap Sku - DESTINATION" -PassThru) } if ($MoveOptionsSourceOptionsToIgnore) { if ($f2uSku.$swapSource) { [string[]]$sourceIgnore = (Get-CloudSkuTable -sIgnore -sourceSku $f2uSku.$swapSource | Out-GridView -Title "SOURCE Options to Ignore" -PassThru) } else { [string[]]$sourceIgnore = (Get-CloudSkuTable -sIgnore -sourceSku $swapSource | Out-GridView -Title "SOURCE Options to Ignore" -PassThru) } if ($sourceIgnore) { $sourceIgnore = $sourceIgnore | % { if ($f2uOpt[($_).split("*")[1]]) { $f2uOpt[($_).split("*")[1]] } else { ($_).split("*")[1] } } } } if ($MoveOptionsDestOptionsToAdd) { if ($f2uSku.$swapDest) { $destOptAdd = (Get-CloudSkuTable -destAdd -destSku $f2uSku.$swapDest | Out-GridView -Title "DESTINATION Options to add" -PassThru) } else { $destOptAdd = (Get-CloudSkuTable -destAdd -destSku $swapDest | Out-GridView -Title "DESTINATION Options to add" -PassThru) } } if ($TemplateMode) { [string[]]$template = (Get-CloudSkuTable -all | Out-GridView -Title "Create a Template to Apply - All existing Options will be replaced if Sku is selected here" -PassThru) } if ($DisplayTenantsSkusAndOptions) { [string[]]$allSkusOptions = (Get-Sku2Service -ugly | Out-GridView -Title "All Skus and Options") } if ($DisplayTenantsSkusAndOptionsFriendlyNames) { [string[]]$allSkusOptions = (Get-Sku2Service -friendly | Out-GridView -Title "All Skus and Options Friendly Names") } if ($DisplayTenantsSkusAndOptionsLookup) { [string[]]$allSkusOptions = (Get-Sku2Service -both | Out-GridView -Title "All Skus and Options Friendly and Ugly Name Lookup") } } Process { if ($ExternalOptionsToAdd) { $optionsToAdd = $ExternalOptionsToAdd } # Define Arrays $removeSkuGroup = @() $addSkuGroup = @() $addAlreadySkuGroup = @() $enabled = @() $disabled = @() $sKey = @() # Set user-specific variables $user = Get-AzureADUser -ObjectId $_ $userLicense = Get-AzureADUserLicenseDetail -ObjectId $_ Set-AzureADUser -ObjectId $_ -UsageLocation $location # Remove Sku(s) if ($skusToRemove) { Foreach ($removeSku in $skusToRemove) { if ($f2uSku.$removeSku) { if ($f2uSku.$removeSku -in (Get-AzureADUserLicenseDetail -ObjectId $_).skupartnumber) { $removeSkuGroup += $f2uSku.$removeSku } } else { if ($removeSku -in (Get-AzureADUserLicenseDetail -ObjectId $_).skupartnumber) { $removeSkuGroup += $removeSku } } } if ($removeSkuGroup) { Write-Output "$($_) has the following Skus, removing these Sku now: $removeSkuGroup " $licensesToAssign = Set-SkuChange -remove -skus $removeSkuGroup Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign } Else { Write-Output "$($_) does not have any of the Skus requested for removal" } } # Add Sku(s). If user has Sku already, all options will be added if ($skusToAdd) { Foreach ($addSku in $skusToAdd) { if ($f2uSku.$addSku) { if ($f2uSku.$addSku -notin (Get-AzureADUserLicenseDetail -ObjectId $_).skupartnumber) { $addSkuGroup += $f2uSku.$addSku } if ($f2uSku.$addSku -in (Get-AzureADUserLicenseDetail -ObjectId $_).skupartnumber) { $addAlreadySkuGroup += $f2uSku.$addSku } } else { if ($addSku -notin (Get-AzureADUserLicenseDetail -ObjectId $_).skupartnumber) { $addSkuGroup += $addSku } if ($addSku -in (Get-AzureADUserLicenseDetail -ObjectId $_).skupartnumber) { $addAlreadySkuGroup += $addSku } } } # Add fresh Sku(s) if ($addSkuGroup) { Write-Output "$($_) does not have the following Skus, adding these Sku now: $addSkuGroup " $licensesToAssign = Set-SkuChange -add -skus $addSkuGroup Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign } # Backfill already assigned Sku(s) with any missing options if ($addAlreadySkuGroup) { Write-Output "$($_) already has the following Skus, adding any options not currently assigned: $addAlreadySkuGroup " $licensesToAssign = Set-SkuChange -addAlready -skus $addAlreadySkuGroup Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign } } # Remove Options. Only if user is assigned Sku. if ($optionsToRemove) { $hashRem = @{ } for ($i = 0; $i -lt $optionsToRemove.count; $i++) { if ($optionsToRemove[$i]) { if ($f2uSku[$optionsToRemove[$i].split("*")[0]]) { # FRIENDLY SKU TRACT if ($hashRem.containskey($f2uSku[$optionsToRemove[$i].split("*")[0]])) { if ($f2uOpt[$optionsToRemove[$i].split("*")[1]]) { # FRIENDLY SKU -- FRIENDLY OPTION EXISTING $hashRem.($f2uSku[$optionsToRemove[$i].split("*")[0]]) += @($f2uOpt[$optionsToRemove[$i].split("*")[1]]) } else { # FRIENDLY SKU -- UGLY OPTION EXISTING $hashRem.($f2uSku[$optionsToRemove[$i].split("*")[0]]) += @($optionsToRemove[$i].split("*")[1]) } } else { if ($f2uOpt[$optionsToRemove[$i].split("*")[1]]) { # FRIENDLY SKU -- FRIENDLY OPTION FRESH! $hashRem.($f2uSku[$optionsToRemove[$i].split("*")[0]]) = @($f2uOpt[$optionsToRemove[$i].split("*")[1]]) } else { # FRIENDLY SKU -- UGLY OPTION FRESH! $hashRem.($f2uSku[$optionsToRemove[$i].split("*")[0]]) = @($optionsToRemove[$i].split("*")[1]) } } } # UGLY SKU TRACT else { if ($hashRem.containskey($optionsToRemove[$i].split("*")[0])) { if ($f2uOpt[$optionsToRemove[$i].split("*")[1]]) { # UGLY SKU -- FRIENDLY OPTION EXISTING $hashRem.($optionsToRemove[$i].split("*")[0]) += @($f2uOpt[$optionsToRemove[$i].split("*")[1]]) } else { # UGLY SKU -- UGLY OPTION EXISTING $hashRem.($optionsToRemove[$i].split("*")[0]) += @($optionsToRemove[$i].split("*")[1]) } } else { if ($f2uOpt[$optionsToRemove[$i].split("*")[1]]) { # UGLY SKU -- FRIENDLY OPTION FRESH! $hashRem.($optionsToRemove[$i].split("*")[0]) = @($f2uOpt[$optionsToRemove[$i].split("*")[1]]) } else { # UGLY SKU -- UGLY OPTION FRESH! $hashRem.($optionsToRemove[$i].split("*")[0]) = @($optionsToRemove[$i].split("*")[1]) } } } } } $hashRem.GetEnumerator() | ForEach-Object { Write-Output "$($user.UserPrincipalName) : $($_.key) : $($_.value) " # User already has Sku $sKey = $_.key if ($sKey -in $userLicense.skupartnumber) { $disabled = $_.Value + ((($userLicense | Where { $_.skupartnumber -contains $sKey }).serviceplans | where { $_.provisioningStatus -eq 'Disabled' }).serviceplanname) $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -removeTheOptions -skus $sKey -options $disabled Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign Write-Output "Options from Sku: $sKey to remove + options currently disabled: $disabled " $completed = $true } Catch { $_.exception.Message -match "\bplan\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $disabled += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "$($user.UserPrincipalName) unable to remove options to Sku: $sKey " } } # User does not have Sku so do nothing else { Write-Output "User does not have SKU $sKey, no options to remove" } } } # Add Option(s). User will be assigned Sku with the options if user has yet to have Sku assigned if ($optionsToAdd -or $ExternalOptionsToAdd) { $hashAdd = @{ } for ($i = 0; $i -lt $optionsToAdd.count; $i++) { if ($optionsToAdd[$i]) { if ($f2uSku[$optionsToAdd[$i].split("*")[0]]) { # FRIENDLY SKU TRACT if ($hashAdd.containskey($f2uSku[$optionsToAdd[$i].split("*")[0]])) { if ($f2uOpt[$optionsToAdd[$i].split("*")[1]]) { # FRIENDLY SKU -- FRIENDLY OPTION EXISTING $hashAdd.($f2uSku[$optionsToAdd[$i].split("*")[0]]) += @($f2uOpt[$optionsToAdd[$i].split("*")[1]]) } else { # FRIENDLY SKU -- UGLY OPTION EXISTING $hashAdd.($f2uSku[$optionsToAdd[$i].split("*")[0]]) += @($optionsToAdd[$i].split("*")[1]) } } else { if ($f2uOpt[$optionsToAdd[$i].split("*")[1]]) { # FRIENDLY SKU -- FRIENDLY OPTION FRESH! $hashAdd.($f2uSku[$optionsToAdd[$i].split("*")[0]]) = @($f2uOpt[$optionsToAdd[$i].split("*")[1]]) } else { # FRIENDLY SKU -- UGLY OPTION FRESH! $hashAdd.($f2uSku[$optionsToAdd[$i].split("*")[0]]) = @($optionsToAdd[$i].split("*")[1]) } } } # UGLY SKU TRACT else { if ($hashAdd.containskey($optionsToAdd[$i].split("*")[0])) { if ($f2uOpt[$optionsToAdd[$i].split("*")[1]]) { # UGLY SKU -- FRIENDLY OPTION EXISTING $hashAdd.($optionsToAdd[$i].split("*")[0]) += @($f2uOpt[$optionsToAdd[$i].split("*")[1]]) } else { # UGLY SKU -- UGLY OPTION EXISTING $hashAdd.($optionsToAdd[$i].split("*")[0]) += @($optionsToAdd[$i].split("*")[1]) } } else { if ($f2uOpt[$optionsToAdd[$i].split("*")[1]]) { # UGLY SKU -- FRIENDLY OPTION FRESH! $hashAdd.($optionsToAdd[$i].split("*")[0]) = @($f2uOpt[$optionsToAdd[$i].split("*")[1]]) } else { # UGLY SKU -- UGLY OPTION FRESH! $hashAdd.($optionsToAdd[$i].split("*")[0]) = @($optionsToAdd[$i].split("*")[1]) } } } } } $hashAdd.GetEnumerator() | ForEach-Object { Write-Output "$($user.UserPrincipalName) : $($_.key) : $($_.value) " # User already has Sku $sKey = $_.key if ($sKey -in $userLicense.skupartnumber) { $enabled = [pscustomobject]$_.Value + ((($userLicense | Where { $_.skupartnumber -contains $sKey }).serviceplans | Where { $_.provisioningstatus -ne 'Disabled' }).serviceplanname) $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $sKey -options $enabled Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop Write-Output "Options from Sku: $sKey to add + options currently enabled: $enabled " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $enabled += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "$($user.UserPrincipalName) unable to apply options to Sku: $sKey " } } # User does not have Sku yet else { $enabled = [pscustomobject]$_.Value $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $sKey -options $enabled Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop Write-Output "User does not have SKU: $sKey, adding Sku with options: $enabled " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $enabled += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "$($user.UserPrincipalName) unable to apply options to Sku: $sKey " } } } } if ($MoveOptionsFromOneSkuToAnother) { if (($userLicense.skupartnumber.Contains($swapSource)) -or ($userLicense.skupartnumber.Contains($f2uSku.$swapSource))) { if (($f2uSku.$swapDest) -and ($f2uSku.$swapSource)) { if (($f2uSku.$swapDest) -eq ($f2uSku.$swapSource)) { Write-Output "Source and Destination Skus are identical" Write-Output "Source Sku: $($f2uSku.$swapSource) and Destination Sku: $($f2uSku.$swapDest) are identical." Write-Output "Please choose a different Source or Destination Sku" Break } (Get-AzureADSubscribedSku | Where { $_.skupartnumber -eq $f2uSku.$swapDest }) | ForEach-Object { if (($_.prepaidunits.enabled - $_.consumedunits) -lt "1") { Write-Output "Out of $($f2uSku.$swapDest) licenses. Please allocate more then rerun." Break } $dest = $_.serviceplans.serviceplanname $source = ((Get-AzureADUserLicenseDetail -ObjectId $user.UserPrincipalName | Where { $_.skupartnumber -eq $f2uSku.$swapSource }).serviceplans | Where { $_.provisioningstatus -ne 'Disabled' }).serviceplanname if ($source) { $source = $source | Where { $sourceIgnore -notcontains $_ } } $destarray = Get-UniqueString $dest $sourcearray = Get-UniqueString $source $options2swap = $sourcearray.keys | Where { $destarray.keys -contains $_ } $options2swap = $options2swap | % { $destarray[$_] } if ($destOptAdd) { $doa = $destOptAdd | % { if ($f2uOpt[($_).split("*")[1]]) { $f2uOpt[($_).split("*")[1]] } else { ($_).split("*")[1] } } $options2swap += $doa } $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $f2uSku.$swapDest -options $options2swap Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop $licensesToAssign = Set-SkuChange -remove -skus $f2uSku.$swapSource Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign Write-Output "$($user.UserPrincipalName) Source: $($f2uSku.$swapSource) Dest: $($f2uSku.$swapDest) Moved Options: $options2swap " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $options2swap += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "Unable to properly add some or all of Options for destination Sku: $($f2uSku.$swapDest) Did not remove Sku: $($f2uSku.$swapSource) " Write-Output "FAILED: $($user.UserPrincipalName) Source: $($f2uSku.$swapSource) Dest: $($f2uSku.$swapDest) Options: $options2swap " } } } if ((!($f2uSku.$swapDest)) -and ($f2uSku.$swapSource)) { if (($swapDest) -eq ($f2uSku.$swapSource)) { Write-Output "Source and Destination Skus are identical" Write-Output "Source Sku: $($f2uSku.$swapSource) and Destination Sku: $($swapDest) are identical." Write-Output "Please choose a different Source or Destination Sku" Break } (Get-AzureADSubscribedSku | Where { $_.skupartnumber -eq $swapDest }) | ForEach-Object { if (($_.prepaidunits.enabled - $_.consumedunits) -lt "1") { Write-Output "Out of $swapDest licenses. Please allocate more then rerun." Break } $dest = $_.serviceplans.serviceplanname $source = ((Get-AzureADUserLicenseDetail -ObjectId $user.UserPrincipalName | Where { $_.skupartnumber -eq $f2uSku.$swapSource }).serviceplans | Where { $_.provisioningstatus -ne 'Disabled' }).serviceplanname if ($source) { $source = $source | Where { $sourceIgnore -notcontains $_ } } $destarray = Get-UniqueString $dest $sourcearray = Get-UniqueString $source $options2swap = $sourcearray.keys | Where { $destarray.keys -contains $_ } $options2swap = $options2swap | % { $destarray[$_] } if ($destOptAdd) { $doa = $destOptAdd | % { if ($f2uOpt[($_).split("*")[1]]) { $f2uOpt[($_).split("*")[1]] } else { ($_).split("*")[1] } } $options2swap += $doa } $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $swapDest -options $options2swap Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop $licensesToAssign = Set-SkuChange -remove -skus $f2uSku.$swapSource Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign Write-Output "$($user.UserPrincipalName) Source: $($f2uSku.$swapSource) Dest: $swapDest Moved Options: $options2swap " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $options2swap += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "Unable to properly add some or all of Options for destination Sku: $swapDest Did not remove Sku: $($f2uSku.$swapSource) " Write-Output "FAILED: $($user.UserPrincipalName) Source: $($f2uSku.$swapSource) Dest: $swapDest Options: $options2swap " } } } if (($f2uSku.$swapDest) -and (!($f2uSku.$swapSource))) { if (($f2uSku.$swapDest) -eq ($swapSource)) { Write-Output "Source and Destination Skus are identical" Write-Output "Source Sku: $swapSource and Destination Sku: $($f2uSku.$swapDest) are identical." Write-Output "Please choose a different Source or Destination Sku" Break } (Get-AzureADSubscribedSku | Where { $_.skupartnumber -eq $f2uSku.$swapDest }) | ForEach-Object { if (($_.prepaidunits.enabled - $_.consumedunits) -lt "1") { Write-Output "Out of $($f2uSku.$swapDest) licenses. Please allocate more then rerun." Break } $dest = $_.serviceplans.serviceplanname $source = ((Get-AzureADUserLicenseDetail -ObjectId $user.UserPrincipalName | Where { $_.skupartnumber -eq $swapSource }).serviceplans | Where { $_.provisioningstatus -ne 'Disabled' }).serviceplanname if ($source) { $source = $source | Where { $sourceIgnore -notcontains $_ } } $destarray = Get-UniqueString $dest $sourcearray = Get-UniqueString $source $options2swap = $sourcearray.keys | Where { $destarray.keys -contains $_ } $options2swap = $options2swap | % { $destarray[$_] } if ($destOptAdd) { $doa = $destOptAdd | % { if ($f2uOpt[($_).split("*")[1]]) { $f2uOpt[($_).split("*")[1]] } else { ($_).split("*")[1] } } $options2swap += $doa } $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $f2uSku.$swapDest -options $options2swap Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop $licensesToAssign = Set-SkuChange -remove -skus $swapSource Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign Write-Output "$($user.UserPrincipalName) Source: $swapSource Dest: $($f2uSku.$swapDest) Moved Options: $options2swap " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $options2swap += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "Unable to properly add some or all of Options for destination Sku: $($f2uSku.$swapDest) Did not remove Sku: $swapSource " Write-Output "FAILED: $($user.UserPrincipalName) Source: $swapSource Dest: $($f2uSku.$swapDest) Options: $options2swap " } } } if ((!($f2uSku.$swapDest)) -and (!($f2uSku.$swapSource))) { if (($swapDest) -eq ($swapSource)) { Write-Output "Source and Destination Skus are identical" Write-Output "Source Sku: $swapSource and Destination Sku: $swapDest are identical." Write-Output "Please choose a different Source or Destination Sku" Break } (Get-AzureADSubscribedSku | Where { $_.skupartnumber -eq $swapDest }) | ForEach-Object { if (($_.prepaidunits.enabled - $_.consumedunits) -lt "1") { Write-Output "Out of $swapDest licenses. Please allocate more then rerun." Break } $dest = $_.serviceplans.serviceplanname $source = ((Get-AzureADUserLicenseDetail -ObjectId $user.UserPrincipalName | Where { $_.skupartnumber -eq $swapSource }).serviceplans | Where { $_.provisioningstatus -ne 'Disabled' }).serviceplanname if ($source) { $source = $source | Where { $sourceIgnore -notcontains $_ } } $destarray = Get-UniqueString $dest $sourcearray = Get-UniqueString $source $options2swap = $sourcearray.keys | Where { $destarray.keys -contains $_ } $options2swap = $options2swap | % { $destarray[$_] } if ($destOptAdd) { $doa = $destOptAdd | % { if ($f2uOpt[($_).split("*")[1]]) { $f2uOpt[($_).split("*")[1]] } else { ($_).split("*")[1] } } $options2swap += $doa } $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $swapDest -options $options2swap Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop $licensesToAssign = Set-SkuChange -remove -skus $swapSource Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign Write-Output "$($user.UserPrincipalName) Source: $swapSource Dest: $swapDest Moved Options: $options2swap " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $options2swap += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "Unable to properly add some or all of Options for destination Sku: $swapDest Did not remove Sku: $swapSource " Write-Output "FAILED: $($user.UserPrincipalName) Source: $swapSource Dest: $swapDest Options: $options2swap " } } } } else { Write-Output "$($user.UserPrincipalName) does not have source Sku: $($f2uSku.$swapSource), no changes will be made to this user" } } # Template mode - applies options to any Skus used in this template - will not respect existing Options (wipes them out) if ($template) { $hashTemplate = @{ } for ($i = 0; $i -lt $template.count; $i++) { if ($template[$i]) { if ($f2uSku[$template[$i].split("*")[0]]) { # FRIENDLY SKU TRACT if ($hashTemplate.containskey($f2uSku[$template[$i].split("*")[0]])) { if ($f2uOpt[$template[$i].split("*")[1]]) { # FRIENDLY SKU -- FRIENDLY OPTION EXISTING $hashTemplate.($f2uSku[$template[$i].split("*")[0]]) += @($f2uOpt[$template[$i].split("*")[1]]) } else { # FRIENDLY SKU -- UGLY OPTION EXISTING $hashTemplate.($f2uSku[$template[$i].split("*")[0]]) += @($template[$i].split("*")[1]) } } else { if ($f2uOpt[$template[$i].split("*")[1]]) { # FRIENDLY SKU -- FRIENDLY OPTION FRESH! $hashTemplate.($f2uSku[$template[$i].split("*")[0]]) = @($f2uOpt[$template[$i].split("*")[1]]) } else { # FRIENDLY SKU -- UGLY OPTION FRESH! $hashTemplate.($f2uSku[$template[$i].split("*")[0]]) = @($template[$i].split("*")[1]) } } } # UGLY SKU TRACT else { if ($hashTemplate.containskey($template[$i].split("*")[0])) { if ($f2uOpt[$template[$i].split("*")[1]]) { # UGLY SKU -- FRIENDLY OPTION EXISTING $hashTemplate.($template[$i].split("*")[0]) += @($f2uOpt[$template[$i].split("*")[1]]) } else { # UGLY SKU -- UGLY OPTION EXISTING $hashTemplate.($template[$i].split("*")[0]) += @($template[$i].split("*")[1]) } } else { if ($f2uOpt[$template[$i].split("*")[1]]) { # UGLY SKU -- FRIENDLY OPTION FRESH! $hashTemplate.($template[$i].split("*")[0]) = @($f2uOpt[$template[$i].split("*")[1]]) } else { # UGLY SKU -- UGLY OPTION FRESH! $hashTemplate.($template[$i].split("*")[0]) = @($template[$i].split("*")[1]) } } } } } $hashTemplate.GetEnumerator() | ForEach-Object { Write-Output "$($user.UserPrincipalName) : $($_.key) : $($_.value) " # User already has Sku $sKey = $_.key if ($sKey -in $userLicense.skupartnumber) { $enabled = [pscustomobject]$_.Value $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $sKey -options $enabled Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop Write-Output "User has Sku $sKey all options will be disabled except: $enabled " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $enabled += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "$($user.UserPrincipalName) unable to apply options to Sku: $sKey " } } # User does not have Sku yet else { $enabled = [pscustomobject]$_.Value $completed = $false $retry = 0 While ((! $completed) -and ($retry -le 5)) { Try { $retry++ $licensesToAssign = Set-SkuChange -addTheOptions -skus $sKey -options $enabled Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $licensesToAssign -ErrorAction Stop Write-Output "User does not have SKU: $sKey, adding Sku with options: $enabled " $completed = $true } Catch { $_.exception.Message -match "\bplan\(s\)\s+([-0-9a-f]{36})" | Out-Null $matches[1] -split (' ') | % { $enabled += ($planId[($_).trim()]) } } } if (! $completed) { Write-Output "$($user.UserPrincipalName) unable to apply options to Sku: $sKey " } } } } if ($ReportUserLicenses) { (Get-UserLicense -allLicenses -usr $_ | Out-GridView -Title "User License Summary $($_)") } if ($ReportUserLicensesEnabled) { (Get-UserLicense -notDisabled -usr $_ | Out-GridView -Title "User License Summary $($_)") } if ($ReportUserLicensesDisabled) { (Get-UserLicense -onlyDisabled -usr $_ | Out-GridView -Title "User License Summary $($_)") } } End { } } |