読者です 読者をやめる 読者になる 読者になる

からめもぶろぐ。

ワタシ SharePoint チョット デキル

PowerShell から SharePoint Online の REST API を叩いてみる

この記事は「PowerShell Advent Calendar 2016」の参加記事です。

qiita.com

前回の記事で「REST API を Invoke-RestMethod で叩けるかも」と丸投げなことを書いてしまったので、実際にやってみたいと思います。

blog.karamem0.jp

OAuth2 認証についておさらい

SharePoint Online の REST API を実行するには、Azure Active Directory (AAD) の OAuth2 認証が必要です。AAD ではアクセス トークンを取得するためにいくつかの方法 (grant_type) をサポートしています。

  • authorization_code (https://login.windows.net/common/oauth2/authorize)
  • client_credentials (X.509 証明書)
  • password (ユーザー名とパスワード、非推奨)
  • device_code (デバイス コード)

authorization_code については Web ブラウザーを使用するアプリケーション (Web アプリケーションやモバイル アプリケーション) が前提なので、PowerShell の場合はそれ以外の方法を選択することになります。password が最も簡単ですが非推奨なので除外して、実質的には device_code か client_credentials の二択になります。それぞれを簡単に比較すると以下の通りになります。

grant_type 手間 無人化
device_code 少ない 不可
client_credentials 多い

どちらもメリットとデメリットがありますので目的に応じて使い分けるのがいいと思います。今回は device_code による認証を行います。

試してみる

手順については松崎さんのブログを参照ください。

blogs.msdn.microsoft.com

アプリケーションの登録

現時点ではプレビュー段階ですが、新しい Azure 管理ポータルからも AAD のアプリ登録ができるようになりましたので、適当な名前で登録します。[リダイレクト URI] は使わないので http://localhost/ としています。

f:id:karamem0:20161215235141p:plain

使用する API に [Office 365 SharePoint Online] を選択します。

f:id:karamem0:20161215235152p:plain

アクセス許可を選択します。今回はサンプルなのでフル コントロールを付けていますが、適切なアクセス許可を選択してください。

f:id:karamem0:20161215235156p:plain

これで事前準備は完了です。

スクリプトの作成

github.com

C# だと WebClient や HttpClient を使って面倒な処理を書くことになりますが、PowerShell の場合は Invoke-RestMethod を使ってかなりすっきり書くことができます。

$tenantId = "<tenantid>"
$resourceUri = "<resourceuri>"
$clientId = "<clientid>"

# デバイス コードの取得
$uri = "https://login.microsoftonline.com/" + $TenantId + "/oauth2/devicecode?" + `
       "resource=" + [System.Uri]::EscapeDataString($resourceUri) + "&" + `
       "client_id=" + $clientId
$headers = @{
    "Accept" = "application/json"
}
$result = Invoke-RestMethod -Method "Get" -Uri $uri -Headers $headers

$userCode = $result.user_code
$deviceCode = $result.device_code

Write-Output $userCode
Start-Process "https://aka.ms/devicelogin"

Read-Host | Out-Null

# トークンの取得
$uri = "https://login.microsoftonline.com/" + $TenantId + "/oauth2/token"
$headers = @{ 
    "Accept" = "application/json"
    "Content-Type" = "application/x-www-form-urlencoded"
}
$body = "resource=" + [System.Uri]::EscapeDataString($resourceUri) + "&" + `
        "client_id=" + $clientId + "&" + `
        "grant_type=device_code&" + `
        "code=" + [System.Uri]::EscapeDataString($deviceCode)

$result = Invoke-RestMethod -Method "Post" -Uri $uri -Headers $headers -Body $body

$accessToken = $result.access_token

# サイトのタイトルを取得
$uri = $resourceUri + "/_api/web/title"
$headers = @{ 
    "Accept" = "application/json"
    "Authorization" = "Bearer " + $accessToken
}
$result = Invoke-RestMethod -Method "Get" -Uri $uri -Headers $headers
Write-Output $result.value

# ドキュメントの一覧を取得
$uri = $resourceUri + "/_api/web/getfolderbyserverrelativeurl('/Shared%20Documents')/files"
$headers = @{ 
    "Accept" = "application/json"
    "Authorization" = "Bearer " + $accessToken
}
$result = Invoke-RestMethod -Method "Get" -Uri $uri -Headers $headers
$result.value | select Name, TimeCreated, TimeLastModified

実行

実行するとプロンプトにコードが表示されます。認証が行われるまでスクリプトは入力待ち状態になっています。

f:id:karamem0:20161215235254p:plain

合わせてブラウザーが起動するので、コンソールに表示されたコードを入力します。

f:id:karamem0:20161215235302p:plain

アプリケーション名を確認して [続行] をクリックします。組織アカウントでのサインインを要求されますのでユーザー名とパスワードを入力します。

f:id:karamem0:20161215235311p:plain

サインインすると完了になります。ブラウザーは閉じても構いません。

f:id:karamem0:20161215235322p:plain

プロンプトで Enter キーをクリックするとスクリプトを再開します。SharePoint Online からサイトのタイトルとドキュメント ライブラリのファイルの一覧を取得できていることがわかります。

f:id:karamem0:20161215235329p:plain

まとめ

SharePoint Online 単体だと CSOM のほうが便利かもしれませんが、他の Office 365 サービスと連携する場合などは、REST API を使うと統一された方法で書くことができそうです。

おまけ

ちなみに、CSOM がどうやって SharePoint Online に認証をしているかというと、BPOSIDCRL という方式を使っているようです。BPOS の名前の通り、レガシーな方法なので、いつまでサポートされるんでしょうか。気になります。

RFC 6749 - The OAuth 2.0 Authorization Framework