SharePoint サイトの分類ソリューションを実装する
注:
SharePoint Online サイトの分類については、「SharePoint の ”モダン” サイトの分類」を参照してください。
適切なガバナンスを行っていても、SharePoint サイトが急成長して、制御不可能に拡大することがあります。 サイトは必要に応じて作成されますが、削除されることはまれです。 検索クロールは未使用のサイト コレクションに阻まれ、検索は古くて関連性のない結果を返します。 サイトの分類を使用すれば、機密データを識別して保持することができます。
この記事では、Core.SiteClassification サンプルを使用してサイトの分類ソリューションを実装し、SharePoint サイト ポリシーを使用して削除を強制する方法を示します。 このソリューションを既存のサイト プロビジョニング ソリューションに統合することにより、サイトをより良く管理することができます。
はじめに
まず、Core.SiteClassification サンプルを、GitHub 上の Office 365 Developer パターンおよびプラクティス プロジェクトからダウンロードします。
注:
この記事で提供されるコードは、明示または黙示のいかなる種類の保証なしに現状のまま提供されるものであり、特定目的への適合性、商品性、権利侵害の不存在についての暗黙的な保証は一切ありません。
サイト ポリシーの定義と設定
最初に、すべてのサイト コレクションで利用できるようにするサイト ポリシーを定義して設定する必要があります。 Core.SiteClassification サンプルは SharePoint Online MT に適用されますが、SharePoint Online 専用または SharePoint オンプレミスでも使用できます。 サイト ポリシーはコンテンツ タイプ ハブで設定します。SharePoint Online MT では https://[tenantname]/sites/contentTypeHub
に配置されています。
サイト ポリシーを設定するには、[設定]>[サイト コレクション管理]>[サイト ポリシー]>[作成] に移動します。 [新しいサイト ポリシー] ページが表示されます。 サイト ポリシー オプションの詳細については、「SharePoint Server のサイト ポリシーの概要」を参照してください。
[新しいサイト ポリシー] ページで、次に示すフィールドに情報を入力します。
名前: HBI
説明: これはトップ シークレットです。
[サイトを自動的に削除する] ラジオ ボタンを設定します。
[削除イベント:] は、サイトの作成日 + 1 年を使用します。
[削除までの残りが次の値になったら、サイトの所有者に電子メール通知を送信します:] チェック ボックスをオンにして、1 か月に設定します。
[次の間隔でフォロー アップ通知を送信します:] チェック ボックスをオンにして、14 日間に設定します。
[所有者は間近に迫った削除を次の期間だけ延長できます]: チェック ボックスをオンにして、1 か月に設定します。
[サイト コレクションを閉じると読み取り専用になります] チェック ボックスをオンにします。
名前の MBI と LBI に対して、これらの手順をあと 2 回繰り返します。 削除ポリシーまたは保持ポリシー用の複数の設定を使用します。 完了したら、新しいポリシーを発行することができます。
カスタム アクションの挿入
サイトの分類用のカスタム アクションを [設定]ページと SharePoint 歯車アイコンに挿入することができます。 このアクションは、ManageWeb アクセス許可を持っているユーザーのみが使用できます。 詳細については、「既定のカスタム アクションの場所と ID」を参照してください。
/// <summary>
/// Adds a custom Action to a Site Collection.
/// </summary>
/// <param name="ctx">The Authenticated client context.</param>
/// <param name="hostUrl">The provider-hosted URL for the application</param>
static void AddCustomAction(ClientContext ctx, string hostUrl)
{
var _web = ctx.Web;
ctx.Load(_web);
ctx.ExecuteQuery();
// You only want the action to show up if you have manage web permissions.
BasePermissions _manageWebPermission = new BasePermissions();
_manageWebPermission.Set(PermissionKind.ManageWeb);
CustomActionEntity _entity = new CustomActionEntity()
{
Group = "SiteTasks",
Location = "Microsoft.SharePoint.SiteSettings",
Title = "Site Classification",
Sequence = 1000,
Url = string.Format(hostUrl, ctx.Url),
Rights = _manageWebPermission,
};
CustomActionEntity _siteActionSC = new CustomActionEntity()
{
Group = "SiteActions",
Location = "Microsoft.SharePoint.StandardMenu",
Title = "Site Classification",
Sequence = 1000,
Url = string.Format(hostUrl, ctx.Url),
Rights = _manageWebPermission
};
_web.AddCustomAction(_entity);
_web.AddCustomAction(_siteActionSC);
}
カスタム サイト分類
[サイト情報の編集] ページを使用すると、以下の特定の分類オプションを選択できます。
対象ユーザーのスコープ:[エンタープライズ]、[組織]、または [チーム] に設定します。
セキュリティ分類:[LBI] などの、入力された分類カテゴリのいずれかに設定します。
有効期限: 以前に入力した分類に基づいて既定の有効期限を上書きします。
対象ユーザーの到達範囲とサイトの分類の両方が検索可能であり、クロールの実行後に、管理対象プロパティがそれらに関連付けられます。 これらのプロパティを使用すれば、サイト コレクション内のカスタム非表示リストを使用して、特定の種類のサイトを検索することができます。 このリストは、SiteManagerImpl クラスの Core.SiteClassification.Common プロジェクトに実装されます。
private void CreateSiteClassificationList(ClientContext ctx)
{
var _newList = new ListCreationInformation()
{
Title = SiteClassificationList.SiteClassificationListTitle,
Description = SiteClassificationList.SiteClassificationDesc,
TemplateType = (int)ListTemplateType.GenericList,
Url = SiteClassificationList.SiteClassificationUrl,
QuickLaunchOption = QuickLaunchOptions.Off
};
if(!ctx.Web.ContentTypeExistsById(SiteClassificationContentType.SITEINFORMATION_CT_ID))
{
// Content type.
ContentType _contentType = ctx.Web.CreateContentType(SiteClassificationContentType.SITEINFORMATION_CT_NAME,
SiteClassificationContentType.SITEINFORMATION_CT_DESC,
SiteClassificationContentType.SITEINFORMATION_CT_ID,
SiteClassificationContentType.SITEINFORMATION_CT_GROUP);
FieldLink _titleFieldLink = _contentType.FieldLinks.GetById(new Guid("fa564e0f-0c70-4ab9-b863-0177e6ddd247"));
titleFieldLink.Required = false;
contentType.Update(false);
// Key field.
ctx.Web.CreateField(SiteClassificationFields.FLD_KEY_ID,
SiteClassificationFields.FLD_KEY_INTERNAL_NAME,
FieldType.Text,
SiteClassificationFields.FLD_KEY_DISPLAY_NAME,
SiteClassificationFields.FIELDS_GROUPNAME);
// Value field.
ctx.Web.CreateField(SiteClassificationFields.FLD_VALUE_ID,
SiteClassificationFields.FLD_VALUE_INTERNAL_NAME,
FieldType.Text,
SiteClassificationFields.FLD_VALUE_DISPLAY_NAME,
SiteClassificationFields.FIELDS_GROUPNAME);
// Add Key field to content type.
ctx.Web.AddFieldToContentTypeById(SiteClassificationContentType.SITEINFORMATION_CT_ID,
SiteClassificationFields.FLD_KEY_ID.ToString(),
true);
// Add Value field to content type.
ctx.Web.AddFieldToContentTypeById(SiteClassificationContentType.SITEINFORMATION_CT_ID,
SiteClassificationFields.FLD_VALUE_ID.ToString(),
true);
}
var _list = ctx.Web.Lists.Add(_newList);
list.Hidden = true;
list.ContentTypesEnabled = true;
list.Update();
ctx.Web.AddContentTypeToListById(SiteClassificationList.SiteClassificationListTitle,
SiteClassificationContentType.SITEINFORMATION_CT_ID, true);
this.CreateCustomPropertiesInList(_list);
ctx.ExecuteQuery();
this.RemoveFromQuickLaunch(ctx, SiteClassificationList.SiteClassificationListTitle);
}
既定で、追加設定なしで、または、CSOM を使用してリストを作成すると、[新着順] メニューでリストが使用できます。 ただし、リストは非表示にする必要があります。 次のコードは、[新着順] メニューから項目を削除します。
private void RemoveFromQuickLaunch(ClientContext ctx, string listName)
{
Site _site = ctx.Site;
Web _web = _site.RootWeb;
ctx.Load(_web, x => x.Navigation, x => x.Navigation.QuickLaunch);
ctx.ExecuteQuery();
var _vNode = from NavigationNode _navNode in _web.Navigation.QuickLaunch
where _navNode.Title == "Recent"
select _navNode;
NavigationNode _nNode = _vNode.First<NavigationNode>();
ctx.Load(_nNode.Children);
ctx.ExecuteQuery();
var vcNode = from NavigationNode cn in _nNode.Children
where cn.Title == listName
select cn;
NavigationNode _cNode = vcNode.First<NavigationNode>();
_cNode.DeleteObject();
ctx.ExecuteQuery();
}
Core.SiteClassification サンプルは、サイト管理者またはアクセス許可を持つ他のユーザーが新しいリストを削除する可能性に備えています。 このページがアクセスを受けるとリストが再作成されますが、サンプルはプロパティを元に戻しません。 サンプルを拡張してリストのアクセス許可を変更し、サイト コレクション管理者のみがアクセスできるようにすれば、この事態を回避できます。 または、Core.SiteEnumeration PnP サンプルを使用して、リストでチェックを実行し、サイト管理者に適宜通知することもできます。
リスト検証チェックは、SiteManagerImpl クラスの Initialize メンバーでも実装できます。
internal void Initialize(ClientContext ctx)
{
try {
var _web = ctx.Web;
var lists = _web.Lists;
ctx.Load(_web);
ctx.Load(lists, lc => lc.Where(l => l.Title == SiteClassificationList.SiteClassificationListTitle));
ctx.ExecuteQuery();
if (lists.Count == 0) {
this.CreateSiteClassificationList(ctx);
}
}
catch(Exception _ex)
{
}
}
}
注:
詳細については、「SharePoint アドインのインストール時にホスト Web でリストを作成し、最新のコンテンツ リストから削除する」を参照してください。
サイト ページへの分類インジケーターの追加
サイト ページにその分類を示すインジケーターを追加できます。 Core.SiteClassification サンプルは、分類を示す画像をサイトのタイトルの横に埋め込む方法を示しています。 以前のバージョンの SharePoint では、これがサーバー側の委任コントロール経由で実行されます。 JavaScript でカスタム マスター ページを使用できますが、このサンプルでは組み込みの JavaScript パターンを使用します。 [サイト情報の編集] ページで [サイト ポリシー] を変更すると、サイトの分類オプションごとに背景色が異なる小さなボックスを表示するようにサイト インジケーターが変更されます。
次のメソッドが、Core.SiteClassification Web プロジェクト、スクリプト、classifier.js で定義されています。 このイメージは Microsoft Azure Web サイトに格納されます。 環境に合わせてハード コーディングされた URL に変更する必要があります。
function setClassifier() {
if (!classified)
{
var clientContext = SP.ClientContext.get_current();
var query = "<View><Query><Where><Eq><FieldRef Name='SC_METADATA_KEY'/><Value Type='Text'>sc_BusinessImpact</Value></Eq></Where></Query><ViewFields><FieldRef Name='ID'/><FieldRef Name='SC_METADATA_KEY'/><FieldRef Name='SC_METADATA_VALUE'/></ViewFields></View>";
var list = clientContext.get_web().get_lists().getByTitle("Site Information");
clientContext.load(list);
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(query);
var listItems = list.getItems(camlQuery);
clientContext.load(listItems);
clientContext.executeQueryAsync(Function.createDelegate(this, function (sender, args) {
var listItemInfo;
var listItemEnumerator = listItems.getEnumerator();
while (listItemEnumerator.moveNext()) {
listItemInfo = listItemEnumerator.get_current().get_item('SC_METADATA_VALUE');
var pageTitle = $('#pageTitle')[0].innerHTML;
if (pageTitle.indexOf("img") > -1) {
classified = true;
}
else {
var siteClassification = listItemInfo;
if (siteClassification == "HBI") {
var img = $("<a href='http://insertyourpolicy' target=_blank><img id=classifer name=classifer src='https://spmanaged.azurewebsites.net/content/img/hbi.png' title='Site contains personally identifiable information (PII), or unauthorized release of information on this site would cause severe or catastrophic loss to Contoso.' alt='Site contains personally identifiable information (PII), or unauthorized release of information on this site would cause severe or catastrophic loss to Contoso.'></a>");
$('#pageTitle').prepend(img);
classified = true;
}
else if (siteClassification == "MBI") {
var img = $("<a href='http://insertyourpolicy' target=_blank><img id=classifer name=classifer src='https://spmanaged.azurewebsites.net/content/img/mbi.png' title='Unauthorized release of information on this site would cause severe impact to Contoso.' alt='Unauthorized release of information on this site would cause severe impact to Contoso.'></a>");
$('#pageTitle').prepend(img);
classified = true;
}
else if (siteClassification == "LBI") {
var img = $("<a href='http://insertyourpolicy' target=_blank><img id=classifer name=classifer src='https://spmanaged.azurewebsites.net/content/img/lbi.png' title='Limited or no impact to Contoso if publically released.' alt='Limited or no impact to Contoso if publically released.'></a>");
$('#pageTitle').prepend(img);
classified = true;
}
}
}
}));
}
別の方法
OfficeDevPnP.Core の ObjectPropertyBagEntry.cs ファイルの拡張メソッド Web.AddIndexedPropertyBagKey を使用すると、リストではなく、サイト プロパティ バッグに分類値を格納できます。 このメソッドを使用すると、プロパティ バッグをクロール対象または検索可能にできます。