今年もよろしくお願いします。

2014年初めの投稿は、1月11日(土)に、日本マイクロソフト品川本社にて開催された第7回 Office 365 勉強会にて、お話をさせて頂いた内容の解説になります。当日は時間の都合上デモを中心に行いましたので、その仕組みの裏側を紹介します。

さて、SharePoint Online 上で共有するコンテンツを考えた時に、掲示板や予定表等の SharePoint Online の適した機能を組合わせていくわけですが、企業にはすでに様々な業務システムが導入されており、それらに蓄えられたデータ(の一部)を SharePoint Online でも共有したいというご要望は良く頂きます。それらのほとんどの業務システムは、データを CSV 形式で出力ができたり、データベースを直接参照することでデータを取り出すことができると思います。

そこで今回は、そのようにして取り出されたデータを PowerShell を用いて SharePoint Online にバッチ処理で定期的に自動投稿するというかたちでの連携シナリオを考えました。

PowerShell で SharePoint Online へデータを投稿するには?

PowerShell で SharePoint Online へデータを投稿する方法は、過去に投稿した下記の記事で紹介しています。

PowerShell + CSOM で SharePoint Online を操作する
http://idea.tostring.jp/?p=914

今回もこの方法を使って SharePoint Online へデータを投稿します。

データの準備とリストの作成

まずは、業務システムから取り出されるデータを確認しましょう。今回はあくまで想定として、下記のような単純な CSV が出力されることとしました。イメージとしては、営業成績のデータでしょうか。この時にどういったデータを出力ができるか?または、出力した後の整形をどうするか?が、実際の導入時にはポイントになってくると思います。

順位,社員名,実績,達成率
1,田中さん,5000,1.6
2,増田さん,4800,0.9
3,高橋さん,4200,0.8
4,佐藤さん,4000,0.72
5,太田さん,2500,0.5

さて、次に SharePoint Online 側にデータを格納するためのリストを作成します。今回はカスタム リストで「営業成績ランキング」というリストを作成し、下図のような列を作成しました。

20140111-1

また、それぞれの列内部名を下記の通り作成しています。

表示名 列内部名
社員名 Title
順位 myRank
実績 myResult
達成率 myPercentComplete

データを投稿してみる

これでデータを出入り口が整いましたので、それらを繋ぐ PowerShell を作成していきます。まずは全体像を。

#.NET CSOM モジュールの読み込み
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"

#コンテキスト作成や初期処理
$siteUrl = "https://tenant.sharepoint.com/sites/hogehoge"
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)

$accountName = "username@tenant.onmicrosoft.com"
$password = ConvertTo-SecureString -AsPlainText -Force "password"
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($accountName, $password)
$ctx.Credentials = $credentials

#リストの取得
$list = $ctx.Web.Lists.GetByTitle("営業成績ランキング")

#リストアイテム取得
$camlQuery = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100)
$colItems = $list.GetItems($camlQuery)
$ctx.Load($colItems)
$ctx.ExecuteQuery();

#アイテム削除処理の予約
for($index = $colItems.Count - 1; $index -gt -1; $index--){
	$colItems[$index].DeleteObject();
}

#データCSVの読み込み
$csv = Import-Csv "<Path>\file.csv"

#アイテム作成処理の予約
foreach($line in $csv){
	#アイテム作成の準備
	$itemCreateInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation

	#作成アイテムの情報設定
	$newItem = $list.AddItem($itemCreateInfo)
	$newItem["Title"] = $line.社員名
	$newItem["myRank"] = $line.順位
	$newItem["myResult"] = $line.実績
	$newItem["myPercentComplete"] = $line.達成率
	$newItem.Update();
}

#アイテム削除および作成処理の実行
$ctx.ExecuteQuery();

エラー処理を省いていますが、コメント行を入れて46行程度のボリュームです。簡単に解説をします。1行目から12行目までは、SharePoint Online へ接続するための定型的な処理です。

#.NET CSOM モジュールの読み込み
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"

