Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
By: Anshuman Mansingh, Technology Specialist, Microsoft Corporation, https://www.linkedin.com/in/anshumanmansingh/ |
I have often come across this requirement where I am asked for a custom report that returns the following.
- A division of licenses based on domains
- Types of licenses assigned
Fortunately, we have Microsoft Excel that can do much of the filtering – if we can export a list of all the details required above. And so, I wrote two PowerShell scripts.
Please find them at the end of this article.
Note: This script has been designed for information retrieval and does not change anything on Office 365. Also, it is not covered under Microsoft support – please treat this as a sample.
Outputs
Script - Version 1
Script Version 1 Output:
This script will find the desktop and post a comma-delimited CSV file. This file can be opened in the notepad. However, to make better sense, you can open it in MS Excel and then press "Ctrl + T" (and select "My table has headers"), to format the output as a table.
Once converted to a table, you can click on the small drop-down (down-arrow) buttons next to each column-head to filter the table as you need.
References on dealing with CSV data in Excel
Columns in the output CSV:
- Display Name
- User Principal Name
- Each SKU or License-type (in the tenant) has a column in the CSV
Below is a sample.
Script Version 1 Time Taken:
This script returns value of the time taken. Below are some test numbers on time taken to connect to office 365, retrieve data, analyze and export to a csv file.
8000 users – 2 minutes 13 seconds
20000 users – 6 minutes 28 seconds
This looks like an acceptable time investment considering the once-in-a-month-type nature of the report.
However, the time taken increases with increasing user base and slower connection and is dependent on the client system configuration.
Script - Version 2
Script Version 2 Output:
This script will find the desktop and post multiple comma-delimited CSV files.
(You can format and filter these CSVs as tables – as explained above in output description of script-version-1.)
Columns in the first CSV:
- Display Name
- User Principal Name
- Each SKU or License-type (in the tenant) has a column in the CSV
Columns in the second CSV:
- Display Name
- User Principal Name
- Each Office 365 Service (in the tenant) has a column in the CSV
Below is a sample from the second CSV
Script Version 2 Time Taken:
The script returns the value of time taken.
8000 users – 2 minutes 31 seconds
20000 users – 6 minutes 48 seconds
Steps to Run
Step 1:
Only for the first run: Prepare PowerShell to run Office 365 related scripts.
- Open Windows PowerShell as an administrator
- Run the command: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
- Confirm "Yes" or "Yes to All" when prompted.
- Close PowerShell Window.
Step 2:
Only for the first run: Download and install the necessary PowerShell modules.
- Microsoft Online Services Sign-In Assistant for IT Professionals RTW and
- Azure Active Directory Module for PowerShell
32 bit 64 bit
Step 3:
Only for the first run:
Ready the script
- Copy the script on to notepad.
- Save the file as a ".ps1" file on the desktop.
Step 4:
Running the script – There are two options.
Action Item: Starting the script
Option 1: Right click on the .ps1 file and click on "Run with PowerShell"
Option 2: Open Windows PowerShell > Type in the path of the file at the prompt - (e.g. "c:\users\anshuman\script.ps1") > hit Enter key.
Action Item: The script will prompt for credentials. Please enter your Office 365 Global Administrator credentials.
Wait & Watch: The script will then keep you waiting as it starts to connect and retrieve users.
Wait & Watch: It will then start reading into each user's licensing information. And while it does that, you will see a progress bar.
Wait & Watch: Once, the processing is over, this script is going to write the licensing information on to a CSV file – and post it on your desktop.
SCRIPTS
#Version 1
#Editables $NameOfOutputFile_LicenseDetails = "LicenseStats.csv" $NameOfOutputFile_Errors = "Errors.csv" $PathOfOutputFiles = [Environment]::GetFolderPath("Desktop") #ErrorsRefreshed $Error.Clear() #Prompts for Office 365 Administrator Credential if(!$cred){$cred = Get-Credential -Message "Office 365 Global Administrator Credentials"} $TimeFlag1 = (Get-Date) #First Time Flag #Initiates Remote PowerShell connection Write-Progress -Activity "Connecting Office 365" -Id 1 Import-Module MSOnline; Connect-MsolService -Credential $cred #Start of Script Write-Progress -Activity "Retrieving User Information" -Id 1 $AllUsers = Get-MsolUser -All | select DisplayName, UserPrincipalName, Licenses $AccountSkuId = ($AllUsers.Licenses.AccountSkuId | group).Name $paras = @(); $paras += "DisplayName"; $paras += "UserPrincipalName"; $paras += "Domain"; $paras += $AccountSkuId $List = @(); $i = 1; $AllCount = ($AllUsers).Count $DesktopPath = $PathOfOutputFiles #Start of User Loop Write-Progress -Activity "Working on Retrieved Data" -Id 1 $AllUsers | foreach{ $cUser = $_ $cList = "" | select $paras $cList.DisplayName = $cUser.DisplayName $cList.UserPrincipalName = $cUser.UserPrincipalName $cList.Domain = (($cUser.UserPrincipalName).split("@")[1]) $cUser.Licenses.AccountSkuid | foreach{ if($_){$cList."$_" = "Yes"} } $List += $cList; $i+=1; if($i -le $AllCount){Write-Progress -Activity "Analysing per-User Licensing Infomation" -PercentComplete (($i/$AllCount)*100) -CurrentOperation "$i of $AllCount" -ParentId 1} Clear-Variable cUser; } #End of User Loop $List | Export-Csv ($DesktopPath + "\" + $NameOfOutputFile_LicenseDetails) -NoTypeInformation $Error | Export-Csv ($DesktopPath + "\" + $NameOfOutputFile_Errors) -NoTypeInformation $TimeFlag2 = (Get-Date); Write-Host "Time Taken: " ($TimeFlag2 - $TimeFlag1) " for " $AllCount " users." $host.EnterNestedPrompt();#$host.ExitNestedPrompt() #End of Script
#Version 2
#Editables $NameOfOutputFile_LicenseDetails = "LicenseStats.csv" $NameOfOutputFile_ServiceStatus = "ServiceStatus.csv" $NameOfOutputFile_Errors = "Errors.csv" $PathOfOutputFiles = [Environment]::GetFolderPath("Desktop") #ErrorsRefreshed $Error.Clear() #Prompts for Office 365 Administrator Credential if(!$cred){$cred = Get-Credential} $TimeFlag1 = (Get-Date) #First Time Flag #Initiates Remote PowerShell connection Write-Progress -Activity "Connecting Office 365" -Id 1 Import-Module MSOnline; Connect-MsolService -Credential $cred #Start of Script Write-Progress -Activity "Retrieving User Information" -Id 1 $AllUsers = Get-MsolUser -All | select DisplayName, UserPrincipalName, Licenses #ColumnsStart $AccountSkuId = ($AllUsers.Licenses.AccountSkuId | group).Name $paras = @(); $paras += "DisplayName"; $paras += "UserPrincipalName"; $paras += "Domain"; $paras += $AccountSkuId $ServicePlans = ($AllUsers.licenses.servicestatus.serviceplan.ServiceName | group).Name $paras2 = @(); $paras2 += "DisplayName"; $paras2 += "UserPrincipalName"; $paras2 += "Domain"; $paras2 += $ServicePlans #ColumnsEnd $List = @(); $List2 = @(); $i = 1; $AllCount = ($AllUsers).Count $DesktopPath = $PathOfOutputFiles #Start of User Loop Write-Progress -Activity "Working on Retrieved Data" -Id 1 $AllUsers | foreach{ $cUser = $_ $cList = "" | select $paras; $cList2 = "" | select $paras2; $cList.DisplayName = $cUser.DisplayName; $cList2.DisplayName = $cUser.DisplayName; $cList.UserPrincipalName = $cUser.UserPrincipalName; $cList2.UserPrincipalName = $cUser.UserPrincipalName; $cList.Domain = (($cUser.UserPrincipalName).split("@")[1]); $cList2.Domain = $cList.Domain; $cUser.Licenses.AccountSkuid | foreach{ if($_){$cList."$_" = "Yes"} } $cUser.licenses.servicestatus | foreach{ if($_){$cList2name = $_.serviceplan.ServiceName; $cList2stat = $_.ProvisioningStatus; $cList2.$cList2name = $cList2stat} } $List += $cList; $List2 += $cList2; $i+=1; if($i -le $AllCount){Write-Progress -Activity "Analysing per-User Licensing Infomation" -PercentComplete (($i/$AllCount)*100) -CurrentOperation "$i of $AllCount" -ParentId 1} Clear-Variable cUser; } #End of User Loop $List | Export-Csv ($DesktopPath + "\" + $NameOfOutputFile_LicenseDetails) -NoTypeInformation $List2 | Export-Csv ($DesktopPath + "\" + $NameOfOutputFile_ServiceStatus) -NoTypeInformation $Error | Export-Csv ($DesktopPath + "\" + $NameOfOutputFile_Errors) -NoTypeInformation $TimeFlag2 = (Get-Date); Write-Host "Time Taken: " ($TimeFlag2 - $TimeFlag1) " for " $AllCount " users." $host.EnterNestedPrompt();#$host.ExitNestedPrompt() #End of Script
Comments
- Anonymous
October 09, 2017
Hi,One minor comment to your code... Due to encoding issues (my language uses accents and other characters like 'ç'), I would add to the Export-Csv lines an -Enconding UTF8.Thanks for sparing me a few hours to code this... ;)