mirror of
https://github.com/admindroid-community/powershell-scripts.git
synced 2025-12-17 16:35:19 +00:00
198 lines
8.0 KiB
PowerShell
198 lines
8.0 KiB
PowerShell
|
|
<#
|
|||
|
|
=============================================================================================
|
|||
|
|
Name: Get Nested Groups in Microsoft 365 Using PowerShell
|
|||
|
|
Version: 1.0
|
|||
|
|
Website: o365reports.com
|
|||
|
|
|
|||
|
|
Script Highlights:
|
|||
|
|
~~~~~~~~~~~~~~~~~~
|
|||
|
|
|
|||
|
|
1. The script exports 2 different CSV reports:
|
|||
|
|
i) M365 nested groups summary report
|
|||
|
|
ii) M365 nested groups detailed report
|
|||
|
|
2. Exports nested group reports based on group types, such as Security, Distribution, Mail enabled security group.
|
|||
|
|
3. Automatically installs the required Microsoft Graph module with your confirmation.
|
|||
|
|
4. The script can be executed with an MFA-enabled account too.
|
|||
|
|
5. Supports Certificate-based Authentication (CBA) too.
|
|||
|
|
6. The script is scheduler friendly.
|
|||
|
|
|
|||
|
|
For detailed script execution: https://o365reports.com/2024/11/19/get-nested-groups-in-microsoft-365-using-powershell/
|
|||
|
|
============================================================================================
|
|||
|
|
#>
|
|||
|
|
|
|||
|
|
Param
|
|||
|
|
(
|
|||
|
|
[Parameter(Mandatory = $false)]
|
|||
|
|
[switch]$DistributionList,
|
|||
|
|
[switch]$Security,
|
|||
|
|
[switch]$MailEnabledSecurity,
|
|||
|
|
[string]$TenantId,
|
|||
|
|
[string]$ClientId,
|
|||
|
|
[string]$CertificateThumbprint
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
$SummaryReport ="$(Get-Location)\M365NestedGroups_SummaryReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv"
|
|||
|
|
$DetailedReport ="$(Get-Location)\M365NestedGroups_DetailedReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv"
|
|||
|
|
|
|||
|
|
|
|||
|
|
# Function to connect to Microsoft Graph
|
|||
|
|
function Connect_ToMgGraph {
|
|||
|
|
# Check if Microsoft Graph module is installed
|
|||
|
|
$MsGraphModule = Get-Module Microsoft.Graph -ListAvailable
|
|||
|
|
if ($MsGraphModule -eq $null) {
|
|||
|
|
Write-Host "`nImportant: Microsoft Graph module is unavailable. It is mandatory to have this module installed in the system to run the script successfully."
|
|||
|
|
$confirm = Read-Host "Are you sure you want to install Microsoft Graph module? [Y] Yes [N] No"
|
|||
|
|
if ($confirm -match "[yY]") {
|
|||
|
|
Write-Host "Installing Microsoft Graph module..."
|
|||
|
|
Install-Module Microsoft.Graph -Scope CurrentUser -AllowClobber
|
|||
|
|
Write-Host "Microsoft Graph module is installed in the machine successfully" -ForegroundColor Magenta
|
|||
|
|
} else {
|
|||
|
|
Write-Host "Exiting. `nNote: Microsoft Graph module must be available in your system to run the script" -ForegroundColor Red
|
|||
|
|
Exit
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Write-Host "`nConnecting to Microsoft Graph..."
|
|||
|
|
|
|||
|
|
if (($TenantId -ne "") -and ($ClientId -ne "") -and ($CertificateThumbprint -ne "")) {
|
|||
|
|
# Use certificate-based authentication if TenantId, ClientId, and CertificateThumbprint are provided
|
|||
|
|
Connect-MgGraph -TenantId $TenantId -AppId $ClientId -CertificateThumbprint $CertificateThumbprint -NoWelcome
|
|||
|
|
} else {
|
|||
|
|
# Use delegated permissions (Scopes) if credentials are not provided
|
|||
|
|
Connect-MgGraph -Scopes "GroupMember.Read.All" -NoWelcome
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Verify connection
|
|||
|
|
if ((Get-MgContext) -ne $null) {
|
|||
|
|
Write-Host "Connected to Microsoft Graph PowerShell using account: $((Get-MgContext).Account)" -ForegroundColor Yellow
|
|||
|
|
} else {
|
|||
|
|
Write-Host "Failed to connect to Microsoft Graph." -ForegroundColor Red
|
|||
|
|
Exit
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Function to get report details
|
|||
|
|
Function Get_members {
|
|||
|
|
$ParentGroup = $_.DisplayName
|
|||
|
|
$ParentGroupEmailAddress = $_.Mail
|
|||
|
|
$ParentGroupId = $_.Id
|
|||
|
|
$CreatedDateTime = $_.CreatedDateTime
|
|||
|
|
|
|||
|
|
$TransitiveNestedGroups = Get-MgGroupTransitiveMemberAsGroup -All -GroupId $ParentGroupId
|
|||
|
|
$TransitiveNestedGroupsCount = $TransitiveNestedGroups.Count
|
|||
|
|
$TransitiveNestedGroupNames = $TransitiveNestedGroups.DisplayName -join ", "
|
|||
|
|
|
|||
|
|
Write-Progress -Activity "`n Processed group count: $Count "`n" Checking members of: $ParentGroup"
|
|||
|
|
|
|||
|
|
# Check for Empty Group
|
|||
|
|
if($TransitiveNestedGroupsCount -eq 0) { return }
|
|||
|
|
|
|||
|
|
# Get the parent group type based on properties
|
|||
|
|
if($_.Mail -ne $null) {
|
|||
|
|
if($_.SecurityEnabled -eq $false) {
|
|||
|
|
$ParentGroupType="DistributionList"
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
$ParentGroupType="MailEnabledSecurity"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
$ParentGroupType="Security"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# If parent group email address is empty
|
|||
|
|
if($ParentGroupEmailAddress -eq $null) {
|
|||
|
|
$ParentGroupEmailAddress = "-"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Filter for security group
|
|||
|
|
if(($Security.IsPresent) -and ($ParentGroupType -ne "Security")) {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Filter for Distribution list
|
|||
|
|
if(($DistributionList.IsPresent) -and ($ParentGroupType -ne "DistributionList")) {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Filter for mail enabled security group
|
|||
|
|
if(($MailEnabledSecurity.IsPresent) -and ($ParentGroupType -ne "MailEnabledSecurity")) {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Print_SummaryReportContent
|
|||
|
|
|
|||
|
|
foreach($TransitiveNestedGroup in $TransitiveNestedGroups) {
|
|||
|
|
$NestedGroup = $TransitiveNestedGroup.displayName
|
|||
|
|
$NestedGroupEmailAddress = $TransitiveNestedGroup.mail
|
|||
|
|
$NestedGroupId = $TransitiveNestedGroup.Id
|
|||
|
|
$NestedUsersCount = Get-MgGroupTransitiveMemberCountAsUser -GroupId $NestedGroupId -ConsistencyLevel eventual
|
|||
|
|
|
|||
|
|
# If Nested group email address is empty
|
|||
|
|
if($NestedGroupEmailAddress -eq $null) {
|
|||
|
|
$NestedGroupEmailAddress = "-"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Get the Nested group type based on properties
|
|||
|
|
if($TransitiveNestedGroup.Mail -ne $null) {
|
|||
|
|
if($TransitiveNestedGroup.SecurityEnabled -eq $false) {
|
|||
|
|
$NestedGroupType="DistributionList"
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
$NestedGroupType="MailEnabledSecurity"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
$NestedGroupType="Security"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Print_DetailedReportContent
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
# Print Summary Report
|
|||
|
|
Function Print_SummaryReportContent {
|
|||
|
|
$Result=@{'Group Name'=$ParentGroup; 'Group Type'=$ParentGroupType; 'Group Email Address'=$ParentGroupEmailAddress; 'Nested Group Names'=$TransitiveNestedGroupNames; 'Nested Groups Count'=$TransitiveNestedGroupsCount; 'Group Id'=$ParentGroupId;}
|
|||
|
|
$Results= New-Object PSObject -Property $Result
|
|||
|
|
$Results | Select-Object 'Group Name', 'Group Type', 'Group Email Address', 'Nested Group Names', 'Nested Groups Count', 'Group Id' | Export-Csv -Path $SummaryReport -Notype -Append
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Print Detailed Output
|
|||
|
|
Function Print_DetailedReportContent {
|
|||
|
|
$Result=@{'Parent Group Name'=$ParentGroup; 'Nested Group Name'=$NestedGroup; 'Nested Group Type'=$NestedGroupType; 'Nested Group Email Address'=$NestedGroupEmailAddress; 'Members Count in Nested Group'=$NestedUsersCount; }
|
|||
|
|
$Results= New-Object PSObject -Property $Result
|
|||
|
|
$Results | Select-Object 'Parent Group Name', 'Nested Group Name', 'Nested Group Type', 'Nested Group Email Address', 'Members Count in Nested Group' | Export-Csv -Path $DetailedReport -Notype -Append
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Connecting to the Microsoft Graph PowerShell Module
|
|||
|
|
Connect_ToMgGraph
|
|||
|
|
|
|||
|
|
# Get all nested groups in Microsoft 365
|
|||
|
|
$Count = 0
|
|||
|
|
Get-MgGroup -All | ForEach-Object {
|
|||
|
|
$Count++
|
|||
|
|
Get_Members
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Disconnect from Microsoft Graph
|
|||
|
|
Disconnect-MgGraph | Out-Null
|
|||
|
|
|
|||
|
|
# Open output file after execution
|
|||
|
|
if((Test-Path -Path $DetailedReport) -eq "True" -and (Test-Path -Path $SummaryReport) -eq "True") {
|
|||
|
|
Write-Host `n" Nested groups summary report available in: " -NoNewline -ForegroundColor Yellow
|
|||
|
|
Write-Host $SummaryReport
|
|||
|
|
Write-Host `n" Nested groups detailed report available in: " -NoNewline -ForegroundColor Yellow
|
|||
|
|
Write-Host $DetailedReport
|
|||
|
|
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 1900+ Microsoft 365 reports. ~~" -ForegroundColor Green
|
|||
|
|
$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) {
|
|||
|
|
Invoke-Item "$DetailedReport"
|
|||
|
|
Invoke-Item "$SummaryReport"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
Write-Host `n"No nested groups are found for the specified criteria." -ForegroundColor Red
|
|||
|
|
}
|