#コンテキスト作成や初期処理
$siteUrl = "https://tenant.sharepoint.com/sites/hogehoge"
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)

$accountName = "username@tenant.onmicrosoft.com"
$password = ConvertTo-SecureString -AsPlainText -Force "password"
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($accountName, $password)
$ctx.Credentials = $credentials

15行目で事前に作成しておいたリストを取得し、17行目から26行目までで、既に投稿されているアイテム全削除の準備をします。

#リストの取得
$list = $ctx.Web.Lists.GetByTitle("営業成績ランキング")

#リストアイテム取得
$camlQuery = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100)
$colItems = $list.GetItems($camlQuery)
$ctx.Load($colItems)
$ctx.ExecuteQuery();

#アイテム削除処理の予約
for($index = $colItems.Count - 1; $index -gt -1; $index--){
	$colItems[$index].DeleteObject();
}

その後、29行目で CSV ファイルを読込んでおり、32行目からのループでアイテムを作成の準備をします。

#データCSVの読み込み
$csv = Import-Csv "<Path>\file.csv"

#アイテム作成処理の予約
foreach($line in $csv){
	#アイテム作成の準備
	$itemCreateInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation

	#作成アイテムの情報設定
	$newItem = $list.AddItem($itemCreateInfo)
	$newItem["Title"] = $line.社員名
	$newItem["myRank"] = $line.順位
	$newItem["myResult"] = $line.実績
	$newItem["myPercentComplete"] = $line.達成率
	$newItem.Update();
}

そして、最後の46行目の処理が実行されたタイミングで、SharePoint へクエリが送信されます。

#アイテム削除および作成処理の実行
$ctx.ExecuteQuery();

実はこれが SharePoint .NET CSOM の特徴で、それまでの処理は、クエリをビルドしているだけに過ぎず、クライアント コンテキストのExecuteQuery()が呼び出されたタイミングで、SharePoint へクエリが送信されることになります。そのため、この呼び出しを少なく抑えることがパフォーマンスへ大きく影響することになります。

ちなみに、21行目でもExecuteQuery()を呼び出していますが、これはその次の処理で、ListItemCollection のデータが必要となるため、SharePoint 側へデータ問合せのためにクエリを送信しています。

投稿された結果

さて、長くなりましたが、実行結果は下図のようになりました。

20140111-2

ただ、トップページに表示するには少しさびしいので、こちらも以前紹介した「JS リンク」などでカスタマイズを行ってみると良いかもしれません。

SharePoint 2013 「JS リンク」を試してみた
http://idea.tostring.jp/?p=68

カスタマイズを行ってみた例は下図です。今回のこのカスタマイズの詳細は割愛します。

20140111-3

さいごに

業務システムと SharePoint Online のあいだにクッションを挟むことで、比較的容易に SharePoint Online へ業務システムのデータを反映することができることを知って頂けたかと思います。SharePoint Online 上のポータルは、やはり業務で利用するものですから、定期的に更新される業務データが表示されるということは、それだけユーザーの閲覧する動機を強く保てると思います。また、SharePoint Online はインターネットにさえ接続ができれば、社外から閲覧することも容易です。さすがに業務システムのすべてのデータや機能を SharePoint Online へ載せることは難しいですが、サマリーのデータを社外から閲覧できるということは有効なシーンも多いかと思います。そのためにも、SharePoint 上で何のデータを共有・表示したいかを考えることが非常に重要になるかと思います。

また、今回の方法は、疎連携になっていることもポイントかと思います。アップグレードをユーザー側で自由にコントロールできない SharePoint Online では、こうした連携方法にしておくことでアップグレード時の影響を抑え、長期の運用を考えた場合はメリットが大きくなるのではないかと思います。

今回参加した Office 365 勉強会の内容は、下記の主催者さんのサイトに過去の分も含めまとめられています。定期的に開催されていますので、ご興味をお持ちの方は是非ご参加ください。

Office 365 勉強会
http://www.office365room.com/o365-meeting/

長くなりましたが、ご参考にして頂けたらと思います!