mirror of
https://github.com/admindroid-community/powershell-scripts.git
synced 2025-12-17 08:25:20 +00:00
Due to issue in MS Graph PowerShell (Version 2.27.0 or 2.28.0), API call is used to retrieve external membership.
188 lines
8.7 KiB
PowerShell
188 lines
8.7 KiB
PowerShell
<#
|
||
=============================================================================================
|
||
Name: Find All Team Channels with External Members in Microsoft 365
|
||
Version: 1.1
|
||
Website: o365reports.com
|
||
|
||
Script Highlights:
|
||
~~~~~~~~~~~~~~~~~
|
||
1. The script exports output into 2 CSV files:
|
||
-Detailed report: Teams Channels and their external user details
|
||
-Summary report: Teams Channels and their guest users count
|
||
2. Exports external users across all Teams channel types, such as private, shared, and standard.
|
||
3. Exports all team channels an external user is a member of.
|
||
4. Automatically install the Microsoft Graph PowerShell module (if not installed already) upon your confirmation.
|
||
5. The script can be executed with an MFA-enabled account too.
|
||
6. It can be executed with certificate-based authentication (CBA) too.
|
||
7. The script is schedular-friendly.
|
||
|
||
Change log:
|
||
~~~~~~~~~~~
|
||
V1.0 (Feb 04, 2025) – File created.
|
||
V1.1 (Jul 07, 2025) – Due to issue in MS Graph PowerShell cmdlet, API call is used to retrieve external membership.
|
||
|
||
|
||
For detailed Script execution: https://o365reports.com/2025/02/04/get-all-teams-channels-with-external-members/
|
||
============================================================================================
|
||
#>
|
||
|
||
Param
|
||
(
|
||
[Parameter(Mandatory = $false)]
|
||
[string]$TeamName,
|
||
[string]$ChannelName,
|
||
[string]$MemberUPN,
|
||
[ValidateSet(
|
||
'Standard',
|
||
'Private',
|
||
'Shared'
|
||
)]
|
||
[string]$ChannelType,
|
||
[string]$TenantId,
|
||
[string]$ClientId,
|
||
[string]$CertificateThumbprint
|
||
)
|
||
|
||
$SummaryReport ="$(Get-Location)\TeamsChannelsWithExternalMembers_SummaryReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv"
|
||
$DetailedReport ="$(Get-Location)\TeamsChannelsWithExternalMembers_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 "Connecting 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 "Team.ReadBasic.All", "Channel.ReadBasic.All", "ChannelMember.Read.All" -NoWelcome
|
||
}
|
||
|
||
$Script:MgContext = Get-MgContext
|
||
|
||
# Verify connection
|
||
if (($Script:MgContext) -ne $null) {
|
||
Write-Host "Connected to Microsoft Graph PowerShell using account: $(($Script:MgContext).Account)"
|
||
} else {
|
||
Write-Host "Failed to connect to Microsoft Graph." -ForegroundColor Red
|
||
Exit
|
||
}
|
||
}
|
||
|
||
# Print Summary Report
|
||
Function Print_SummaryReportContent {
|
||
$Result = @{'Team Name'=$TeamDisplayName; 'Channel Name'=$ChannelDisplayName; 'Membership Type'=$MembershipType; 'External Members Count'=$ExternalMembersCount; 'External Members'=$ExternalMembers; 'Team Id'=$TeamId; 'Channel Id'=$ChannelId;}
|
||
$Results = New-Object PSObject -Property $Result
|
||
$Results | Select-Object 'Team Name', 'Channel Name', 'Membership Type', 'External Members Count', 'External Members', 'Team Id', 'Channel Id' | Export-Csv -Path $SummaryReport -Notype -Append
|
||
}
|
||
|
||
# Print Detailed Output
|
||
Function Print_DetailedReportContent {
|
||
$Result = @{'Team Name'=$TeamDisplayName; 'Channel Name'=$ChannelDisplayName; 'Membership Type'=$MembershipType; 'External Member Name'=$ExternalMemberName; 'External Member Email'=$ExternalMemberEmail; 'External Member Id'=$ExternalMemberGuid;}
|
||
$Results = New-Object PSObject -Property $Result
|
||
$Results | Select-Object 'Team Name', 'Channel Name', 'Membership Type', 'External Member Name', 'External Member Email', 'External Member Id'| Export-Csv -Path $DetailedReport -Notype -Append
|
||
}
|
||
|
||
# Connecting to the Microsoft Graph PowerShell Module
|
||
Connect_ToMgGraph
|
||
|
||
# Get all teams channels with external members in Microsoft 365
|
||
$ProcessedTeamsCount = 0
|
||
$TeamsChannelsWithExternalMembersCount = 0
|
||
$TenantId = ($Script:MgContext).TenantId
|
||
|
||
if (!([string]::IsNullOrEmpty($TeamName))) { $TeamFilter = "displayName eq '$($TeamName)'" }
|
||
|
||
if (!([string]::IsNullOrEmpty($ChannelName))) {
|
||
if (!([string]::IsNullOrEmpty($TeamName))) {
|
||
$ChannelFilter = "displayName eq '$($ChannelName)'"
|
||
}
|
||
else {
|
||
Write-Host "`nError: TeamName param is mandatory to filter based on Channels." -ForegroundColor Red
|
||
Exit
|
||
}
|
||
}
|
||
|
||
Get-MgTeam -Filter "$($TeamFilter)" -All | ForEach-Object {
|
||
$TeamId = $_.Id
|
||
$TeamDisplayName = $_.DisplayName
|
||
$ProcessedTeamsCount++
|
||
|
||
Get-MgTeamChannel -Filter "$($ChannelFilter)" -All -Team $TeamId | ForEach-Object {
|
||
$ChannelId = $_.Id
|
||
$ChannelDisplayName = $_.DisplayName
|
||
$MembershipType = $_.MembershipType
|
||
$ExternalMembersCount = 0
|
||
$ExternalMembers = @()
|
||
$ExternalUserFound = $false
|
||
Write-Progress -Activity "`n Processed Teams count: $ProcessedTeamsCount"`n" Processing Channel: $($ChannelDisplayName) from Team: $($TeamDisplayName)"
|
||
|
||
#Get-MgTeamChannelMember -All -Team $TeamId -Channel $ChannelId | ForEach-Object {
|
||
try {
|
||
(Invoke-MgGraphRequest -Method GET -Uri "/v1.0/teams/$($TeamId)/channels/$($ChannelId)/members" -ErrorAction Stop).value | ForEach-Object {
|
||
$ExternalMemberTenantId = $_.tenantId
|
||
if (($ExternalMemberTenantId -ne $TenantId) -or ($_.roles -contains "guest")) {
|
||
$ExternalMemberName = $_.displayName
|
||
$ExternalMemberEmail = $_.email
|
||
$ExternalMemberGuid = $_.userId
|
||
|
||
if (($MembershipType -notin @("standard","private"))) { $MembershipType = "shared" }
|
||
|
||
# Apply filters based on params
|
||
if (!([string]::IsNullOrEmpty($MemberUPN)) -and ($MemberUPN -ne $ExternalMemberEmail)) { return }
|
||
if (!([string]::IsNullOrEmpty($ChannelType)) -and ($ChannelType -ne $MembershipType)) { return }
|
||
|
||
$ExternalUserFound = $true
|
||
$ExternalMembersCount++
|
||
$ExternalMembers += $ExternalMemberEmail
|
||
Print_DetailedReportContent
|
||
}
|
||
}
|
||
if ($ExternalUserFound) {
|
||
$ExternalMembers = $ExternalMembers -join ", "
|
||
$TeamsChannelsWithExternalMembersCount++
|
||
Print_SummaryReportContent
|
||
}
|
||
|
||
}
|
||
catch {
|
||
Write-Host "Error occurred while fetching members for Channel: $($ChannelDisplayName) in Team: $($TeamDisplayName)."
|
||
}
|
||
}
|
||
}
|
||
# Disconnect from Microsoft Graph
|
||
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 1900+ Microsoft 365 reports. ~~" -ForegroundColor Green
|
||
|
||
# Open output file after execution
|
||
if((Test-Path -Path $DetailedReport) -eq "True") {
|
||
Write-Host `n"$TeamsChannelsWithExternalMembersCount teams channels are found with external members."
|
||
Write-Host `n" The summary report available in: " -NoNewline -ForegroundColor Yellow; Write-Host $SummaryReport
|
||
Write-Host `n" The detailed report available in: " -NoNewline -ForegroundColor Yellow; Write-Host $DetailedReport
|
||
$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 "$SummaryReport"
|
||
Invoke-Item "$DetailedReport"
|
||
}
|
||
}
|
||
else {
|
||
Write-Host `n"No teams channels are found with external members." -ForegroundColor Red
|
||
} |