In my last post I showed how to get SharePoint Online Site Collection Last Activity Date with Microsoft Graph API.
In this post I will demonstrate how to use last activity date and set site collection to Read Only -mode using SharePoint Online Site Policy Feature.
Create Site Policy and publish it to site collections from a Content Type Hub
First we need to create a Site Policy. You can create site policy for individual site collection at site collection level or all site collections in a Content Type Hub. I choose the later one and create site policies in a Content Type Hub.
SharePoint Online Content Type Hub can be found from address https://<tenantURL>/sites/ContentTypeHub.
There is a Site Policies -link in a Site Settings > Site Collection Administration.

In Site Policies you can create policy you like. I created policy which closes the site and deletes it after 3 years. When the site collection is closed it is set to read only mode.

After you have created the policy, you need to publish it to the site collections. This can be done clicking “manage publishing for this policy”.

In a Content Type Publishing Settings you can Publish, Unpublish or Republish your site policy to SharePoint Online site collections.

Activate Site Policy to site collection manually or using PowerShell
When you have created and published Site Policy in a Content Type Hub, you can use it in a Site Collection. You can activate Site Policy manually from Site Settings or you can use PnP PowerShell Set-PnPSitePolicy command to activate site policy with PowerShell.
Activate Site Policy manually
You can activate site policy to site collection from Site Settings. There is Site Closure and Deletion -link in Site Administration.
Note! If you don’t see Site Closure and Deletion in a Site Administration, the reason is that Site Policy Feature is not Activated on the site collection level. Go to Site Settings and Site collection features to Active Site Policy Feature.


Here you can see settings for Site Closure and Deletion. In picture below you can see that Site Policy named “Set site read only” was applied to the site collection and information message “This site is read only at the site collection administrator’s request” is displayed in top of the browser window.

