Entra / Microsoft 365 · Teams
Report loop workspaces
Example script to show how to report Loop workspaces, including pagination when there are more than 200 workspaces in the tenant.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -NoWelcome -Scopes Directory.Read.All
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
Connect-MgGraph -NoWelcome -Scopes Directory.Read.All# Connect to SharePoint Online[array]$Domains = (Get-MgOrganization).verifiedDomains$DefaultDomain = $Domains | Where-Object {$_.IsDefault -eq $true}$SPOAdminRoot = ("https://{0}-admin.sharepoint.com" -f $DefaultDomain.Name.split('.')[0])Write-Host "Connecting to SharePoint Online..."Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShellConnect-SPOService -Url $SPOAdminRootIf (Get-SPOTenant) {Write-Host ("Connected to SharePoint Online at {0}" -f $SPOAdminRoot)} Else {Write-Host "Failed to connect to SharePoint Online"Break}Write-Host "Looking for Loop workspaces..."[array]$LoopWorkspaces = Get-SPOContainer -OwningApplicationID a187e399-0c36-4b98-8f04-1edc167a0996 -PagedIf (!($LoopWorkspaces)) {Write-Host "Can't get Loop workspaces - exiting"; break}# Figure out if there are more than 200 workspaces.[string]$Token = $nullIf ($LoopWorkspaces[200]) {# Extract the token for the next page of workspace information$Token = $LoopWorkSpaces[200].split(":")[1].Trim()# Remove the last item in the array because it's the one that contains the token$LoopWorkspaces = $LoopWorkspaces[0..199]}Write-Host "Token for next page found - retrieving more workspaces..."While ($Token) {# Loop while we can get a token for the next page of workspaces[array]$NextSetofWorkSpaces = Get-SPOContainer -OwningApplicationID a187e399-0c36-4b98-8f04-1edc167a0996 `-PagingToken $Token -PagedIf ($NextSetofWorkSpaces[200]) {$Token = $NextSetofWorkSpaces[200].split(":")[1].Trim()$NextSetofWorkspaces = $NextSetofWorkspaces[0..199]} Else {$Token = $NullIf (($NextSetofWorkSpaces[$NextSetofWorkspaces.count -1]) -eq "End of containers view.") {# Remove the last item in the array because it contains the message "End of containers view."$NextSetofWorkspaces = $NextSetofWorkspaces[0..($NextSetofWorkspaces.count -2)]}}$LoopWorkspaces += $NextSetofWorkspaces}Write-Host ("{0} Loop workspaces found" -f $LoopWorkspaces.count)$CSVOutputFile = "C:\temp\LoopWorkSpaces.CSV"$LoopServicePlan = 'c4b8c31a-fb44-4c65-9837-a21f55fcabda'# Define the licenses that allow users to create Loop workspaces. We use this information to figure out if the# licenses assigned to the owner account allows them to create more workspaces.$LoopValidLicenses = @{}$LoopValidLicenses.Add("f245ecc8-75af-4f8e-b61f-27d8114de5f3", "Microsoft 365 Business Standard")$LoopValidLicenses.Add("cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46", "Microsoft 365 Business Premium")$LoopValidLicenses.Add("05e9a617-0261-4cee-bb44-138d3ef5d965", "Microosft 365 E3")$LoopValidLicenses.Add("0c21030a-7e60-4ec7-9a0f-0042e0e0211a", "Microsoft 365 E3 Hub Min 500")$LoopValidLicenses.Add("06ebc4ee-1bb5-47dd-8120-11324bc54e06", "Microsoft 365 E5")$LoopWorkspaces = $LoopWorkspaces | Sort-Object ContainerName$Report = [System.Collections.Generic.List[Object]]::new()$TotalBytes = 0; $LicenseOK = 0; $i = 0ForEach ($LoopSpace in $LoopWorkspaces) {$i++Write-Output ("Analyzing workspace {0} {1}/{2}" -f $LoopSpace.ContainerName, $i, $LoopWorkspaces.count)# Get detail of the workspace$LoopSpaceDetails = Get-SPOContainer -Identity $LoopSpace.ContainerId# Get detail about the owner[array]$Owners = $LoopSpaceDetails.OwnersIf ($Owners) {ForEach ($Owner in $Owners) {$LicenseFound = $Null; $LoopLicenseStatus = "Unlicensed"; $LicenseName = $Null# Find if the Loop service plan is successfully provisioned or is awaiting provisioning for the account[array]$UserLicenseData = Get-MgUserLicenseDetail -UserId $Owner$LoopLicense = $UserLicenseData | Select-Object -ExpandProperty ServicePlans | `Where-Object {$_.ServicePlanId -eq $LoopServicePlan} | Select-Object -ExpandProperty ProvisioningStatusIf ($LoopLicense -in 'Success', 'PendingProvisioning') {$LicenseOK++$LoopLicenseStatus = "OK"}# Find what SKU the Loop service plan belongs toTry {$User = Get-MgUser -UserId $Owner -Property Id, displayName, department, UserPrincipalName -ErrorAction Stop$OwnerName = $User.DisplayName$UserUPN = $User.UserPrincipalName$UserDepartment = $User.Department[array]$SKUs = $UserLicenseData.SkuIdForEach ($Sku in $Skus) {$LicenseFound = $LoopValidLicenses[$Sku]If ($LicenseFound) {$LicenseName = $LicenseFound}}} Catch {Write-Host ("Unable to find user {0} - skipping" -f $Owner) -ForegroundColor RedContinue}}} Else {$Members = "Microsoft 365 Group"$LicenseName = "Microsoft 365 Group"$LoopLicenseStatus = "OK"$OwnerName = "Microsoft 365 Group"$UserUPN = $null$UserDepartment = $null}[array]$Members = $Null[array]$Managers = $LoopSpaceDetails.ManagersForEach ($Manager in $Managers) {Try {$Member = Get-MgUser -UserId $Manager -ErrorAction Stop$Members += $Member.DisplayName} Catch {Continue # Probably a group that the Get-SPOContainer doesn't report yet}}$StorageUsed = "{0:N2}" -f ($LoopSpaceDetails.StorageUsedInBytes/1MB)$TotalBytes = $TotalBytes + $LoopSpaceDetails.StorageUsedInBytes$ReportLine = [PSCustomObject]@{ContainerId = $LoopSpace.ContainerIdApp = $LoopSpaceDetails.OwningApplicationName'Workspace Name' = $LoopSpace.ContainerNameDescription = $LoopSpace.DescriptionOwner = $OwnerNameUPN = $UserUPNDepartment = $UserDepartmentLicense = $LoopLicenseStatusProduct = $LicenseNameMembers = ($Members -Join ", ")Created = $LoopSpaceDetails.CreatedOnSiteURL = $LoopSpaceDetails.ContainerSiteUrl"Storage (MB)" = $StorageUsed}$Report.Add($ReportLine)}$Report | Out-GridView -Title "Details of Loop Workspaces"$Users = $Report | Select-Object Owner, License | Sort-Object Owner -Unique$Report | Export-CSV -NoTypeInformation $CSVOutputFile$TotalLoopStorage = "{0:N2}" -f ($TotalBytes/1GB)Write-Output ""Write-Output ("Microsoft Loop is consuming {0} GB of the tenant's SharePoint Online storage quota" -f $TotalLoopStorage)Write-Output ("Number of Loop workspaces found: {0}" -f $LoopWorkspaces.count)Write-Output ""Write-Output "Details of Users and License status (to create new Loop workspaces)"$Users | Sort-Object LicenseWrite-Output ""Write-Output ("Details can be found in the CSV file {0}" -f $CSVOutputFile)
Attribution
Author
Office365itpros