DEV Community

Kohei Ogawa | 書家
Kohei Ogawa | 書家

Posted on • Updated on • Originally published at zenn.dev

How to read files on SharePoint Online using Azure Data Factory/Azure Synapse Pipeline(.jp) - supplement

Azure Data Factory/Azure Synapse Pipelineは、Cloud上のSparkクラスターで膨大なデータをD&DのGUIベースで設計し、処理することができます。

この記事の対象者は、Azure Data Factoy(Synapse Pipeline)でアクティビティを用いてパイプライン実行をしたことがある方を対象としております。そうでいない方は、以下の記事をご参考ください。

はじめに

 実装したいことはシンプルで、SharePoint上にあるフォルダを対象に複数ファイルをAzure Blob Storageにコピーすることです。この一連の流れはSharePointヘビーユーザ企業には需要があることは確認されており、インターネット上でチャレンジしては、エラーを出力され、問題が解決されていない掲示板の声は多いです。
 Microsoftはこの一連の流れを記事にしており、参考に実装を勧めたが、つまづくポイントが多く、表記ゆれや最後まで説明されていない箇所が存在した。特に、ファイル名がランダムな文字列となり、予期した挙動にならなかった。
 そこで、本記事では日本語スピーカーを対象にMicrosoftが公開しているTechCommunityの資料の補助として情報を残します。

▼Microsoft Tech Communityが公開している記事

https://techcommunity.microsoft.com/t5/azure-data-factory-blog/sharepoint-online-multiple-files-folder-copy-with-http-connector/ba-p/2480426

本記事に関するリソース

Azure Data Factoryのソース管理機能に基づいて、リポジトリが構成されております。

メンテナンス中
▼本記事の内容を実装したソースコード
https://github.com/hogaku/sharepoint_in_adf
▼本記事で仕様したテストデータ(githubリポジトリ上にあり)
本記事で仕様したテストデータ
▼MSTechCommunityの記事(本記事の被補助記事)
https://techcommunity.microsoft.com/t5/azure-data-factory-blog/sharepoint-online-multiple-files-folder-copy-with-http-connector/ba-p/2480426

手法

以下に示す3ステップにより実現します。

  1. Webアクティビティを用いて、SharePointOnlineからアクセストークンを取得します(アクティビティ名:Web1)。
  2. 2つ目のWebアクティビティを用意し、SPO上のフォルダからファイルの一覧を取得(アクティビティ名:Web2)
  3. ForEachアクティビティとデータのコピーアクティビティを用いて、フォルダ内のファイルリストをループし、随時、データをコピー(SharePoint→Azure Blob Storage)(ForEachアクティビティ名:ForEach1, データのコピーアクティビティ名:CopyData1)。 全体のパイプラインフロー Fig.1 全体のパイプラインフロー ForEachアクティビティの内部アクティビティ Fig.2 ForEachアクティビティの内部アクティビティ

Step1: Grab Access token from SPO(SPOからのアクセストークンの取得)

こちらのStepでは、SharePointAPIを利用してファイルを取得するために、AADアプリの登録と登録したアプリからのSharePointサイトへのアクセス許可するための手続きを行います。初めての方は用心深くなるかもしれませんが、示されている通りに手順を踏めば特に問題ないでしょう。一応、軽く示します。

「a) AAD アプリケーションの登録」に関して

  1. まずはこちらのAzure PortalのMicrosoft|アプリの登録へアクセスし、[+新規登録]ボタンをクリック後、↓のリンクへアクセスし、アプリケーションの登録を行いましょう。

▼アプリケーションを Azure AD テナントに登録する
※MSTechCommunityの記事では、英語の記事がリンクとして掲載されているため、改めて、日本語ページを掲載しておきます。
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-auth-aad-app?tabs=dotnet#register-your-application-with-an-azure-ad-tenant

2.次にこのように項目を埋めてください(一番上の名前の部分は適当につけてください。アプリのリストの画面で表示されます)。

アプリケーションの登録画面
Fig.3 アプリケーションの登録画面

  1. 登録されたアプリのページに遷移し、「証明書とシークレット」に移動し、新しいクライアントシークレットを作成します。

!注意
以下2つのページはつまづいた際によくアクセスすることになるかと思いますのでブラウザにページを残しておくことをおすすめします。

後程、次の画像の「概要ページ」に示されている「アプリケーション (クライアント)ID」、「オブジェクト ID」、「ディレクトリ (テナント) ID」と、「証明書とシークレット」に示されている「値」をWebアクティビティの設定で利用します。

登録されたアプリの概要ページ
Fig.4 登録されたアプリの概要ページ
登録されたアプリのsecretkeyページ
Fig.5 登録されたアプリの証明書とシークレットページ