Activate Site Policy using PnP PowerShell
I made PowerShell script for getting all Site Collection’s Last Activity Date from Graph API and then set Site Policy for site collection’s using Set-PnPSitePolicy command if site last activity date is older than 120 days.
Firsth we use Invoke-RestMethod to get SharePoint Site Collection usage details from Microsoft Graph API.
If Site’s Last Activity Date is older than 120 days and Site Template is Team Site or Group, we call function Set-SitePolicyPnP for activating the Site Policy named “ReadOnlyCTHubAuto” for the Site Collection.
#Get SharePoint site activity from Graph Api
$String = "https://graph.microsoft.com/beta/reports/getSharePointSiteUsageDetail`(`period=`'`D180`'`)?`$format=application/json"
$Results = Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Method Get -Uri $String
Write-Host "Number of sites found:" $Results.value.Count.ToString() -ForegroundColor Green
$Today = Get-Date
write-Host "Current date:" $Today
$ExpDate = $Today.AddDays(-120)
write-Host "Expiration date:" $ExpDate
$Results.value | Sort-Object -Property lastActivityDate | Select-Object -Property siteUrl, lastActivityDate, rootWebTemplate | ForEach-Object {
write-Host "------"
$_.siteUrl
write-Host "Last activity date:" $_.lastActivityDate
$_.rootWebTemplate
#If lastActivityDate is null or empty
if (!$_.lastActivityDate) {write-host "Last activity date not found" -ForegroundColor Yellow }
#If lastActivityDate is older than 120 days and site template is classic Team Site or Group
elseif(([datetime]$_.lastActivityDate -lt $ExpDate -and $_.rootWebTemplate -eq "Group") -or ([datetime]$_.lastActivityDate -lt $ExpDate -and $_.rootWebTemplate -eq "Team Site")) {
write-host "Site is out of the date" -ForegroundColor Red
write-host "Setting Site Policy with PnP" -ForegroundColor Blue
Set-SitePolicyPnP -siteUrl $_.siteUrl -rootWebTemplate $_.rootWebTemplate
}
#If lastActivityDate is newer than 30 days
elseif ([datetime]$_.lastActivityDate -ge $ExpDate) {write-host "Site is okay" -ForegroundColor Green }
}
Here is the Function to Setting the Site Policy with Set-PnPSitePolicy.
Note!: Because Group based Site Collection don’t have Site Policy Feature already activated, I made check for that and activate feature using Enable-PnPFeature -Identity 2fcd5f8a-26b7-4a6a-9755-918566dba90a (this is guide for SharePoint Site Policy feature).
function Set-SitePolicyPnP ($siteUrl, $rootWebTemplate)
{
#Connect to the site
$Connection = Connect-PnPOnline -Url $siteUrl -UseWebLogin
write-Host $siteUrl -ForegroundColor Blue
write-Host $rootWebTemplate -ForegroundColor Yellow
#check if site is based on Team Site or Group template then activate site policy feature
if (($rootWebTemplate -eq "Team Site") -or ($rootWebTemplate -eq "Group")) {
write-Host "Enabling feature and policy for site closure" -ForegroundColor Green
$SitePolicyFeatureActivated = ""
$SitePolicyFeatureActivated = Get-PnPFeature -Identity 2fcd5f8a-26b7-4a6a-9755-918566dba90a -Scope Site -Web $SiteUrl -Connection $Connection
$SitePolicyFeatureActivated = $SitePolicyFeatureActivated | Select-Object -Property DisplayName
if (!$SitePolicyFeatureActivated) {
write-Host "Site Policy feature is not activated" $SiteUrl -ForegroundColor Yellow
Enable-PnPFeature -Identity 2fcd5f8a-26b7-4a6a-9755-918566dba90a -Scope Site -Connection $Connection
write-Host "Site Policy feature now activated" $SiteUrl -ForegroundColor Green
$SitePolicyActivated = Get-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection | Select-Object -Property Name
if (!$SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto not found" $SiteUrl -ForegroundColor Yellow
write-Host "Site Policy ReadOnlyCTHubAuto has not been set" $SiteUrl -ForegroundColor Yellow
}
elseif ($SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto found" $SiteUrl -ForegroundColor Green
Set-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection
write-Host "Site Policy ReadOnlyCTHubAuto have been set" $SiteUrl -ForegroundColor Green
}
}
elseif ($SitePolicyFeatureActivated) {
write-Host "Site Policy feature is already activated" $SiteUrl -ForegroundColor Green
$SitePolicyActivated = Get-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection | Select-Object -Property Name
if (!$SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto not found" $SiteUrl -ForegroundColor Yellow
write-Host "Site Policy ReadOnlyCTHubAuto has not been set" $SiteUrl -ForegroundColor Yellow
}
elseif ($SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto found" $SiteUrl -ForegroundColor Green
Set-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection
write-Host "Site Policy ReadOnlyCTHubAuto have been set" $SiteUrl -ForegroundColor Green
}
}
}
}
Here is the whole script.
#Getting SharePoint Online last activity date and setting site policy for site
function Set-SitePolicyPnP ($siteUrl, $rootWebTemplate)
{
#Connect to the site
$Connection = Connect-PnPOnline -Url $siteUrl -UseWebLogin
write-Host $siteUrl -ForegroundColor Blue
write-Host $rootWebTemplate -ForegroundColor Yellow
#check if site is based on Team Site or Group template then activate site policy feature
if (($rootWebTemplate -eq "Team Site") -or ($rootWebTemplate -eq "Group")) {
write-Host "Enabling feature and policy for site closure" -ForegroundColor Green
$SitePolicyFeatureActivated = ""
$SitePolicyFeatureActivated = Get-PnPFeature -Identity 2fcd5f8a-26b7-4a6a-9755-918566dba90a -Scope Site -Web $SiteUrl -Connection $Connection
$SitePolicyFeatureActivated = $SitePolicyFeatureActivated | Select-Object -Property DisplayName
if (!$SitePolicyFeatureActivated) {
write-Host "Site Policy feature is not activated" $SiteUrl -ForegroundColor Yellow
Enable-PnPFeature -Identity 2fcd5f8a-26b7-4a6a-9755-918566dba90a -Scope Site -Connection $Connection
write-Host "Site Policy feature now activated" $SiteUrl -ForegroundColor Green
$SitePolicyActivated = Get-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection | Select-Object -Property Name
if (!$SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto not found" $SiteUrl -ForegroundColor Yellow
write-Host "Site Policy ReadOnlyCTHubAuto has not been set" $SiteUrl -ForegroundColor Yellow
}
elseif ($SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto found" $SiteUrl -ForegroundColor Green
Set-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection
write-Host "Site Policy ReadOnlyCTHubAuto have been set" $SiteUrl -ForegroundColor Green
}
}
elseif ($SitePolicyFeatureActivated) {
write-Host "Site Policy feature is already activated" $SiteUrl -ForegroundColor Green
$SitePolicyActivated = Get-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection | Select-Object -Property Name
if (!$SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto not found" $SiteUrl -ForegroundColor Yellow
write-Host "Site Policy ReadOnlyCTHubAuto has not been set" $SiteUrl -ForegroundColor Yellow
}
elseif ($SitePolicyActivated) {
write-Host "Site Policy ReadOnlyCTHubAuto found" $SiteUrl -ForegroundColor Green
Set-PnPSitePolicy -Name "ReadOnlyCTHubAuto" -Connection $Connection
write-Host "Site Policy ReadOnlyCTHubAuto have been set" $SiteUrl -ForegroundColor Green
}
}
}
}
#Get SharePoint site activity from Graph Api
$String = "https://graph.microsoft.com/beta/reports/getSharePointSiteUsageDetail`(`period=`'`D180`'`)?`$format=application/json"
$Results = Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Method Get -Uri $String
Write-Host "Number of sites found:" $Results.value.Count.ToString() -ForegroundColor Green
$Today = Get-Date
write-Host "Current date:" $Today
$ExpDate = $Today.AddDays(-120)
write-Host "Expiration date:" $ExpDate
$Results.value | Sort-Object -Property lastActivityDate | Select-Object -Property siteUrl, lastActivityDate, rootWebTemplate | ForEach-Object {
write-Host "------"
$_.siteUrl
write-Host "Last activity date:" $_.lastActivityDate
$_.rootWebTemplate
#If lastActivityDate is null or empty
if (!$_.lastActivityDate) {write-host "Last activity date not found" -ForegroundColor Yellow }
#If lastActivityDate is older than 120 days and site template is classic Team Site or Group
elseif(([datetime]$_.lastActivityDate -lt $ExpDate -and $_.rootWebTemplate -eq "Group") -or ([datetime]$_.lastActivityDate -lt $ExpDate -and $_.rootWebTemplate -eq "Team Site")) {
write-host "Site is out of the date" -ForegroundColor Red
write-host "Setting Site Policy with PnP" -ForegroundColor Blue
Set-SitePolicyPnP -siteUrl $_.siteUrl -rootWebTemplate $_.rootWebTemplate
}
#If lastActivityDate is newer than 30 days
elseif ([datetime]$_.lastActivityDate -ge $ExpDate) {write-host "Site is okay" -ForegroundColor Green }
}
Conclusions
Using Microsoft Graph API and PnP PowerShell commands you can do lot of automation in your SharePoint Online Tenant.
Many, many thanks for this! I was literally about to write something similar and stumbled across your wonderful post!
LikeLike
The “Site Policies” does not get listed in any settings / menu’s even though I am the global admin. What could be wrong here?
LikeLike
Hi, If you don’t see Site Closure and Deletion in a Site Administration, the reason is that Site Policy Feature is not Activated on the site collection level. Go to Site Settings and Site collection features to Active Site Policy Feature.
LikeLike