Microsoft 365 Copilot Security Audit: PowerShell Script to Detect Overshared SharePoint Sites & Sensitive Data
How do you audit Microsoft 365 Copilot security before deployment? Microsoft 365 Copilot strictly inherits existing user permissions, which means any file accessible to a user can be indexed and summarized in seconds. To prevent data leakage, administrators must audit four primary oversharing vectors before licensing users: (1) “Everyone except external users” (EEEU) permissions on SharePoint document libraries, (2) Organization-wide and Anonymous sharing links, (3) Public Microsoft 365 Groups containing confidential data, and (4) Sites lacking Restricted Site Access (RSA) or Microsoft Purview sensitivity labels. Auditing is executed via PowerShell using PnP.PowerShell and Microsoft.Graph to export an actionable CSV risk register.
When enterprise leadership approves a rollout of Microsoft 365 Copilot ($30/user/month), the primary technical roadblock is almost never bandwidth, licensing, or client hardware. It is data governance and permission rot.
The fundamental design principle of Microsoft 365 Copilot is that it operates in the context of the authenticated user: Copilot can only summarize, index, and reveal information that the user already has permission to read. On paper, this sounds secure. In practice, it is a catastrophic vulnerability for organizations with years of unmanaged SharePoint Online sites.
In standard enterprise environments, users frequently share documents using “People in your organization” links, or administrators historically added Everyone except external users (EEEU) to site member groups to save time. Before Copilot, security through obscurity protected this data—nobody knew the confidential executive compensation spreadsheet was stored in a neglected department subsite. With Copilot, any employee can simply prompt: “Show me executive bonuses for Q3” or “Summarize upcoming restructuring plans,” and Copilot will surface and synthesize those files instantly.
In this production engineering runbook, we provide an end-to-end PowerShell security audit suite tested in active Microsoft 365 tenants, detail the exact configuration of SharePoint Restricted Site Access (RSA) policies, and supply a remediation roadmap to lock down oversharing before you assign your first Copilot license.
The Microsoft 365 Copilot Oversharing Threat Matrix
Before executing the PowerShell audit script, voice and cloud engineers must understand the four distinct data leakage vectors that Copilot exploits:
| Oversharing Vector | How Copilot Exploits It | Risk Severity | Remediation Standard |
|---|---|---|---|
| “Everyone except external users” (EEEU) | Any employee in the tenant can query confidential HR/Finance libraries via Copilot search grounding. | CRITICAL | Strip EEEU claims from site roles and document libraries via automated PowerShell. |
| Organization-Wide Sharing Links | Files shared via “People in your company” links get indexed into the Microsoft Graph semantic index for all internal users. | HIGH | Revoke tenant-wide sharing links; enforce “Specific people” as default sharing link type. |
| Public Microsoft 365 Groups | Teams channels created as “Public” allow any user to read conversations and indexed SharePoint files without joining. | HIGH | Convert sensitive Public M365 Groups to Private using Set-UnifiedGroup -AccessType Private. |
| Unlabeled Confidential Repositories | Sites without Microsoft Purview sensitivity labels lack automatic cryptographic protection or DLP export blocks. | MEDIUM | Apply mandatory sensitivity labels and enable SharePoint Restricted Site Access (RSA). |
Prerequisites & PowerShell Modules
To run a tenant-wide Copilot security audit, ensure your administrative workstation is equipped with modern PowerShell 7.4+ and the required modules:
# Install Required Modern Modules for M365 Copilot Audit
Install-Module -Name PnP.PowerShell -Scope CurrentUser -Repository PSGallery -Force
Install-Module -Name Microsoft.Graph.Authentication -Scope CurrentUser -Repository PSGallery -Force
Install-Module -Name Microsoft.Graph.Groups -Scope CurrentUser -Repository PSGallery -Force
Install-Module -Name Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser -Repository PSGallery -Force
You must have the SharePoint Administrator and Global Reader (or Global Administrator) roles assigned in Microsoft Entra ID to enumerate site permissions and Graph group memberships.
Production PowerShell Script: Microsoft 365 Copilot Security Audit
This automated PowerShell runbook scans every site collection across your tenant, flags domain-wide oversharing permissions, verifies external sharing policies, checks for Restricted Site Access (RSA) policy configuration, and generates an audit CSV report:
<#
.SYNOPSIS
Microsoft 365 Copilot Readiness & Oversharing Security Audit Suite.
.DESCRIPTION
Scans all SharePoint Online site collections for "Everyone except external users",
open sharing capabilities, public M365 Groups, and Restricted Site Access (RSA)
policies to prevent unauthorized data exposure through Copilot semantic search.
.AUTHOR
Satya Pathak (SkypeExchange4U.com)
.VERSION
2.4.0 (Production Hardened)
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$TenantAdminUrl = "https://contoso-admin.sharepoint.com",
[Parameter(Mandatory = $false)]
[string]$ReportPath = ".\M365-Copilot-Oversharing-Audit-Report-$((Get-Date).ToString('yyyyMMdd-HHmmss')).csv"
)
Write-Host "`n======================================================================" -ForegroundColor Cyan
Write-Host " MICROSOFT 365 COPILOT SECURITY & OVERSHARING AUDIT SUITE " -ForegroundColor Cyan
Write-Host "======================================================================`n" -ForegroundColor Cyan
# 1. Connect to SharePoint Online Admin
try {
Write-Host "[*] Connecting to SharePoint Online Admin ($TenantAdminUrl)..." -ForegroundColor Yellow
Connect-PnPOnline -Url $TenantAdminUrl -Interactive -WarningAction SilentlyContinue
Write-Host " [+] Connected successfully to SharePoint Online." -ForegroundColor Green
} catch {
Write-Error "Failed to connect to SharePoint Online. Verify admin permissions and URL."
return
}
# 2. Retrieve All Site Collections (Excluding System & App Catalog Sites)
Write-Host "[*] Querying all site collections across tenant..." -ForegroundColor Yellow
$Sites = Get-PnPTenantSite -Filter "Url -notlike '*/sites/appcatalog*' -and Url -notlike '*/personal/*'" | Where-Object { $_.Template -ne 'SRCHCEN#0' }
Write-Host " [+] Found $($Sites.Count) site collections for security evaluation.`n" -ForegroundColor Green
$AuditResults = [System.Collections.Generic.List[PSCustomObject]]::new()
$TotalSites = $Sites.Count
$Counter = 0
foreach ($Site in $Sites) {
$Counter++
$Percent = [math]::Round(($Counter / $TotalSites) * 100, 1)
Write-Progress -Activity "Auditing SharePoint Sites for Copilot Risks" -Status "[$Counter/$TotalSites] ($Percent%) Scanning: $($Site.Url)" -PercentComplete $Percent
$RiskFlags = [System.Collections.Generic.List[string]]::new()
$Severity = "LOW"
$HasEEEU = $false
$IsPublicGroup = $false
# Connect to Individual Site Collection
try {
$SiteConn = Connect-PnPOnline -Url $Site.Url -Interactive -ReturnConnection -WarningAction SilentlyContinue
} catch {
Write-Warning "Could not connect to site: $($Site.Url). Skipping permission deep-dive."
continue
}
# Vector 1: Check External Sharing Settings
$SharingCap = $Site.SharingCapability.ToString()
if ($SharingCap -in @("ExternalUserAndGuestSharing", "ExternalUserSharingOnly")) {
$RiskFlags.Add("ExternalSharingAllowed: $SharingCap")
}
# Vector 2: Inspect Site Permissions for "Everyone except external users" (EEEU)
try {
$RoleAssignments = Get-PnPProperty -ClientObject (Get-PnPWeb -Connection $SiteConn) -Property RoleAssignments -Connection $SiteConn
foreach ($Role in $RoleAssignments) {
$Member = Get-PnPProperty -ClientObject $Role -Property Member -Connection $SiteConn
$LoginName = $Member.LoginName
$Title = $Member.Title
# Flag EEEU or Everyone claims
if ($LoginName -like "*spo-grid-all-users/*" -or $Title -like "*Everyone except external users*" -or $Title -eq "Everyone") {
$HasEEEU = $true
$RiskFlags.Add("DomainWideAccess: '$Title' has site permissions")
$Severity = "CRITICAL"
}
}
} catch {
# Permission inspection warning
}
# Vector 3: Check Microsoft 365 Group Privacy (Public vs Private)
if ($Site.GroupId -and $Site.GroupId -ne [Guid]::Empty) {
try {
$GroupInfo = Get-PnPMicrosoft365Group -Identity $Site.GroupId -Connection $SiteConn
if ($GroupInfo.Visibility -eq "Public") {
$IsPublicGroup = $true
$RiskFlags.Add("PublicGroup: Any tenant user can browse and read content")
if ($Severity -ne "CRITICAL") { $Severity = "HIGH" }
}
} catch {
# Non-fatal group query skip
}
}
# Vector 4: Check SharePoint Restricted Site Access (RSA) Status
$RsaConfigured = $false
try {
$RsaInfo = Get-PnPSite -Includes RestrictedSharePointAccessInfo -Connection $SiteConn
if ($RsaInfo.RestrictedSharePointAccessInfo -and $RsaInfo.RestrictedSharePointAccessInfo.RestrictedAccessControlStatus -eq "Enabled") {
$RsaConfigured = $true
}
} catch {
$RsaConfigured = $false
}
if (-not $RsaConfigured -and $HasEEEU) {
$RiskFlags.Add("MissingRSA: Site lacks Restricted Site Access containment")
}
# Determine Severity Color for Terminal Output
$Color = switch ($Severity) {
"CRITICAL" { "Red" }
"HIGH" { "Yellow" }
"MEDIUM" { "Cyan" }
default { "DarkGray" }
}
if ($RiskFlags.Count -gt 0) {
Write-Host " [!][$Severity] $($Site.Url) -> $($RiskFlags -join ' | ')" -ForegroundColor $Color
}
# Add to Audit Collection
$AuditResults.Add([PSCustomObject]@{
SiteUrl = $Site.Url
SiteTitle = $Site.Title
Template = $Site.Template
SharingCapability = $SharingCap
HasDomainWideAccess = $HasEEEU
IsPublicGroup = $IsPublicGroup
RsaPolicyEnabled = $RsaConfigured
RiskSeverity = $Severity
DetectedRiskVectors = if ($RiskFlags.Count -gt 0) { $RiskFlags -join "; " } else { "None (Secure)" }
AuditTimestamp = (Get-Date).ToString("u")
})
}
# 3. Export Comprehensive CSV Audit Report
$AuditResults | Export-Csv -Path $ReportPath -NoTypeInformation -Encoding utf8
Write-Host "`n======================================================================" -ForegroundColor Green
Write-Host " AUDIT COMPLETE: $Counter sites evaluated." -ForegroundColor Green
Write-Host " CSV Report Exported: $ReportPath" -ForegroundColor Green
Write-Host "======================================================================`n" -ForegroundColor Green
# Print Executive Risk Summary
$CriticalCount = ($AuditResults | Where-Object { $_.RiskSeverity -eq 'CRITICAL' }).Count
$HighCount = ($AuditResults | Where-Object { $_.RiskSeverity -eq 'HIGH' }).Count
$SecureCount = ($AuditResults | Where-Object { $_.RiskSeverity -eq 'LOW' }).Count
Write-Host "Executive Copilot Security Summary:" -ForegroundColor White
Write-Host " [!] CRITICAL Overshared Sites (EEEU Detected) : $CriticalCount" -ForegroundColor Red
Write-Host " [!] HIGH Risk Sites (Public Groups / Open) : $HighCount" -ForegroundColor Yellow
Write-Host " [+] Secure / Restricted Sites : $SecureCount" -ForegroundColor Green
Remediation Strategy: How to Fix Oversharing Before Licensing Users
Once your audit report identifies high-risk repositories, execute this three-tiered remediation protocol to safeguard sensitive data:
Tier 1: Remove “Everyone Except External Users” (EEEU) Bulk Strip
In many enterprise sites, EEEU was mistakenly added to the Visitors or Members SharePoint group. Use this PowerShell snippet to surgically strip domain-wide claims without affecting legitimate user permissions:
# Bulk Remove "Everyone except external users" from a Targeted Site
$TargetSiteUrl = "https://contoso.sharepoint.com/sites/HumanResources"
Connect-PnPOnline -Url $TargetSiteUrl -Interactive
# Find and remove EEEU from Site Role Assignments
$RoleAssignments = Get-PnPProperty -ClientObject (Get-PnPWeb) -Property RoleAssignments
foreach ($Role in $RoleAssignments) {
$Member = Get-PnPProperty -ClientObject $Role -Property Member
if ($Member.Title -like "*Everyone except external users*" -or $Member.LoginName -like "*spo-grid-all-users/*") {
Write-Host "Stripping EEEU claim: $($Member.Title) from site role..." -ForegroundColor Yellow
Remove-PnPUser -Identity $Member.Id -Force
Write-Host "Successfully removed domain-wide access." -ForegroundColor Green
}
}
Tier 2: Implement SharePoint Restricted Site Access (RSA) Policies
Cleaning up 10 years of granular file-level permissions can take months. To prevent Copilot from leaking data immediately while permissions remediation is underway, Microsoft introduced SharePoint Restricted Site Access (RSA).
When RSA is enabled on a site, only members of a specified Microsoft Entra ID Security Group can access the site and have its content indexed by Microsoft 365 Copilot. Even if an employee has direct read permissions on a file, Copilot will ignore it if they are not in the RSA Security Group:
# Enable Restricted Site Access (RSA) using SharePoint Online Management Shell
Connect-SPOService -Url "https://contoso-admin.sharepoint.com"
# 1. Enforce Restricted Access Control on the Confidential Site
Set-SPOSite -Identity "https://contoso.sharepoint.com/sites/ExecutivePayroll" -RestrictedAccessControl $true
# 2. Bind the Site to a Designated Entra ID Security Group (Object ID)
Set-SPOSite -Identity "https://contoso.sharepoint.com/sites/ExecutivePayroll" `
-RestrictedAccessControlAllowedPrincipals "7a12b489-4e2a-4311-912f-981245ab78cd"
Write-Host "RSA Activated: Copilot will strictly ignore this site for all users outside the authorized group." -ForegroundColor Green
Tier 3: Convert Sensitive Public M365 Groups to Private
If your audit flags department channels (e.g., Legal, Mergers & Acquisitions, Payroll) configured as Public Teams, convert them immediately via Microsoft Graph or Exchange Online PowerShell:
# Connect to Exchange Online PowerShell
Connect-ExchangeOnline
# Convert Public M365 Group to Private
Set-UnifiedGroup -Identity "LegalTeam" -AccessType "Private"
Write-Host "Group converted to Private. Non-members can no longer index conversations or SharePoint files via Copilot." -ForegroundColor Green
Related Microsoft 365 & PowerShell Automation Guides
To build a secure, automated Microsoft 365 and enterprise voice infrastructure, explore our related runbooks:
- Microsoft 365 & Entra ID PowerShell Automation Runbook — Automate user onboarding, dormant license cleanup, and security health checks.
- Teams Direct Routing Calls Dropping After 30 Seconds: SIP ACK Fix — Resolve asymmetric firewall routing, Contact header NAT leaks, and RFC 3261 timer drops.
- Teams Direct Routing SIP 488 Not Acceptable Here Fix — Resolve SRTP encryption mismatches, G.729 codec negotiation failures, and Media Bypass ICE errors.
- Microsoft 365 Tenant-to-Tenant Migration Runbook — Architecture plan for domain cutover, cross-tenant identity sync, and mailbox transitions.
- Exchange Online PowerShell in 2026: The Commands You Actually Need — Master modern Exchange REST cmdlets, message tracing, and mailbox permission audits.
Need to Quarantine a Sensitive Site from Copilot? Enforce perimeter security using our step-by-step runbook: Restricting Microsoft 365 Copilot from Sensitive SharePoint Sites: PowerShell & Restricted Access Control (RSA) Guide.
Frequently Asked Questions (FAQ)
Can Microsoft 365 Copilot access private or restricted SharePoint files?
No. Microsoft 365 Copilot strictly enforces the existing security permissions of the user issuing the prompt. If a user does not have read access to a document or SharePoint site, Copilot cannot index, summarize, or reveal that content. However, if a document was mistakenly shared using domain-wide permissions (such as Everyone except external users), Copilot will treat it as accessible and summarize it upon request.
What is SharePoint Restricted Site Access (RSA) and how does it protect Copilot?
SharePoint Restricted Site Access (RSA) is an administrative policy (configured via Set-SPOSite -RestrictedAccessControl $true) that restricts site access and Copilot semantic indexing strictly to members of a designated Microsoft Entra ID Security Group. Even if an unauthorized employee holds direct or inherited sharing link permissions to a file, RSA blocks Copilot from indexing the site content for that user.
How do I identify which SharePoint sites are overshared before deploying Copilot?
You can execute our automated PowerShell audit script using PnP.PowerShell to scan all site collections across your tenant. The script inspects role assignments for spo-grid-all-users (Everyone except external users), identifies Public Microsoft 365 Groups holding sensitive data, checks external sharing policies, and exports a prioritized CSV risk matrix.