Skip to content

Commit 40465d6

Browse files
authored
Merge pull request #905 from ojopiyo/patch-11
Create README.md
2 parents b8e3787 + 5382978 commit 40465d6

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
2+
3+
# Site Collection Ownership Validation
4+
5+
## Summary
6+
7+
This script audits all SharePoint Online site collections in a Microsoft 365 tenant to validate site ownership. It identifies site collections that have **no owners**, **disabled owners**, or **guest-only owners**, helping administrators detect governance and operational risks across the tenant.
8+
9+
The output provides a clear, actionable dataset that can be used for remediation, reporting, or ongoing governance monitoring in large Microsoft 365 environments.
10+
11+
## Why It Matters / Real-World Scenario
12+
13+
In large tenants, SharePoint sites are frequently created through Teams, automation, or self-service processes. Over time, owners leave the organisation, accounts are disabled, or sites become orphaned.
14+
15+
Without a valid internal owner:
16+
- Access requests and security incidents cannot be actioned
17+
- Data retention and compliance requirements may be violated
18+
- External users may retain unmanaged access
19+
- IT teams become the default escalation point with no clear decision authority
20+
21+
This script enables proactive identification of these risks before they result in security, compliance, or operational issues.
22+
23+
## Benefits
24+
- Improves governance by enforcing clear ownership accountability
25+
- Reduces security and compliance risk across SharePoint and Teams-connected sites
26+
- Supports audits and compliance reviews with evidence-based reporting
27+
- Enables targeted remediation rather than blanket administrative ownership
28+
- Scales efficiently for large Microsoft 365 tenants
29+
30+
31+
# [PnP PowerShell](#tab/pnpps)
32+
33+
```powershell
34+
35+
# Prerequisites:
36+
# - PnP.PowerShell module
37+
# - Microsoft Graph permissions: User.Read.All, Directory.Read.All
38+
39+
Connect-PnPOnline -Url "https://<tenant>-admin.sharepoint.com" -Interactive
40+
41+
$tenantSites = Get-PnPTenantSite -IncludeOneDriveSites:$false
42+
$results = @()
43+
44+
foreach ($site in $tenantSites) {
45+
try {
46+
Connect-PnPOnline -Url $site.Url -Interactive -ErrorAction Stop
47+
$owners = Get-PnPSiteCollectionAdmin
48+
49+
$ownerDetails = foreach ($owner in $owners) {
50+
$user = Get-MgUser -UserId $owner.LoginName -ErrorAction SilentlyContinue
51+
52+
[PSCustomObject]@{
53+
DisplayName = $owner.Title
54+
UserPrincipalName = $owner.LoginName
55+
IsGuest = ($user.UserType -eq "Guest")
56+
IsDisabled = (-not $user.AccountEnabled)
57+
}
58+
}
59+
60+
$hasInternalActiveOwner = $ownerDetails | Where-Object {
61+
$_.IsGuest -eq $false -and $_.IsDisabled -eq $false
62+
}
63+
64+
if (-not $hasInternalActiveOwner) {
65+
$results += [PSCustomObject]@{
66+
SiteUrl = $site.Url
67+
SiteTitle = $site.Title
68+
OwnerCount = $ownerDetails.Count
69+
Owners = ($ownerDetails | Select-Object -ExpandProperty UserPrincipalName) -join "; "
70+
RiskReason = if ($ownerDetails.Count -eq 0) {
71+
"No owners assigned"
72+
} elseif ($ownerDetails.IsGuest -notcontains $false) {
73+
"Guest-only ownership"
74+
} else {
75+
"All owners disabled"
76+
}
77+
}
78+
}
79+
}
80+
catch {
81+
Write-Warning "Failed to process site: $($site.Url)"
82+
}
83+
}
84+
85+
$results
86+
87+
88+
89+
```
90+
91+
92+
# [Usage](#tab/usage)
93+
94+
1. Install required modules:
95+
96+
```powershell
97+
98+
Install-Module PnP.PowerShell
99+
Install-Module Microsoft.Graph
100+
101+
102+
```
103+
104+
2. Install required modules:
105+
- SharePoint Administrator role
106+
- Microsoft Graph permissions: **User.Read.All**, **Directory.Read.All**
107+
108+
3. Run the script from a secure admin workstation.
109+
110+
[!INCLUDE [More about PnP PowerShell](../../docfx/includes/MORE-PNPPS.md)]
111+
***
112+
113+
114+
## Output
115+
116+
The script returns a collection of objects containing:
117+
- Site URL
118+
- Site title
119+
- Owner count
120+
- Owner UPNs
121+
- Governance risk reason
122+
123+
This output can be:
124+
- Exported to CSV
125+
- Ingested into Power BI
126+
- Used as input for remediation automation
127+
128+
## Notes
129+
- Script excludes OneDrive sites by default
130+
- Designed to be read-only (no changes applied)
131+
- Suitable for scheduled execution (e.g. quarterly governance reviews)
132+
- Can be extended to auto-assign fallback owners if required
133+
134+
## Contributors
135+
136+
| Author(s) |
137+
|-----------|
138+
| [Josiah Opiyo](https://github.com/ojopiyo) |
139+
140+
*Built with a focus on automation, governance, least privilege, and clean Microsoft 365 tenants—helping M365 admins gain visibility and reduce operational risk.*
141+
142+
143+
## Version history
144+
145+
Version|Date|Comments
146+
-------|----|--------
147+
1.0|Dec 22, 2025|Initial release
148+
149+
150+
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
151+
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-site-collection-ownership-validation" aria-hidden="true" />
328 KB
Loading
58.7 KB
Loading
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
[
2+
{
3+
"name": "spo-site-collection-ownership-validation",
4+
"source": "pnp",
5+
"title": "Site Collection Ownership Validation",
6+
"shortDescription": "This script audits all SharePoint Online site collections in a Microsoft 365 tenant to validate site ownership.",
7+
"url": "https://pnp.github.io/script-samples/spo-site-collection-ownership-validation/README.html",
8+
"longDescription": [
9+
""
10+
],
11+
"creationDateTime": "2026-01-10",
12+
"updateDateTime": "2026-01-10",
13+
"products": [
14+
"SharePoint"
15+
],
16+
"metadata": [
17+
{
18+
"key": "PNP-POWERSHELL",
19+
"value": "3.1.0"
20+
}
21+
],
22+
"categories": [
23+
"Report"
24+
],
25+
"tags": [
26+
"Get-PnPTenantSite",
27+
"Get-PnPSiteCollectionAdmin"
28+
],
29+
"thumbnails": [
30+
{
31+
"type": "image",
32+
"order": 100,
33+
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/spo-site-collection-ownership-validation/assets/preview.png",
34+
"alt": "Preview of the sample Site Collection Ownership Validation"
35+
}
36+
],
37+
"authors": [
38+
{
39+
"gitHubAccount": "ojopiyo",
40+
"company": "",
41+
"pictureUrl": "https://github.com/ojopiyo.png",
42+
"name": "Josiah Opiyo"
43+
}
44+
],
45+
"references": [
46+
{
47+
"name": "Want to learn more about PnP PowerShell and the cmdlets",
48+
"description": "Check out the PnP PowerShell site to get started and for the reference to the cmdlets.",
49+
"url": "https://aka.ms/pnp/powershell"
50+
},
51+
{
52+
"name": "Want to learn more about Microsoft Graph PowerShell SDK and the cmdlets",
53+
"description": "Check out the Microsoft Graph PowerShell SDK documentation site to get started and for the reference to the cmdlets.",
54+
"url": "https://learn.microsoft.com/graph/powershell/get-started"
55+
}
56+
]
57+
}
58+
]

0 commit comments

Comments
 (0)