💻

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

2022/01/01に公開

はじめに

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

https://qiita.com/advent-calendar/2016/powershell

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

https://zenn.dev/karamem0/articles/2016_12_10_000000

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 を選択します。

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

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

スクリプトの作成

WebClientHttpClient を使わなければならない 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