ManageGroupLicense.ps1
function PrintTree($printNode,$rootNodeName) { $returnArray=@() foreach ($node in $printNode) { out-logfile -string $rootNodeName out-logfile -string $node.text if ($node.checked) { out-logfile -string "IsChecked:TRUE" } else { out-logfile -string "IsChecked:FALSE" } $functionObject = New-Object PSObject -Property @{ SkuPartNumber = $rootNodeName SkuPartNumber_ServicePlanName = ($rootNodeName+"_"+$node.text) ServicePlanName = $node.text EnabledNew = $node.checked } $returnArray += $functionObject } return $returnArray } function CheckAllChildNodes($treeNode, $nodeChecked){ foreach($node in $treeNode.Nodes){ $node.Checked = $nodeChecked if($node.Nodes.Count -gt 0){ CheckAllChildNodes $node $nodeChecked } } } function ManageGroupLicense { $planArray = @() $global:fakePlanID = "00000000-0000-0000-0000-000000000000" out-logfile -string "Entered manage group license..." #**************************************************************************************************************************** $commit_Click = { $ToolLabel.Text = "Beginning license commit operation..." $global:telemetryCommits++ out-logfile -string "It is time to commit the changes that were made." $ToolLabel.Text = "Pulling all user defined options from the license tree - this may take a minute..." foreach ($rootNode in $licenseList.Nodes) { out-logfile -string $rootNode.Text $planArray +=PrintTree $rootNode.nodes $rootNode.text } $ToolLabel.Text = "Comparing previous license state to user defined license state - this may take a minute..." foreach ($sku in $global:skuTracking) { out-logfile -string ("Evaluting Sku: "+$sku.SkuPartNumber_ServicePlanName) if ($planArray.SkuPartNumber_ServicePlanName.contains($sku.SkuPartNumber_ServicePlanName)) { out-logfile -string "SKU located within the plan tree - this was expected." $planUpdate = $planArray | where {$_.SkuPartNumber_ServicePlanName -eq $sku.SkuPartNumber_ServicePlanName} out-logfile -string $planUpdate $sku.enabledNew = $planUpdate.EnabledNew out-logfile -string $sku } } out-xmlFile -itemToExport $global:skuTracking -itemNameToExport ("GlobalSKUTrackingPostUpdate-"+(Get-Date -Format FileDateTime)) $skusToRemove=@() $licenseParams = @{} $skusToAdd=@() $ToolLabel.Text = "Evaluating for existing skus with plan changes..." out-logfile -string "Searching for changes to existing skus." foreach ($id in $global:skuRootIDPresent) { out-logfile -string ('Evaluating ID: '+$id) $skusToAddHash=@{} $disabledPlans=@() $addTest=@() $addTestEnabled=@() $addTestDisabled=@() $addTest += $global:skuTracking | where {$_.skuID -eq $id} $addTestEnabled += $global:skuTracking | where {($_.skuID -eq $id) -and ($_.enabledNew -eq $true)} $addTestDisabled += $global:skuTracking | where {($_.skuID -eq $id) -and ($_.enabledNew -eq $false)} out-logfile -string ("Count of all found skus: "+$addTest.count.tostring()) out-logfile -string ("Count of all found skus enabled: "+$addTestEnabled.count.tostring()) out-logfile -string ("Count of all found skus disabled: "+$addTestDisabled.count.tostring()) if (($addTestEnabled.count -gt 0) -and ($id -ne $global:fakePlanID)) { out-logfile -string "The sku is present - updating disalbed plans." foreach ($sku in $addTestDisabled) { out-logfile -string "Building disabled IDs" out-logfile -string $sku.ServicePlanID $disabledPlans+=$sku.ServicePlanID } $skusToAddHash.add("DisabledPlans",$disabledPlans) $skusToAddHash.add("SkuID",$id) $skusToAdd+=$skusToAddHash } else { out-logfile -string "The sku was not modified partially." } } $ToolLabel.Text = "Evaluating for SKUs entirely removed..." out-logfile -string "Begin to look for skus that have been removed..." foreach ($id in $global:skuRootIDPresent) { $removeTest=@() $removeTestDisabled=@() out-logfile -string ('Evaluating ID: '+$id) $removeTest += $global:skuTracking | where {$_.skuID -eq $id} $removeTestDisabled += $global:skuTracking | where {($_.skuID -eq $id) -and ($_.enabledNew -eq $false)} out-logfile -string ("The number of skus to test for removal: "+$removeTest.count.tostring()) out-logfile -string ("The number of skus to test with plans removed: "+$removeTestDisabled.count.toString()) if (($removeTest.count -eq $removeTestDisabled.count) -and ($id -ne $global:fakePlanID)) { out-logfile -string "The number of sku references equals number of plans disalbed -> remove sku." out-logfile -string $id $skusToRemove += $id out-logfile -string "Remove the entry from the active array - it's no longer active." $global:skuRootIDPresent = $global:skuRootIDPresent | where {$_ -ne $id} $global:skuRootIDNotPresent += $id } else { out-logfile -string "The SKU is not a SKU that was entirely removed." } } $ToolLabel.Text = "Evaluating for SKUs entirely added..." out-logfile -string "Determine if any entire skus were added to the new license template by reviewing skus that were not already there." foreach ($id in $global:skuRootIDNotPresent) { out-logfile -string ('Evaluating ID: '+$id) $skusToAddHash=@{} $disabledPlans=@() $addTest=@() $addTestEnabled=@() $addTest += $global:skuTracking | where {$_.skuID -eq $id} $addTestEnabled += $global:skuTracking | where {($_.skuID -eq $id) -and ($_.enabledNew -eq $true)} out-logfile -string ("Count of all found skus: "+$addTest.count.tostring()) out-logfile -string ("Count of all found skus enabled: "+$addTestEnabled.count.tostring()) if (($addTest.count -eq $addTestEnabled.count) -and ($id -ne $global:fakePlanID)) { out-logfile -string "The number of sku references and plan references are equal -> the entire sku was added" out-logfile -string $id $skusToAddHash.add("DisabledPlans",$disabledPlans) $skusToAddHash.add("SkuID",$id) $skusToAdd+=$skusToAddHash out-logfile -string "Remove from the IDs not present - it is now present." $global:skuRootIDNotPresent = $global:skuRootIDNotPresent | where {$_ -ne $id} $global:skuRootIDPresent += $id } else { out-logfile -string "The SKU was not a SKU that was entirely added." } } $ToolLabel.Text = "Evaluating SKUs for partial additions..." out-logfile -string "Searching for new skus that were partially added." foreach ($id in $global:skuRootIDNotPresent) { out-logfile -string ('Evaluating ID: '+$id) $skusToAddHash=@{} $disabledPlans=@() $addTest=@() $addTestEnabled=@() $addTestDisabled=@() $addTest += $global:skuTracking | where {$_.skuID -eq $id} $addTestEnabled += $global:skuTracking | where {($_.skuID -eq $id) -and ($_.enabledNew -eq $true)} $addTestDisabled += $global:skuTracking | where {($_.skuID -eq $id) -and ($_.enabledNew -eq $false)} out-logfile -string ("Count of all found skus: "+$addTest.count.tostring()) out-logfile -string ("Count of all found skus enabled: "+$addTestEnabled.count.tostring()) out-logfile -string ("Count of all found skus disabled: "+$addTestDisabled.count.tostring()) if (($addTestEnabled.count -gt 0) -and ($addTestDisabled.count -gt 0) -and ($id -ne $global:fakePlanID)) { out-logfile -string "The sku was added but only partially added." foreach ($sku in $addTestDisabled) { out-logfile -string "Building disabled IDS" out-logfile -string $sku.ServicePlanID $disabledPlans+=$sku.ServicePlanID } $skusToAddHash.add("DisabledPlans",$disabledPlans) $skusToAddHash.add("SkuID",$id) $skusToAdd+=$skusToAddHash $global:skuRootIDNotPresent = $global:skuRootIDNotPresent | where {$_ -ne $id} $global:skuRootIDPresent += $id } else { out-logfile -string "The sku was not added even partially." } } $licenseParams.add("AddLicenses",$skusToAdd) $licenseParams.add("RemoveLicenses",$skusToRemove) out-xmlFile -itemToExport $licenseParams -itemNameToExport ("LicenseParams-"+(Get-Date -Format FileDateTime)) try { $ToolLabel.Text = "Applying the new license template to the group..." Set-MgGroupLicense -GroupId $global:groupID -BodyParameter $licenseParams -errorAction Stop $ToolLabel.Text = "License template successfully applied..." [System.Windows.Forms.MessageBox]::Show("LICENSE COMMIT SUCCESSFUL - RUN SEARCH TO REFRESH", 'SUCCESS') } catch { out-logfile -string "Error adjusting licenses on group." $errorText = $_ out-logfile -string $errorText $errorText = ($errorText -split 'Status: 400')[0] $global:errorMessages+=$errorText $ToolLabel.Text = "ERROR: License template NOT successfully applied..." [System.Windows.Forms.MessageBox]::Show("Unable to adjust the licenses on the group: "+$errorText, 'Warning') $global:telemetryCommitErrors++ } } #**************************************************************************************************************************** $exit_Click = { $form2.close() } #**************************************************************************************************************************** $Button1_Click = { $ToolLabel.Text = "Entering Group Search" $global:telemetrySearches++ $global:skuTracking = @() $global:skuRootIDPresent = @() $global:skuRootIDNotPresent = @() out-logfile -string "Search button selected..." out-logfile -string "Clearing all form controls..." $ToolLabel.Text = "Resetting Display Dialogs" $displayNameText.clear() $expirationDateTimeText.clear() $mailText.clear() $groupTypeText.clear() $membershipRuleText.clear() $GroupMembersView.rows.clear() $licenseList.beginUpdate() $licenseList.Nodes.Clear() $licenseList.endUpdate() $ToolLabel.Text = "Obtaining Group ID" $global:groupID = $groupObjectIDText.Text Out-logfile -string "Group ID to Search:" out-logfile -string $global:groupID $getGroupFailure = $FALSE try { out-logfile -string "Attempt to locate the group via groupID..." $graphGroup = get-MGGroup -groupID $global:groupID -errorAction STOP out-logfile -string "Group was successfully located..." out-logfile -string $graphGroup $getGroupFailure=$false out-xmlFile -itemToExport $graphGroup -itemNameToExport ("GraphGroup-"+(Get-Date -Format FileDateTime)) $ToolLabel.Text = "GET-MGGroup Successful" } catch { $getGroupFailure=$true $errorText=$_ out-logfile -string "The group was not located by group object id.." out-logfile -string $errorText $errorText = ($errorText -split 'Status: 400')[0] $global:errorMessages+=$errorText $ToolLabel.Text = "GET-MGGroup ERROR" [System.Windows.Forms.MessageBox]::Show("The group was not located by group object id.."+$errorText, 'Warning') $global:telemetrySearcheErrors++ } if ($getGroupFailure -eq $FALSE) { try { out-logfile -string "Attempt to obtain assigned licenses on the group by groupID..." $graphGroupLicenses = get-MGGroup -groupID $global:groupID -property "AssignedLicenses" -errorAction STOP out-logfile -string "Group and licenses were successfully located..." out-xmlFile -itemToExport $graphGroupLicenses -itemNameToExport ("GraphGroupLicense-"+(Get-Date -Format FileDateTime)) $ToolLabel.Text = "Get Group Licenses Successful" } catch { $getGroupFailure=$true $errorText=$_ out-logfile -string "The group was not located by group object id.." out-logfile -string $errorText $errorText = ($errorText -split 'Status: 400')[0] $global:errorMessages+=$errorText $ToolLabel.Text = "Get Group Licenses ERROR" [System.Windows.Forms.MessageBox]::Show("The group was not located by group object id.."+$errorText, 'Warning') $global:telemetrySearcheErrors++ } } if ($getGroupFailure -eq $FALSE) { out-logfile -string "Previous operations were successfuly - determine all skus within the tenant..." try { $skus = Get-MgSubscribedSku -errorAction Stop out-logfile -string "SKUs successfully obtained..." $getGroupFailure=$false out-xmlFile -itemToExport $skus -itemNameToExport ("GraphSKUS-"+(Get-Date -Format FileDateTime)) $ToolLabel.Text = "Get-MGSubscribedSKU SUCESSFUL" } catch { $getGroupFailure=$true $errorText=$_ out-logfile -string "Unable to obtain the skus within the tenant.." out-logfile -string $errorText $errorText = ($errorText -split 'Status: 400')[0] $global:errorMessages+=$errorText $ToolLabel.Text = "Get-MGSubscribedSKU ERROR" [System.Windows.Forms.MessageBox]::Show("Unable to obtain the skus within the tenant.."+$errorText, 'Warning') $global:telemetrySearcheErrors++ } out-logfile -string "Removing all non-user SKUs" $skus = $skus | where {$_.appliesTo -eq "User"} out-xmlFile -itemToExport $skus -itemNameToExport ("GraphSKUSUserOnly-"+(Get-Date -Format FileDateTime)) out-logfile -string "Build the custom powershell object for each of the sku / plan combinations that could be enabled." $ToolLabel.Text = "Enumerating all SKUs and SKU-Plans in tenant..." foreach ($sku in $skus) { out-logfile -string ("Evaluating Sku: "+$sku.skuPartNumber) foreach ($servicePlan in $sku.ServicePlans) { out-logfile -string ("Evaluating Service Plan: "+$servicePlan.ServicePlanName) if ($servicePlan.AppliesTo -eq "User") { out-logfile -string "Service plan is per user - creating object." $functionObject = New-Object PSObject -Property @{ SkuID = $sku.SkuId SkuPartNumber = $sku.SkuPartNumber SkuPartNumber_ServicePlanName = $sku.SkuPartNumber+"_"+$servicePlan.ServicePlanName ServicePlanID = $servicePlan.ServicePlanId ServicePlanName = $servicePlan.ServicePlanName EnabledOnGroup = $false EnabledNew = $false } $global:skuTracking += $functionObject } } } out-xmlFile -itemToExport $global:skuTracking -itemNameToExport ("SkuTracking-"+(Get-Date -Format FileDateTime)) $ToolLabel.Text = "Comparing SKU and SKU-Plan assignments on group to tenant SKU / SKU-Plans" out-logfile -string "Evaluating the skus in the tenant against the group provided." if ($graphGroupLicenses.assignedLicenses.count -gt 0) { out-logfile -string "The group specified has licenses - being the evaluation." foreach ($skuObject in $global:skuTracking) { out-logfile -string "Checking to see if the group has the SKU id..." if ($graphGroupLicenses.AssignedLicenses.SkuID.contains($skuObject.skuID)) { out-logfile -string "The group licenses the sku id - check disabled plans..." $workingLicense = $graphGroupLicenses.assignedLicenses | where {$_.skuID -eq $skuObject.skuID} out-logfile -string ("Evaluating the following sku ID on the group: "+$workingLicense.skuID) if ($workingLicense.disabledPlans.contains($skuObject.ServicePlanID)) { out-logfile -string "The plan is disabled - no work." } else { out-logfile -string "The sku is not disabled - set the SKU to enabled." $skuObject.EnabledOnGroup = $TRUE } } } } out-xmlFile -itemToExport $global:skuTracking -itemNameToExport ("SkuTrackingGroupEvaluation-"+(Get-Date -Format FileDateTime)) } if ($getGroupFailure -eq $false) { $ToolLabel.Text = "Updating form controls with group and license information..." out-logfile -string "Displaying all relevant form controls..." $displayName.show() $expirationDateTime.Show() $mail.show() $groupTypes.show() $membershipRule.show() $displayNameText.show() $expirationDateTimeText.show() $mailText.show() $groupTypeText.show() $membershipRuleText.show() $displayNameText.appendtext($graphGroup.displayName) $expirationDateTimeText.appendTExt($graphGroup.ExpirationDateTime) $mailText.appendtext($graphGroup.mail) $membershipRuleText.appendtext($graphGroup.membershipRule) $groupTypeText.appendtext($graphGroup.GroupTypes) if ($graphGroup.displayName.Length -gt 0) { out-logfile -string $graphGroup.displayName } if ($graphGroup.ExpirationDateTime.Length -gt 0) { out-logfile -string $graphGroup.ExpirationDateTime } if ($graphGroup.mail.Length -gt 0) { out-logfile -string $graphGroup.mail } if ($graphGroup.membershipRule.Length -gt 0) { out-logfile -string $graphGroup.membershipRule } if ($graphGroup.GroupTypes.Length -gt 0) { out-logfile -string $graphGroup.GroupTypes } } else { out-logfile -string "Relevant form controls not displayed due to previous failure." } <# if ($getGroupFailure -eq $false) { out-logfile -string "Previous operation was successful proceed with locating membership." try { $groupMembers = get-mgGroupMember -groupID $global:groupID -all -errorAction STOP $getGroupFailure=$false } catch { $getGroupFailure=$true $errorText=$_ out-logfile -string "The group was not located by group object id.." out-logfile -string $errorText [System.Windows.Forms.MessageBox]::Show("The group was not located by group object id.."+$errorText, 'Warning') } out-xmlFile -itemToExport $groupMembers -itemNameToExport ("GroupMembers-"+(Get-Date -Format FileDateTime)) out-logfile -string "Showing relelvant group member controls..." $GroupMembersName.Show() $GroupMembersView.show() out-logfile -string "Showing relevant group member information..." $groupMembersView.columnCount = 2 $groupMembersView.columnHeadersVisible = $TRUE $groupMembersView.columns[0].name = "ID" $groupMembersView.columns[1].name = "DisplayName" out-logfile -string "Generate the membership view and log membership for preservation..." foreach ($object in $groupMembers) { $groupMembersView.rows.add($object.id,$object.AdditionalProperties.displayName) } } #> if ($getGroupFailure -eq $FALSE) { out-logfile -string "Showing license display controls..." $licenseList.beginUpdate() $licenseLabel.show() $LicenseList.show() foreach ($sku in $skus) { $rootNode = New-Object System.Windows.Forms.TreeNode $rootNode.text = $sku.SkuPartNumber $rootNode.name = $sku.SkuPartNumber out-logfile -string "Testing all licenses on the group to determine if any portion of the sku is available..." $test = @() $test += $global:skuTracking | where {($_.skuPartNumber -eq $sku.skuPartNumber) -and ($_.EnabledOnGroup -eq $TRUE)} if ($test.count -gt 0) { out-logfile -string "A plan within the sku is enabled -> set the main sku to checked..." $rootNode.checked=$true $global:skuRootIDPresent+=$sku.SkuID } else { $global:skuRootIDNotPresent+=$sku.skuID out-logfile -string "No plans within the sku are enabled -> set the main sku to unchecked." } [void]$licenseList.nodes.add($rootNode) foreach ($servicePlan in $sku.servicePlans) { if ($servicePlan.appliesTo -ne "Company") { $subnode = New-Object System.Windows.Forms.TreeNode $subnode.text = $servicePlan.ServicePlanName out-logfile -string "Testing all enabled plans to determine if the plan name within the sku is enabled on the group..." $test = @() $test += $global:skuTracking | where {(($_.skuPartNumber -eq $sku.skuPartNumber) -and ($_.EnabledOnGroup -eq $TRUE) -and ($_.ServicePlanName -eq $servicePlan.ServicePlanName))} if ($test.count -gt 0) { out-logfile -string "The service plan on the sku is enabled on the group - setting the checkbox..." $subnode.checked = $true } else { out-logfile -string "The service plan on the sku is not enabled on the group - set to unchecked..." } [void]$rootnode.Nodes.Add($subnode) } } } $licenseList.endUpdate() $global:skuRootIDPresent+=$global:fakePlanID $global:skuRootIDNotPresent+=$global:fakePlanID $global:skuRootIDPresent+=$global:fakePlanID $global:skuRootIDNotPresent+=$global:fakePlanID $licenseList.add_AfterCheck{ $ToolLabel.Text = "License option selected - updating tree..." $commit.show() #Event Argument: $_ = [System.Windows.Forms.TreeViewEventArgs] if($_.Action -ne 'Unknown'){ if($_.Node.Nodes.Count -gt 0){ CheckAllChildNodes $_.Node $_.Node.Checked } else { $parent = $_.node.parent $needsChecked = $FALSE foreach ($n in $parent.nodes) { if ($n.checked) { $needsChecked = $true break } else { $needsChecked=$false } } if ($needsChecked -eq $TRUE) { $parent.checked = $TRUE } else { $parent.Checked = $false } } } } } } . (Join-Path $PSScriptRoot 'managegrouplicense.designer.ps1') $Form2.ShowDialog() } |