SharePoint Online の REST API を PowerShell から叩いてみる
はじめに
この記事は PowerShell Advent Calendar 2016 の参加記事です。
前回の記事で「REST API を Invoke-RestMethod
で叩けるかも」と丸投げなことを書いてしまったので、実際にやってみます。
OAuth についておさらい
SharePoint Online の REST API を実行するには、Azure AD の OAuth によるアクセス許可が必要です。Azure AD ではアクセス トークンを取得するためにいくつかの認可フローをサポートしています。
- Authorization Code Grant
- Implicit Grant
- Client Credentials Grant
- 共有シークレット
- 証明書
- Resource Owner Password Credentials Grant
- Device Flow
Authorization Code と Implicit Grant については UI (Web ブラウザー) を使用するアプリケーションが前提です。そのため PowerShell の場合はそれ以外の方法を選択することになります。その他の方法を簡単に比較すると以下の通りになります。
認可フロー | アクセス許可 | 難易度 | 無人化 | セキュリティ |
---|---|---|---|---|
Client Credentials (共有シークレット) | アプリケーション | 低 | 可 | 低 |
Client Credentials (証明書) | アプリケーション | 高 | 可 | 高 |
Device Flow | ユーザー | 中 | 不可 | - |
どちらもメリットとデメリットがありますので目的に応じて使い分ける必要があります。今回は Device Flow を使って認証します。
実行手順
アプリケーションの登録
Azure 管理ポータルから Azure AD のアプリケーションを適当な名前で登録します。
使用する API に Office 365 SharePoint Online を選択します。
アクセス許可を選択します。今回はサンプルなのでフル コントロールを付けていますが、適切なアクセス許可を選択してください。
これで事前準備は完了です。
スクリプトの作成
WebClient
や HttpClient
を使わなければならない C# と異なり PowerShell の場合は Invoke-RestMethod
を使ってかなりすっきり書くことができます。
$tenantId = "{{tenant-id}}"
$resourceUri = "{{resource-uri}}"
$clientId = "{{client-id}}"
# デバイス コードの取得
$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
実行結果
実行するとプロンプトにコードが表示されます。認証が行われるまでスクリプトは入力待ち状態になっています。合わせてブラウザーが起動するので、コンソールに表示されたコードを入力します。
アプリケーション名を確認して 続行 をクリックします。組織アカウントでのサインインを要求されますのでユーザー名とパスワードを入力します。
サインインすると完了になります。ブラウザーは閉じても構いません。
プロンプトで Enter キーをクリックするとスクリプトを再開します。SharePoint Online からサイトのタイトルとドキュメント ライブラリのファイルの一覧を取得します。
おわりに
SharePoint Online 単体だと CSOM のほうが便利ですが、他の Office 365 サービスと連携する場合などは、REST API を使うと統一された方法で書くことができそうです。
ちなみに、CSOM がどうやって SharePoint Online に認証をしているかというと、BPOSIDCRL
という方式を使っているようです。BPOS の名前の通り、レガシーな方法なので、いつまでサポートされるんでしょうか。気になります。
Discussion