「b) 登録されたアプリに SharePoint サイトのアクセス許可を付与する(SharePoint のサイト所有者のアクセス許可が必要)」に関して

こちらは画像が1枚張られ、詳細はこちらのリンクを参照ということで、再び英語ページのリンクのため、日本語ページを掲載しておきます。
https://docs.microsoft.com/ja-jp/azure/data-factory/connector-sharepoint-online-list?tabs=data-factory#prerequisites
リンク先を踏むと、前提条件の1に先ほどのAADへのアプリの登録に関して記載があり、2.登録した~からとなります。
SharePointOnlineサイトの管理ページへアクセスします。
https://[your_site_url]/_layouts/15/appinv.aspx

!注意
サイトの URL は置き換えてください。[your_site_url]までのURLは、次のようなSharePoint上でのHome画面のURLとなります。

SPのHome
Fig.6 SharePoint上のHome画面

参考資料:SharePoint Online の直打ちURL集

上手くいくとこのような管理ページにアクセスすることができます。
SharePointの
Fig.7 SharePointの管理ページ
あとはドキュメントにも記載がありますが、以下の通りに入力すればOKです。

!注意
注意点としては、アプリIDは、Azure Portal上から確認できる登録したアプリの「概要ページ」に示されている「アプリケーション (クライアント)ID」を入力し、参照をクリックすれば適応できます。

項目名 設定内容
アプリ ドメイン localhost.com
リダイレクト URL https://www.localhost.com
権限の要求 XML ↓以下に示す
<AppPermissionRequests AllowAppOnlyPolicy="true">
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read"/>
</AppPermissionRequests>
Enter fullscreen mode Exit fullscreen mode

「c) ADF パイプラインを作成します。 Web アクティビティの作成から開始してアクセス トークンを取得する」に関して

!注意
注意点としては、ヘッダー本文の文字列の作成に関してです。クライアント-シークレットに対応する文字列は、シークレットIDではなく、値になります(AzurePortal上の証明書とシークレットに記載)。

設定内容を示します。
| 項目名 | 設定内容 |
| ---- | ---- |
| URL | https://accounts.accesscontrol.windows.net/[ディレクトリ (テナント) ID]/tokens/OAuth/2 |
| メソッド* | POST |
| ヘッダー(名前) | Content-Type |
| ヘッダー
(値) | application/x-www-form-urlencoded |
| 本文 | 便宜上、↓に示す。コピーして[]の部分を書き換えてください(カッコは不要)。|

grant_type==client_credentials&client_id=[アプリケーション (クライアント) ID]@[値(クライアントシークレット)]&client_secret=[値(クライアントシークレット)]&リソース=000000003-0000-0ff1-ce00-00000000/[ディレクトリ (テナント) ID].sharepoint.com@[ディレクトリ (テナント) ID]
Enter fullscreen mode Exit fullscreen mode

!注意
Web1アクティビティのみのこの時点でデバッグ実行し、正常に動作するか確認することをおすすめします。もしも失敗した場合は、設定を見直しましょう。

アプリケーションの登録画面
Fig.8 アプリケーションの登録画面

Step2: Get the list of Files(ファイルの一覧を取得する)

こちらのStepでは、Step1で取得したSPOのトークン情報を用いて、SPO上のファイル情報を取得します。ここのWebアクティビティでは、こちらのRest APIをコールしております。
https://docs.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest#working-with-folders-by-using-rest

項目名 設定内容
URL 便宜上、↓に示す。コピーして[]の部分を書き換えてください(カッコは不要)。
メソッド* GET
ヘッダー1つ目*(名前) Authorization
ヘッダー1つ目*(値) @{concat('Bearer ', activity('Web1').output.access_token)}
ヘッダー2つ目*(名前) Accept
ヘッダー2つ目*(値) application/json
https://microsoftapc.sharepoint.com/teams/SPOinADF/_api/web/GetFolderByServerRelativeUrl('Shared Documents/フォルダ名')/Files
Enter fullscreen mode Exit fullscreen mode

デバッグ実行し、Fig.9に示すWeb2の出力をクリックすると出力画面でこのようにファイルのパスや、作成日等を取得することができます。こちらの画面で正しい情報が取得できているのかの確認をすることができます。
パイプライン実行の出力画面
Fig.9 パイプライン実行の出力画面
Web2の出力結果画面
Fig.10 Web2の出力結果画面

Step3: Loop the list of relative file names(相対ファイル名のリストをループする)

こちらのStepでは、Step2で取得したSPOのファイルリストの内容を取得して、内部でコピー処理するためのアクティビティを用意します。ここは一番シンプルで、設定する内容は次の1つのみで注意点も特にないかと思います。
ForEachアクティビティの設定内容
Fig.11 ForEachアクティビティの設定内容
copyアクティビティの配置

項目名 設定内容
順次 チェックあり
項目 @activity('Web2').output.value

