Last active
September 24, 2024 22:31
-
-
Save Calvindd2f/e38f81e4b1b1a1e955939083d9409074 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Function to calculate the annual costs of the licenses assigned to a user account | |
| Function Get-LicenseCosts { | |
| [CmdletBinding()] | |
| param ( | |
| [array]$Licenses | |
| ) | |
| [int]$Costs = 0 | |
| foreach ($License in $Licenses) { | |
| $LicenseCost = $PricingHashTable[$License] | |
| if ([float]$LicenseCost) { | |
| $AnnualCost = [float]$LicenseCost * 100 * 12 # Convert to cents and calculate annual | |
| $Costs += $AnnualCost | |
| } | |
| } | |
| return ($Costs / 100) # Return annual cost in dollars | |
| } | |
| # Function to import CSV data and populate HashTables | |
| Function Import-LicenseData { | |
| param ( | |
| [string]$SkuCsvPath, | |
| [string]$ServicePlanCsvPath | |
| ) | |
| if (!(Test-Path $SkuCsvPath) -or !(Test-Path $ServicePlanCsvPath)) { | |
| Write-Error "License data files are missing. Exiting..." | |
| return $false | |
| } | |
| $ImportSkus = Import-Csv $SkuCsvPath | |
| $ImportServicePlans = Import-Csv $ServicePlanCsvPath | |
| $SkuHashTable = @{} | |
| $ServicePlanHashTable = @{} | |
| foreach ($Line in $ImportSkus) { $SkuHashTable.Add([string]$Line.SkuId, [string]$Line.DisplayName) } | |
| foreach ($Line in $ImportServicePlans) { $ServicePlanHashTable.Add([string]$Line.ServicePlanId, [string]$Line.ServicePlanDisplayName) } | |
| $PricingInfoAvailable = $false | |
| if ($ImportSkus[0].Price) { | |
| $PricingInfoAvailable = $true | |
| $Global:PricingHashTable = @{} | |
| foreach ($Line in $ImportSkus) { | |
| $PricingHashTable.Add([string]$Line.SkuId, [string]$Line.Price) | |
| } | |
| $Currency = if ($ImportSkus[0].Currency) { $ImportSkus[0].Currency } else { "USD" } | |
| } | |
| return @{ | |
| SkuHashTable = $SkuHashTable; | |
| ServicePlanHashTable = $ServicePlanHashTable; | |
| PricingInfoAvailable = $PricingInfoAvailable; | |
| Currency = $Currency | |
| } | |
| } | |
| # Function to process user data and generate the report | |
| Function Process-UserLicenses { | |
| param ( | |
| [array]$Users, | |
| [hashtable]$SkuHashTable, | |
| [hashtable]$ServicePlanHashTable, | |
| [bool]$PricingInfoAvailable, | |
| [string]$Currency | |
| ) | |
| $TotalUserLicenseCosts = 0 | |
| $Report = [System.Collections.Generic.List[Object]]::new() | |
| foreach ($User in $Users) { | |
| $LicenseInfo = @() | |
| $DisabledPlans = @() | |
| $UserCosts = 0 | |
| $GroupAssignments = $User.LicenseAssignmentStates | Where-Object { $_.AssignedByGroup -and $_.State -eq "Active" } | |
| $GroupLicensing = $null | |
| # Group-based licensing assignments | |
| foreach ($G in $GroupAssignments) { | |
| $GroupName = (Get-MgGroup -GroupId $G.AssignedByGroup).DisplayName | |
| $GroupProductName = $SkuHashTable[$G.SkuId] | |
| $GroupLicensing += ("{0} assigned from {1}" -f $GroupProductName, $GroupName) | |
| } | |
| $GroupLicensingAssignments = $GroupLicensing -join ", " | |
| # Direct License Assignments | |
| $DirectAssignments = $User.AssignedLicenses.SkuId | Where-Object { $_ -notin $GroupAssignments.SkuId } | |
| foreach ($License in $DirectAssignments) { | |
| if ($SkuHashTable.ContainsKey($License)) { | |
| $LicenseInfo += $SkuHashTable[$License] | |
| } else { | |
| $LicenseInfo += $License | |
| } | |
| } | |
| # Disabled Plans Reporting | |
| $License = $User.AssignedLicenses | Where-Object { $_.SkuId -eq $License } | |
| if ($License.DisabledPlans) { | |
| foreach ($DisabledPlan in $License.DisabledPlans) { | |
| if ($ServicePlanHashTable.ContainsKey($DisabledPlan)) { | |
| $DisabledPlans += $ServicePlanHashTable[$DisabledPlan] | |
| } else { | |
| $DisabledPlans += $DisabledPlan | |
| } | |
| } | |
| } | |
| # License Cost Calculation | |
| if ($PricingInfoAvailable) { | |
| $UserCosts = Get-LicenseCosts -Licenses $User.AssignedLicenses.SkuId | |
| $TotalUserLicenseCosts += $UserCosts | |
| } | |
| # Generate Report Line | |
| $ReportLine = [PSCustomObject][Ordered]@{ | |
| User = $User.DisplayName | |
| UPN = $User.UserPrincipalName | |
| Country = $User.Country | |
| Department = $User.Department | |
| Title = $User.JobTitle | |
| "Direct assigned licenses" = $LicenseInfo -join ", " | |
| "Disabled Plans" = $DisabledPlans -join ", " | |
| "Group based licenses" = $GroupLicensingAssignments | |
| "Annual License Costs" = if ($PricingInfoAvailable) { ("{0} {1}" -f $Currency, ($UserCosts.ToString('F2'))) } else { "N/A" } | |
| "Account created" = $User.CreatedDateTime | |
| "Last Signin" = $User.SignInActivity.LastSignInDateTime | |
| } | |
| $Report.Add($ReportLine) | |
| } | |
| return @{ | |
| Report = $Report; | |
| TotalUserLicenseCosts = $TotalUserLicenseCosts | |
| } | |
| } | |
| # Main Execution | |
| [string]$RunDate = Get-Date -format "dd-MMM-yyyy HH:mm:ss" | |
| [string]$Currency = "USD" | |
| $LicenseData = Import-LicenseData -SkuCsvPath "c:\temp\SkuDataComplete.csv" -ServicePlanCsvPath "c:\temp\ServicePlanDataComplete.csv" | |
| if (!$LicenseData) { | |
| Write-Error "Failed to load license data." | |
| return | |
| } | |
| $Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -All -Property id, displayName, userPrincipalName, country, department, assignedlicenses, LicenseAssignmentStates, createdDateTime, jobTitle, signInActivity | |
| if (!$Users) { | |
| Write-Error "No licensed user accounts found." | |
| return | |
| } | |
| $ReportData = Process-UserLicenses -Users $Users -SkuHashTable $LicenseData.SkuHashTable -ServicePlanHashTable $LicenseData.ServicePlanHashTable -PricingInfoAvailable $LicenseData.PricingInfoAvailable -Currency $LicenseData.Currency | |
| $Report = $ReportData.Report | |
| # Generate CSV and HTML reports | |
| $CSVOutputFile = "c:\temp\Microsoft365LicensesReport.CSV" | |
| $ReportFile = "c:\temp\Microsoft365LicensesReport.html" | |
| $Report | Export-Csv -Path $CSVOutputFile -NoTypeInformation | |
| Write-Host "Report saved to $CSVOutputFile" | |
| Disconnect-MgGraph |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Dependencies