278 lines
11 KiB
PowerShell
Raw Normal View History

<#
=============================================================================================
Name: List Microsoft 365 Users Direct Membership Using PowerShell
Version: 1.0
website: o365reports.com
~~~~~~~~~~~~~~~~~~
Script Highlights:
~~~~~~~~~~~~~~~~~~
1. The script exports 3 different CSV reports.
1 - i) User's direct group membership report
1 - ii)Users with admin roles
1 - iii) Users with their administrative units
2. Retrieves guest user memberships, too.
3. Allows you to get specific users direct membership within existing objects separately.
4. You can import a CSV and filter down memberships for a list of users, too!
5. Automatically install the required Microsoft Graph modules with your confirmation.
6. The script can be executed with an MFA-enabled account too. 
7. Exports report results as a CSV file. 
8. The script is scheduler-friendly, making it easy to automate.
9. It supports certificate-based authentication (CBA) too.
For detailed Script execution: : https://o365reports.com/2024/08/06/list-microsoft-365-users-direct-membership-using-powershell
============================================================================================
#>
param(
[string]$TenantID,
[string]$ClientID,
[string]$CertificateThumbPrint,
[string]$UserId,
[string]$CSV
)
$directoryRolesFilePath = ".\Users_DirectoryRoles_Membership_Report$((Get-Date -format yyyy-MMM-dd-ddd_hh-mm-ss_tt).ToString()).csv"
$administrativeUnitsFilePath = ".\Users_AdministrativeUnits_Membership_Report$((Get-Date -format yyyy-MMM-dd-ddd_hh-mm-ss_tt).ToString()).csv"
$groupFilePath = ".\Users_GroupMembership_Report$((Get-Date -format yyyy-MMM-dd-ddd_hh-mm-ss_tt).ToString()).csv"
$global:Count = 0
function UserDirectMembership{
param(
[Parameter(Mandatory = $true)]
[PSCustomObject]$UserDetails
)
try {
$global:Count++
Write-Progress -Activity "Getting User's Direct Membership Report.. Processed Users Count:$($Count)" -Status "Fetching User data for $($UserDetails.DisplayName)"
Get-MgUserMemberOf -UserId $UserDetails.Id -All | Select-Object -ExpandProperty AdditionalProperties -Property id |ForEach-Object{$DirectMembership=$_
if ($DirectMembership.'@odata.type' -eq "#microsoft.graph.directoryRole")
{
$directoryRole = [PSCustomObject]@{
"User Name " = $UserDetails.DisplayName
"UPN"=$UserDetails.UserPrincipalName
"DirectoryRole Name" = $DirectMembership.displayName
"DirectoryRole Description" = $DirectMembership.description
"DirectoryRole Id" = $DirectMembership.Id
"User SignIn Status"=$UserDetails.SignInStatus
"User Department"=$UserDetails.Department
"User Job Title"=$UserDetails.JobTitle
}
$directoryRole | Export-Csv -Path $directoryRolesFilePath -NoTypeInformation -Append -Force
}
elseif($DirectMembership.'@odata.type' -eq "#microsoft.graph.group")
{
$group = [PSCustomObject]@{
"User Name " = $UserDetails.DisplayName
"UPN"=$UserDetails.UserPrincipalName
"Group Name" = $DirectMembership.displayName
"Group Description" = $DirectMembership.description
"Group Visibility" = $DirectMembership.visibility
"Group Mail Id" = $DirectMembership.mail
"Group Types" = ""
"Group Created Date Time" = Get-Date -Date $DirectMembership.createdDateTime
"Group Id" = $DirectMembership.Id
"User SignIn Status"=$UserDetails.SignInStatus
"User Department"=$UserDetails.Department
"User Job Title"=$UserDetails.JobTitle
}
if ($DirectMembership.groupTypes[0] -eq "Unified")
{
$group."Group Types" = "Microsoft 365 group"
}
elseif($DirectMembership.securityEnabled -and $DirectMembership.mailEnabled)
{
$group."Group Types" = "Mail-enabled security group"
}
elseif($DirectMembership.securityEnabled)
{
$group."Group Types" = "Security group"
}
else
{
$group."Group Types" = "Distribution list"
}
$group| Export-Csv -Path $groupFilePath -NoTypeInformation -Append -Force
}
elseif($DirectMembership.'@odata.type' -eq "#microsoft.graph.administrativeUnit")
{
$administrativeUnits = [PSCustomObject]@{
"User Name " = $UserDetails.DisplayName
"UPN"=$UserDetails.UserPrincipalName
"AU Name" = $DirectMembership.displayName
"AU Description" = $DirectMembership.description
"AU Id" = $DirectMembership.Id
"User SignIn Status"=$UserDetails.SignInStatus
"User Department"=$UserDetails.Department
"User Job Title"=$UserDetails.JobTitle
}
$administrativeUnits | Export-Csv -Path $administrativeUnitsFilePath -NoTypeInformation -Append -Force
}
}
}
catch {
Write-Host "Error occurred: $( $_.Exception.Message )" -ForegroundColor Red
Exit
}
}
#Module installation
$Module = Get-Module -Name Microsoft.Graph.Users -ListAvailable
if ($Module.count -eq 0)
{
Write-Host Microsoft.Graph.Users is not available in Your System -ForegroundColor Red
$Confirm = Read-Host Are you sure you want to install module? [Y] Yes [N] No
if ($Confirm -eq "y" -or $Confirm -eq "Y")
{
try
{
Install-Module Microsoft.Graph.Users -Force -AllowClobber -Scope CurrentUser
}
catch
{
Write-Host "Error occurred : $( $_.Exception.Message )" -ForegroundColor Red
Exit
}
Write-Host Microsoft.Graph.Users installed successfully... -ForegroundColor Green
}
else
{
Write-Host Microsoft.Graph.Users is required .Please Install-Module Microsoft.Graph.Users to continue..
Exit
}
}
#Authenication
try
{
if (($TenantId -ne "") -and ($ClientId -ne "") -and ($CertificateThumbPrint -ne "")) {
$Connect = Connect-MgGraph -TenantId $TenantID.Trim() -ClientID $ClientID.Trim() -CertificateThumbprint $CertificateThumbPrint.Trim() -ErrorAction Stop
}else{
$Connect = Connect-MgGraph -Scopes "Directory.Read.All" -ErrorAction Stop}
}
catch
{
Write-Host "Error occurred while connecting to Microsoft Graph: $( $_.Exception.Message )" -ForegroundColor Red
Exit
}
function UserClass{
param(
[Parameter(Mandatory = $true)]
[string]$Userid
)
try{
$User=Get-MgUser -UserId $Userid.Trim() -Property DisplayName,UserPrincipalName,AccountEnabled,department,JobTitle,id | Select-Object DisplayName,UserPrincipalName,AccountEnabled,department,JobTitle,id
$UserDetails=[PSCustomObject]@{
"DisplayName"=$User.DisplayName
"UserPrincipalName"=$User.UserPrincipalName
"Department"=$User.Department
"JobTitle"=$User.JobTitle
"Id"=$User.Id
"SignInStatus"=""
}
if($User.AccountEnabled){
$UserDetails.SignInStatus="Enabled"}
else{
$UserDetails.SignInStatus="Disabled"}
UserDirectMembership -UserDetails $UserDetails
}catch{
Write-Host "Error occurred : $( $_.Exception.Message )" -ForegroundColor Red
}
}
#Get membership details for a single user
if($UserId -ne "")
{
UserClass -Userid $UserId
}
#Get membership details for a list of users
elseif($CSV -ne "")
{
if ((Test-Path -Path $CSV) -eq "True") {
Import-Csv -Path $CSV | ForEach-Object {
$UserId = $_.UserId
UserClass -Userid $UserId
}
}
else {
Write-Host "Incorrect Csv File Path : $CSV" -ForegroundColor Red
Exit
}
}
#Get membership details for all users
else{
try{
Get-MgUser -All -Property DisplayName,UserPrincipalName,AccountEnabled,department,JobTitle,id | Select-Object DisplayName,UserPrincipalName,AccountEnabled,department,JobTitle,id |ForEach-Object{$User=$_
$UserDetails=[PSCustomObject]@{
"DisplayName"=$User.DisplayName
"UserPrincipalName"=$User.UserPrincipalName
"Department"=$User.Department
"JobTitle"=$User.JobTitle
"Id"=$User.Id
"SignInStatus"=""
}
if($User.AccountEnabled){
$UserDetails.SignInStatus="Enabled"}
else{
$UserDetails.SignInStatus="Disabled"}
UserDirectMembership -UserDetails $UserDetails}
}catch{
Write-Host "Error occurred : $( $_.Exception.Message )" -ForegroundColor Red
}
}
Write-Host `n Script executed successfully -ForegroundColor Green
if ((Test-Path -Path $groupFilePath) -eq "True") {
Write-Host `n "Users' group membership report availble in:" -NoNewline -ForegroundColor Yellow; Write-Host "$groupFilePath" `n
}else{ $groupFilePath=""
Write-Host `n "No data is available for the Users' group membership report" -NoNewline `n}
if ((Test-Path -Path $directoryRolesFilePath) -eq "True") {
Write-Host `n "Users' directory role membership report availble in :" -NoNewline -ForegroundColor Yellow; Write-Host "$directoryRolesFilePath" `n
}else{$directoryRolesFilePath=""
Write-Host `n "No data is available for the Users directory role membership report" -NoNewline `n
}
if ((Test-Path -Path $administrativeUnitsFilePath) -eq "True") {
Write-Host `n "Users' Administrative Units membership report availble in:" -NoNewline -ForegroundColor Yellow; Write-Host "$administrativeUnitsFilePath" `n
}else{ $administrativeUnitsFilePath=""
Write-Host `n "No data is available for the Users' Administrative Units membership report" -NoNewline `n
}
if($directoryRolesFilePath -ne "" -or $administrativeUnitsFilePath -ne "" -or $groupFilePath -ne ""){
$Prompt = New-Object -ComObject wscript.shell
$UserInput = $Prompt.popup("Do you want to open output files?", 0, "Open Output File", 4)
if ($UserInput -eq 6) {
if($groupFilePath -ne ""){
Invoke-Item $groupFilePath
}
if($directoryRolesFilePath -ne ""){
Invoke-Item $directoryRolesFilePath
}
if($administrativeUnitsFilePath -ne ""){
Invoke-Item $administrativeUnitsFilePath
}
}}
Disconnect-MgGraph |Out-Null
Write-Host `n~~ Script prepared by AdminDroid Community ~~`n -ForegroundColor Green
Write-Host "~~ Check out " -NoNewline -ForegroundColor Green; Write-Host "admindroid.com" -ForegroundColor Yellow -NoNewline; Write-Host " to get access to 1800+ Microsoft 365 reports. ~~" -ForegroundColor Green `n