設定が完了したら、ForEachアクティビティをダブルクリックし、データのコピーアクティビティを配置しましょう。
ForEachアクティビティ内部に設置されたコピーアクティビティ
Fig.12 ForEachアクティビティ内部に設置されたコピーアクティビティ

Step4:Create Copy activity(コピーアクティビティを作成)

Step名にCreate Copy activityと書かれていますが、実際は設定のみですね。
一番ここのStepの設定が混乱します。

ソース

まずは、こちらに既に設定済みの画面を示します。
データのコピーアクティビティのソース設定
Fig.13 データのコピーアクティビティのソース設定
| 項目名 | 設定内容 |
| ---- | ---- |
| ソースデータセット |次、説明!|
| RelativeURL |@{item().ServerRelativeUrl}|
| 要求メソッド*| GET |
| 追加のヘッダー| @{concat('Authorization: Bearer',activity('Web1').output.access_token)} |

既に設定されているが、正しく動作していない前提でチェックポイントとして記述します。
上から見ていきましょう。まずは、ソースデータセットです。ここでは、手順通り、HTTPのコネクタを選択しバイナリ項目で作成されていることをまず確認してください。
ソースデータセットの設定値
Fig.14 ソースデータセットの設定値
| 項目名 | 設定内容 |
| ---- | ---- |
| リンクサービスのプロパティ(名前) |FileName|
| リンクサービスのプロパティ(値) |@dataset().RelativeURL|

パラメータとして、RelativeURLという名前で指定します。ここで指定した文字列が、@dataset().RelativeURLとして扱うことができます。
▼参考資料
https://docs.microsoft.com/ja-jp/azure/data-factory/control-flow-expression-language-functions#a-dataset-with-a-parameter
ソースデータセットのパラメータ値
Fig.15 ソースデータセットのパラメータ値

項目名 設定内容
名前 RelativeURL
種類 文字列
既定値 abc

そして、具体的にどうやって、このRelativeURLの値を決めているかというと、Fig.13のソースデータセットのプロパティでRelativeURLの値で決めています。@{item().ServerRelativeUrl}と記述しましたが、これはFig.10に示すWeb2アクティビティで取得したファイル情報に書かれている「ServerRelativeUrl」の値を参照しており、このようにitem().○○でこの値を取得しセットします。

シンク

次は、シンク設定をチェックして行きましょう。
データのコピーアクティビティのシンク設定
Fig.16 データのコピーアクティビティのシンク設定
こちらも、データセットのプロパティでFileNameを指定し、値を@item.Nameで取得しています。

!注意
実はこちら、MSTechCommunityの記事では、記載が省略されていますね。。。ここを記述しないと、生成されたファイルは名前も拡張子も持たずにただのバイナリデータとなってしまうので注意です(ファイル名を無理やり編集すれば、通常通り開くことは可能)。

シンクデータセットの中身はこのようになっています。
シンクデータセットの設定値
Fig.17 シンクデータセットの設定値

項目名 設定内容
リンクサービス 次に説明
ファイルパス [コンテナ名(適当に記入)]/ディレクトリ名/@dataset().FileName
圧縮の種類 なし

そして、パラメータ値はこのようになります。
シンクデータセットのパラメータ値
Fig.18 シンクデータセットのパラメータ値

ソースの設定と大体一緒ですね。データセットにパラメータを持たせて、SPOから取得したファイルリストのFileNameの値をセットしてコピーしたバイナリデータに名前を付けています。改めて、Fig.10に示すWeb2アクティビティで取得した情報を確認するとばっちりNameの文字列があることが分かると思います。こちらのデータを参照しています。

パイプラインの実行

デバッグボタンをクリックして、実行すると以下のような結果が得られたら成功です。CopyData1が4つあるのは4ファイル分処理をしたということですね。
実行結果画面の確認
Fig.19 実行結果画面の確認

4つのテストファイルは、画像ファイル、テキストファイル(文字化け確認用に日本語・英語記述)、パワポファイル、圧縮ファイルを用意してテストしました。
結果、Blob Storageには4つのファイルが生成され、ダウンロードして問題なく開けることを確認しました。
Blob Storageの中身の確認
Fig.20 Blob Storageの中身の確認

参考資料

最後に

本記事では、Microsoft Tech Communityの記事を基に補助説明を加えたものになります。SharePoint上のファイルをStorageにコピーする方法としてAzure Data Factoryを用いましたが、同様のことは、こちらの記事のようにAzure Logic Appsでも実現することができます(その違いに関しては気になる方がおりましたら、加筆するかもしれません)。

お読み頂きましてありがとうございました😊
ご質問やご感想などありましたら、ぜひTwitter (@shisyu_gaku) までお気軽にお問い合わせください。

Top comments (0)