How to read files on SharePoint Online using Azure Data Factory/Azure Synapse Pipeline(.jp) - supplement
Tags: azure, beginners, datafactory, japanese
Published: 2022-01-29 14:23:03

Azure Data Factory/Azure Synapse Pipelineは、Cloud上のSparkクラスターで膨大なデータをD&DのGUIベースで設計し、処理することができます。
[](https://docs.microsoft.com/ja-jp/azure/data-factory/introduction)

この記事の対象者は、Azure Data Factoy(Synapse Pipeline)で**アクティビティを用いてパイプライン実行をしたことがある方を対象**としております。そうでいない方は、以下の記事をご参考ください。
- Azure Data Factoryのクイックスタートについて[こちら](https://docs.microsoft.com/ja-jp/azure/data-factory/quickstart-create-data-factory-portal)を参照ください
- Azure Data Factoryについてより理解を深めたい方は充実した[こちらのYouTubeチャンネル](https://www.youtube.com/channel/UC2S0k7NeLcEm5_IhHUwpN0g)をご覧ください。
- Azure Data FactoryとSynapse Pipelineは、ほぼ近しいサービスであるが、違いについて知りたい方は以下のサイトを参照ください。
	- [ADF および Azure Synapse Analytics で利用可能な機能](https://docs.microsoft.com/ja-jp/azure/synapse-analytics/data-integration/concepts-data-factory-differences#available-features-in-adf--azure-synapse-analytics) (Microsoft公式ドキュメント)
	- [【Microsoft Azure】Azure Synapse Analyticsでできることを理解する](https://www.simpletraveler.jp/2021/11/07/%E3%80%90microsoft-azure%E3%80%91azure-synapse-analytics%E3%81%A7%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B/#Azure_Data_Factory)

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

▼Microsoft Tech Communityが公開している記事
<!-- MEMO:dev.to用 [SharePoint Online Multiple Files (Folder) Copy with Http Connector](https://techcommunity.microsoft.com/t5/azure-data-factory-blog/sharepoint-online-multiple-files-folder-copy-with-http-connector/ba-p/2480426)-->
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://docs.microsoft.com/ja-jp/azure/data-factory/source-control)に基づいて、リポジトリが構成されております。
<!-- MEMO:dev.to用　- [hogaku/sharepoint_in_adf](https://github.com/hogaku/sharepoint_in_adf) - 本記事の内容を実装したソースコード-->
メンテナンス中
~~▼本記事の内容を実装したソースコード~~
~~https://github.com/hogaku/sharepoint_in_adf~~
▼本記事で仕様したテストデータ(githubリポジトリ上にあり)
![本記事で仕様したテストデータ](https://storage.googleapis.com/zenn-user-upload/a60a514b4072-20220129.png)
▼MSTechCommunityの記事(本記事の被補助記事)
https://techcommunity.microsoft.com/t5/azure-data-factory-blog/sharepoint-online-multiple-files-folder-copy-with-http-connector/ba-p/2480426

## 手法
以下に示す３ステップにより実現します。
1. Webアクティビティを用いて、SharePointOnlineからアクセストークンを取得します(アクティビティ名:Web1)。
2. 2つ目のWebアクティビティを用意し、SPO上のフォルダからファイルの一覧を取得(アクティビティ名:Web2)
3. ForEachアクティビティとデータのコピーアクティビティを用いて、フォルダ内のファイルリストをループし、随時、データをコピー(SharePoint→Azure Blob Storage)(ForEachアクティビティ名:ForEach1, データのコピーアクティビティ名:CopyData1)。
![全体のパイプラインフロー](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlkzrs25w4q8nptfh2bo.png)
*Fig.1 全体のパイプラインフロー*
![ForEachアクティビティの内部アクティビティ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zkipnc6a7ggwpieqsr9d.png)
*Fig.2 ForEachアクティビティの内部アクティビティ*

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

#### 「a) AAD アプリケーションの登録」に関して
1. まずは[こちらのAzure PortalのMicrosoft|アプリの登録](https://ms.portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps)へアクセスし、[+新規登録]ボタンをクリック後、↓のリンクへアクセスし、アプリケーションの登録を行いましょう。

▼アプリケーションを 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)を掲載しておきます。
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-auth-aad-app?tabs=dotnet#register-your-application-with-an-azure-ad-tenant

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

![アプリケーションの登録画面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c0wdgw7r89e06z165e67.png)
*Fig.3 アプリケーションの登録画面*

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

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

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

![登録されたアプリの概要ページ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/opdz8dbe1j7ikq40rjpf.png)
*Fig.4 登録されたアプリの概要ページ*
![登録されたアプリのsecretkeyページ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/juxnpcz1a1dl6ssrpmwk.png)
*Fig.5 登録されたアプリの証明書とシークレットページ*

#### 「b) 登録されたアプリに SharePoint サイトのアクセス許可を付与する(SharePoint のサイト所有者のアクセス許可が必要)」に関して
こちらは画像が1枚張られ、詳細はこちらのリンクを参照ということで、再び英語ページのリンクのため、[日本語ページ](https://docs.microsoft.com/ja-jp/azure/data-factory/connector-sharepoint-online-list?tabs=data-factory#prerequisites)を掲載しておきます。
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6u23l0exbjgmcxtnjvb.png)
*Fig.6 SharePoint上のHome画面*

参考資料：[SharePoint Online の直打ちURL集](https://qiita.com/TNx/items/1b2776ab7f1a8ebd55a4)

 上手くいくとこのような管理ページにアクセスすることができます。
 ![SharePointの](https://storage.googleapis.com/zenn-user-upload/385d3d7aa0fe-20220126.png)
 *Fig.7 SharePointの管理ページ*
 あとはドキュメントにも記載がありますが、以下の通りに入力すればOKです。

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


| 項目名 | 設定内容 | 
| ---- | ---- | 
| アプリ ドメイン | localhost.com | 
| リダイレクト URL | https://www.localhost.com | 
| 権限の要求 XML | ↓以下に示す | 

```XML
<AppPermissionRequests AllowAppOnlyPolicy="true">
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read"/>
</AppPermissionRequests>
```

#### 「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]
```

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


![アプリケーションの登録画面](https://storage.googleapis.com/zenn-user-upload/45f53ab8eb79-20220126.png)
*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
```
デバッグ実行し、Fig.9に示すWeb2の出力をクリックすると出力画面でこのようにファイルのパスや、作成日等を取得することができます。こちらの画面で正しい情報が取得できているのかの確認をすることができます。
![パイプライン実行の出力画面](https://storage.googleapis.com/zenn-user-upload/01f74364dc1b-20220126.png)
*Fig.9 パイプライン実行の出力画面*
![Web2の出力結果画面](https://storage.googleapis.com/zenn-user-upload/b05ed02da768-20220126.png)
*Fig.10 Web2の出力結果画面*

### Step3: Loop the list of relative file names(相対ファイル名のリストをループする)
こちらのStepでは、Step2で取得したSPOのファイルリストの内容を取得して、内部でコピー処理するためのアクティビティを用意します。ここは一番シンプルで、設定する内容は次の1つのみで注意点も特にないかと思います。
![ForEachアクティビティの設定内容](https://storage.googleapis.com/zenn-user-upload/4acf3d2c834d-20220127.png)
*Fig.11 ForEachアクティビティの設定内容*
![copyアクティビティの配置](https://storage.googleapis.com/zenn-user-upload/ad68e16e1c06-20220127.png)

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

設定が完了したら、ForEachアクティビティをダブルクリックし、データのコピーアクティビティを配置しましょう。
![ForEachアクティビティ内部に設置されたコピーアクティビティ](https://storage.googleapis.com/zenn-user-upload/3db856405b05-20220127.png)
*Fig.12 ForEachアクティビティ内部に設置されたコピーアクティビティ*

### Step4:Create Copy activity(コピーアクティビティを作成)
Step名にCreate Copy activityと書かれていますが、実際は設定のみですね。
一番ここのStepの設定が混乱します。
#### ソース
まずは、こちらに既に設定済みの画面を示します。
![データのコピーアクティビティのソース設定](https://storage.googleapis.com/zenn-user-upload/acfada4103e0-20220127.png)
*Fig.13 データのコピーアクティビティのソース設定*
| 項目名 | 設定内容 | 
| ---- | ---- | 
| ソースデータセット |次、説明！| 
| RelativeURL |@{item().ServerRelativeUrl}| 
| 要求メソッド*| GET |
| 追加のヘッダー| @{concat('Authorization: Bearer',activity('Web1').output.access_token)} |

**既に設定されているが、正しく動作していない前提でチェックポイント**として記述します。
上から見ていきましょう。まずは、ソースデータセットです。ここでは、手順通り、HTTPのコネクタを選択しバイナリ項目で作成されていることをまず確認してください。
![ソースデータセットの設定値](https://storage.googleapis.com/zenn-user-upload/76a376443240-20220127.png)
*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
![ソースデータセットのパラメータ値](https://storage.googleapis.com/zenn-user-upload/46cda527d506-20220127.png)
*Fig.15 ソースデータセットのパラメータ値*

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

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

#### シンク
次は、シンク設定をチェックして行きましょう。
![データのコピーアクティビティのシンク設定](https://storage.googleapis.com/zenn-user-upload/8af98c0e94fa-20220129.png)
*Fig.16 データのコピーアクティビティのシンク設定*
こちらも、データセットのプロパティでFileNameを指定し、値を`@item.Name`で取得しています。

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


シンクデータセットの中身はこのようになっています。
![シンクデータセットの設定値](https://storage.googleapis.com/zenn-user-upload/92c55cb42356-20220129.png)
*Fig.17 シンクデータセットの設定値*

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

そして、パラメータ値はこのようになります。
![シンクデータセットのパラメータ値](https://storage.googleapis.com/zenn-user-upload/01f93a8211ee-20220129.png)
*Fig.18 シンクデータセットのパラメータ値*

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

### パイプラインの実行
デバッグボタンをクリックして、実行すると以下のような結果が得られたら成功です。CopyData1が4つあるのは4ファイル分処理をしたということですね。
![実行結果画面の確認](https://storage.googleapis.com/zenn-user-upload/c55920ca72ff-20220129.png)
*Fig.19 実行結果画面の確認*

4つのテストファイルは、画像ファイル、テキストファイル(文字化け確認用に日本語・英語記述)、パワポファイル、圧縮ファイルを用意してテストしました。
結果、Blob Storageには4つのファイルが生成され、ダウンロードして問題なく開けることを確認しました。
![Blob Storageの中身の確認](https://storage.googleapis.com/zenn-user-upload/e9e2d0cd087c-20220129.png)
*Fig.20 Blob Storageの中身の確認*
## 参考資料
- [Azure Data Factory または Azure Synapse Analytics を使用して SharePoint Online リストからデータをコピーする](https://docs.microsoft.com/ja-jp/azure/data-factory/connector-sharepoint-online-list?tabs=data-factory)
- [SharePoint Online Multiple Files (Folder) Copy with Http Connector](https://www.drware.com/sharepoint-online-multiple-files-folder-copy-with-http-connector/)
- [How to read files on SharePoint Online using Azure Data Factory](https://charith-ekanayake.medium.com/how-to-read-files-on-sharepoint-online-using-azure-data-factory-501cdf9f9d0e)
- [SharePoint File Copy to Azure using Power Automate or Azure Data Factory](https://www.youtube.com/watch?v=fhtwW3FXf3g)
- [Azure Data FactoryでSharePointのファイルをADLS Gen2にコピー](https://qiita.com/yaagi/items/eb6a86e0c9a2fc3b3e61)

## 最後に
本記事では、Microsoft Tech Communityの記事を基に補助説明を加えたものになります。SharePoint上のファイルをStorageにコピーする方法としてAzure Data Factoryを用いましたが、同様のことは、[こちらの記事](https://www.mssqltips.com/sqlservertip/5893/transfer-files-from-sharepoint-to-blob-storage-with-azure-logic-apps/)のようにAzure Logic Appsでも実現することができます(その違いに関しては気になる方がおりましたら、加筆するかもしれません)。

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