For a site lifecycle scenario we need to set a site collection to read-only. In the (good) old world with SharePoint on-premise that was a simple task. Because we are working with Office 365 and SharePoint Online, it is a little bit difficult, because we want a very high grade on automation.

First of all, there is no PowerShell cmdlet or anything in the client object model that would enable us to directly set a site collection to read-only. But, we have something in SharePoint that is called Site Policy. Such a policy applied to the root web of a site collection could set the state of the site collection to read-only, when the site is closed. Could be a simple workaround, but creating a site policy by code does not seem to be possible in SharePoint Online. But on the other hand, applying a site policy to a site could be done with classes and methods from the client object model. Does that make sense? Not for me.

Looking behind the scenes of a site policy (and reading other articles from Microsoft), a site policy is nothing else than a content type that is created in the web. First idea was to create this content type by code. The client object model has classes and methods to do that, but the configuration of the site policy is stored in the XmlDocument member of the content type and this member could not be set using CSOM or the Rest endpoint. Thanks a lot for making this happen.

Ok, saying goodbye from creating the site policy by code, we still need to create the site policy (or its content type) automatically, when the site collection is created. Publishing content types is one of the main tasks of the Content Type Hub in SharePoint. Having SharePoint Online, the Content Type Hub is automatically made available, when the tenant is created at https://tenantname.sharepoint.com/sites/contenttypehub. So, let’s create the site policy in the site collection of the Content Type Hub.

This will create the content type “Mark Readonly Tester” in this site collection. The content type is hidden by default, so we are not able to do anything via the web ui.

Next create a new site collection in the tenant. Could be a simple Team Site. When this site collection is created, switch to Site Settings and the Site Policy page (found in Site Collection Administration). And what do we see? No site policy. Investigating with the SharePoint Client Browser (many thanks to Bram de Jager!), the content type of the site policy was not published to our new site collection. Perfect, next problem to solve.

I did some really dirty stuff with this content type, and I do not know, whether it is supported by Microsoft, but after making the changes with the following client side code (that makes use of the Office 365 PnP Core), the content type for the site policy was published to a newly created site collection.

Web web = ctx.Web;
ContentType ct = web.GetContentTypeByName(contentTypeName);
FieldCollection fields = ct.Fields;
FieldLinkCollection fieldLinks = ct.FieldLinks;

ctx.Load(web);
ctx.Load(ct);
ctx.Load(fields);
ctx.Load(fieldLinks);
ctx.ExecuteQueryRetry();

ct.Hidden = false;
ct.Group = contentTypeGroup;

foreach (Field field in fields)
{
    field.Hidden = false;
    field.Update();
}

foreach (FieldLink fieldLink in fieldLinks)
{
    fieldLink.Hidden = false;
}

ct.Update(true);

web.AddFieldToContentTypeByName(contentTypeName, new Guid("{9ebcd900-9d05-46c8-8f4d-e46e87328844}")); // field: Categories

web.Update();
ctx.ExecuteQueryRetry();

When a new site collection is created, we can see the site policy in the site settings of the site collection.

When we switch to the Site Closure and Delection page in the Site Administration of the site settings, we can select the site policy.

And when this policy is selected and the site will be closed, the read-only setting will do what it should.

The same result we can get by running this short piece of code that we will now can use in our site lifecycle scenario to set a site collection to read-only.

Web web = ctx.Web;
web.ApplySitePolicy("Mark Readonly Tester");
web.Update();
ctx.ExecuteQueryRetry();

ProjectPolicy.CloseProject(ctx, web);
ctx.ExecuteQueryRetry();

Once again, actually I do not know, whether this is a supported scenario or not, but it will solve the problem to deploy a site policy to a new site collection.

 

Advertisements