Entra / Microsoft 365 · Users & guests
Get Planner plans for user
Use Microsoft Graph with delegated permissions to report the Planner plans a user can access.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
# Review required modules and connection steps before running.# Connect to Microsoft Graph or Exchange Online as needed for this script.
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
$AuthContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList "https://login.windows.net/redmondassociates.onmicrosoft.com"$Platform = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters -ArgumentList "Auto"$AuthenticationResult = $authContext.AcquireTokenAsync("https://graph.microsoft.com", "ded88173-911c-42a5-892b-26d7bea4c788", "https://login.microsoftonline.com/common/oauth2/nativeclient", $Platform)$Headers = @{'Authorization'=$AuthenticationResult.Result.CreateAuthorizationHeader()}# Extract user details from the authentication result$User = $AuthenticationResult.Result.UserInfo.DisplayableId# Find all Microsoft 365 Groups the user belongs to$Uri = "https://graph.microsoft.com/beta/users/$User/transitiveMemberOf"$MemberOf = Invoke-WebRequest -Headers $Headers -Uri $Uri | ConvertFrom-Json# Put the result in a list of groups we can process ;ater$GroupsMemberOf = [System.Collections.Generic.List[Object]]::new()ForEach ($M in $MemberOf.Value) {If ($M.GroupTypes -eq "Unified") { # Only select Microsoft 365 Groups$ReportLine = [PSCustomObject][Ordered]@{GroupId = $M.IdName = $M.DisplayName }$GroupsMemberOf.Add($ReportLine) }}# If there are any more groups to get, fetch them using the Nextlink given by the Graph and add them to the list$NextLink = $MemberOf.'@Odata.NextLink'While ($NextLink -ne $Null) {Write-Host "Still processing..."$MemberOf = Invoke-WebRequest -Method GET -Uri $NextLink -ContentType "application/json" -Headers $Headers | ConvertFrom-JsonForEach ($M in $MemberOf.Value) {If ($M.GroupTypes -eq "Unified") { # Only select Microsoft 365 Groups$ReportLine = [PSCustomObject][Ordered]@{GroupId = $M.IdName = $M.DisplayName }$GroupsMemberOf.Add($ReportLine) }}$NextLink = $MemberOf.'@Odata.NextLink'} #End WhileCLS# We now have a list of Microsoft 365 Groups that the user belongs to, so we can check# the groups to find out which have plans and report details of the plans we find.$Activity = "Checking Plans for " + $User$Report = [System.Collections.Generic.List[Object]]::new(); $PlanNumber = 0$i = 0; $GroupCount = $GroupsMemberOf.CountForEach ($Group in $GroupsMemberOf) {$i++$ProgressBar = "Processing group " + $Group.Name + " (" + $i + " of " + $GroupCount + ")"Write-Progress -Activity $Activity -Status $ProgressBar -PercentComplete ($i/$GroupCount*100)$PlanURI = 'https://graph.microsoft.com/V1.0/groups/' + $Group.GroupId + '/planner/plans'$Plans = Invoke-WebRequest -Method GET -Uri $PlanURI -ContentType "application/json" -Headers $Headers | ConvertFrom-JsonForEach ($Plan in $Plans.Value) {$PlanId = $Plan.Id$PlanNumber++$PlanCreated = Get-Date($Plan.CreatedDateTime) -format g$PlanOwner = $Plan.Owner # Microsoft 365 Group$PlanTitle = $Plan.Title$BucketURI = 'https://graph.microsoft.com/v1.0/planner/plans/' + $PlanId + '/buckets/'$Buckets = Invoke-RestMethod -Method GET -Uri $BucketURI -ContentType "application/json" -Headers $Headers$NumberBuckets = $Buckets.Value.Count$TasksURI = 'https://graph.microsoft.com/v1.0/planner/plans/' + $PlanId + '/tasks/'$Tasks = Invoke-RestMethod -Method GET -Uri $TasksURI -ContentType "application/json" -Headers $Headers$NumberTasks = $Tasks.'@odata.count'[DateTime]$LastTask = "1-Jan-1999"# Grab some data about tasks like the date of the latest task and task completion stats$TasksNotStarted = 0; $TasksInProgress = 0; $TasksComplete = 0ForEach ($Task in $Tasks.Value) {If (-not [string]::IsNullOrEmpty($Task.CreatedDateTime)) {[DateTime]$TaskCreated = Get-Date($Task.CreatedDateTime) -format g }If ($TaskCreated -gt $LastTask) {$LastTask = $TaskCreated; $LastTaskTitle = $Task.Title}Switch ($Task.PercentComplete) { #Generate stats for task completion status0 {$TasksNotStarted++}50 {$TasksInProgress++}100 {$TasksComplete++}} #End switch} # End ForIf ($LastTask -eq "1-Jan-1999") { # Check how long it's been since a task was created in the plan$LastTaskDate = "No tasks"; $DaysSinceTask = "N/A"}Else {$LastTaskDate = Get-Date($LastTask) -format g$DaysSinceTask = (New-TimeSpan($LastTask)).Days }# Write out information about plan$ReportLine = [PSCustomObject][Ordered]@{GroupId = $Group.GroupIdName = $Group.NamePlanId = $PlanIdTitle = $PlanTitleCreated = $PlanCreatedBuckets = $NumberBucketsTasks = $NumberTasksNotStarted = $TasksNotStartedInProgress = $TasksInProgressComplete = $TasksCompleteLastTaskDate = $LastTaskDateDaysSinceTask = $DaysSinceTaskLastTaskTitle = $LastTaskTitle }$Report.Add($ReportLine) } # End processing plan} # End GroupsWrite-Host "All done. " $PlanNumber "plans found in" $GroupCount "Microsoft 365 Groups for user" $User$Report | Select Name, Title, Created, Tasks, NotStarted, InProgress, Complete, LastTaskDate, DaysSinceTask, Buckets | Out-GridView
Attribution
Author
Office365itpros