DirectCloud-BOX with Power Automate Desktop「API連携でオンプレミスからのファイル配信を効率化する」

## 概要

DirectCloud-BOXとPower Automate DesktopのAPI連携を利用したファイル配信の自動化を検証します。オンプレミスのファイルをDirectCloud-BOXにアップロード、配信先リストに基づいてパスワードおよび閲覧回数制限、期限付きリンクを作成、取得後メール配信をおこないます。

![DirectCloud.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/185b6720-5925-4662-f505-53295540643b.gif)

## 想定

* オンプレ基幹システムが残る中小企業
* ユーザーが安全に使用
* たくさんの書類を配信先リストに基づいてミスなく一括送信したい
* パス付zipをやめたい
* ファイル閲覧パスワードについてはあらかじめ配信先に通知しておく（今後はSMS等別途手段を検討）

## イメージ

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/efa8aa54-c506-9b31-33bf-616e576110ab.png)

## 注意事項

* スコープが大きくなりすぎるため基幹システムからデーター取り出す部分については触れません。
* 請求書ファイルが「取引先コード＋処理日付.pdf」の形式で出力済みのところから考えます。
* DirectCloud-BOXとPower Automate DesktopとのAPI連携を「PowerShellスクリプトの実行」アクションで行います。
* 検証用にコピペ可能なPower Automate Desktopのコードがありますが、認証情報等は抜いてありますのでご自身の環境にあわせ適宜置き換える必要があります。
* 2021年8月の記事です。
* 試す場合、自己責任でお願いいたします。

## 検証環境および想定される必要環境

* Microsoft 365　E5開発者向けプログラム

   https://developer.microsoft.com/ja-JP/microsoft-365/dev-program#Subscription

* Windows 10 Pro　21H1
* Power Automate Desktop 2.12.171.21216　アテンド型RPA試用版
* DirectCloud-BOX　フリープラン

   https://directcloud.jp/freeplan

開発者とユーザーの権限を分ける想定をしているため実際の運用は「Power Automateアテンド型RPAのユーザーごとのプラン」が必要になります。ユーザーに実行のみの権限でフローを共有することで、認証情報に触れないようにできます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/2ec09c1d-e682-7e8f-ef98-299e74c535ac.png)

https://docs.microsoft.com/ja-jp/power-automate/desktop-flows/manage#share-desktop-flows

## DirectCloud-BOXの準備

DirectCloud-BOX登録後ログインします。
初回管理者でログインとなるので二要素認証等必要に応じて設定します。わかりやすく迷うことはないと思います。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/698419c2-ae55-cf66-c8a1-d1c4e73b8062.png)

初期パスワードの変更についてはユーザー管理から行うかアプリ版起動時に求められます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/10c26b0b-b318-a440-4ec5-3d2fd1858f0b.png)


共有＞カスタム設定よりAPIを使用するように設定します。
今回はユーザーの権限でAPI連携を行うのでユーザーのServiceコードとService Keyを使用します。管理者権限でログインすればコードは確認できます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/92f5142d-734b-6bcd-151e-7493b488130c.png)

ユーザーを追加します。ユーザーIDはアクセストークン取得にも使用します。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/2d03bd7d-060f-95fa-b4ac-102d2d6b788e.png)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/8542296a-1ffd-4b29-182c-58e9f1aedfa2.png)

管理者とユーザーでAPIは機能差があります。

https://directcloud.jp/api_reference

ユーザーでブラウザからログインした場合、権限、インターフェイスは制限されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c68cc25e-9188-236d-b00c-351cf29edc61.png)

今回の検証ではユーザー権限のAPI機能を使用します。


https://directcloud.jp/contents/webapi/


### Power Automate Desktopの準備

製品ページ

https://flow.microsoft.com/ja-jp/desktop/   

Power Automate Desktopの準備についてはリリースされてから時間がたつので割愛いたします。

@K2_kzy 様の【Power Automate Desktopの始め方】が参考になります。

https://qiita.com/K2_kzy/items/b8b22edbf56b65248949

機能については

@maekawawawa 様の【Power Automateの新しいRPA機能】Power Automate Desktopで出来ること（全33機能の紹介）が参考になります。

https://qiita.com/maekawawawa/items/e171240843e56d98be56

## サンプルデータの準備

### 配信先リストの準備

Excelで次のような表を準備し**SendList.xlsx**としてデスクトップに設置しました。本来は社内サーバ等の取引先データに接続した方がよいかと思います。Power Automate DesktopにはSQL接続やターミナルエミュレーションに関するアクションが用意されているので、そうした連携も楽にできますが今回はスコープが広くなりすぎてしまうため、Excelで代用します。

| Code | Name      | Adress              | Pass      | LastSendDate |
| ---- | --------- | ------------------- | --------- | ------------ |
| 1001 | 株式会社A | *****@z***.com      | axjmg42Z  |              |
| 1002 | B株式会社 | ****@******.jp      | Y6rDCmn   |              |
| 1003 | 有限会社C | ****@r******.jp     | AF8K2gv1g |              |
| 1004 | D株式会社 | ******@************ | Hg#ggD34  |

### 配信データの作成

請求データのダミーとして適当なPDFを作成しInvoiceファルダーを作り格納しました。ファイルの名づけルールは先頭4文字が取引先コードとし数値化した日付と組あわせています。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c9b0abb5-368e-f00f-0081-bb4340aa432a.png)

### 処理済みフォルダーの作成

処理済みのファイルを保管しておくフォルダーをUploadedと名前を付けてデスクトップに設置しました。

![2021-08-23-19-12-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/39db341b-2d50-1d57-10b0-913b1074684d.png)

## アクセストークンの取得フロー作成

設定したDirectCloud-BOXの**ユーザー**情報を使用しますので準備ください。

| Name        | Description          |
| ----------- | -------------------- |
| service     | APIキーのservice     |
| service_key | APIキーのservice_key |
| code        | 会社ID               |
| id          | ユーザーID           |
| password    | パスワード           |

###「DirectCloud-BOX Get_Token」フローを作成

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/5e621f71-6d40-9424-4d56-77c03a3921b8.png)

**※出力変数を使用して次のフローに渡すため「access_token」「API_Url」を作成します。**

###3.「PowerShellスクリプトの実行」アクションの内容
[APIリファレンス](https://directcloud.jp/api_reference/detail/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC/Auth#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E7%99%BA%E8%A1%8C)を参考にInvoke-RestMethodをつかってコードを記述します。

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7.1

設定情報は適宜ご自分のものに書き換えてください。
ハッシュテーブルとして設定値を記述しています。

https://docs.microsoft.com/ja-jp/powershell/scripting/learn/deep-dives/everything-about-hashtable?view=powershell-7.1#as-a-lookup-table

```ps1:PowerShell
$endpoint = "/openapi/jauth/token";

$uri = "https://api.directcloud.jp$endpoint";

$body = @{
    service     = "**********"
    service_key = "***********************************************"
    code        = "**********" 
    id          = "*******" 
    password    = "*********"
};

$headers = @{
    lang = "eng"
};

$response = Invoke-RestMethod -Uri $uri `
    -Method 'POST' `
    -Headers $headers `
    -Body $body;
$response | ConvertTo-Json;
```

DirectCloud-BOXではPowerShellからAPI接続する場合、```https://api.directcloud.jp```とリファレンスに記されているエンドポイントをつなげて使用します。必要なデータを設定しInvoke-RestMethodで叩けば動作することがわかりました。出力形式はJSONです。上記コードはPowerShellのコードとして動作可能です。

### Power Automate Desktopのコード

```r:PowerAutomateDesktop

SET Domain TO $'''https://api.directcloud.jp'''
/# ======================================
access_tokenの取得
======================================
#/
System.RunPowershellScript Script: $'''$endpoint = \"/openapi/jauth/token\";

$uri = \"%Domain%$endpoint\";

$body = @{
    service     = \"********\"
    service_key = \"*************************************************\"
    code        = \"********\" 
    id          = \"*******\" 
    password    = \"**********\"
};

$headers = @{
    lang = \"eng\"
};

$response = Invoke-RestMethod -Uri $uri `
    -Method \'POST\' `
    -Headers $headers `
    -Body $body;
$response | ConvertTo-Json;''' ScriptOutput=> PowershellOutput ScriptError=> ScriptError
Variables.ConvertJsonToCustomObject Json: PowershellOutput CustomObject=> JsonAsCustomObject
SET access_token TO JsonAsCustomObject['access_token']
SET API_Url TO Domain

```

保存すればアクセストークンを取得するフローは完成です。

## ファイル配信自動化フローの作成

* 少しだけ長めなフローなのまず大まかなフロー図です。
* サブフロー「DirectCloudBox」内でAPI接続しファイルアップロードとダウンロードリンク作成をおこないます。。
* メール配信後日時をExcelに記録しています。
* エラー処理は最終エラーを記録するだけの単純なものです。
* Mainフローの最後にアクセストークンを廃棄します。

![flowx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/995e14ed-ac43-f55f-6fb6-122d263906fd.png)


### Power Automate Desktopのフロー

### メインフロー「Main」

![Main.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/11b9764f-443c-682d-581d-2278acb7c65e.jpeg)

### サブフロー「DirectCloudBox」

![DCB.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/df7b266b-734f-265a-59c8-0e62706a6e25.jpeg)

#### PowerShellスクリプトの実行　DirectCloud-BOXへのファイルアップロード

https://directcloud.jp/api_reference/detail/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC/File#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89

3行目PowerShellスクリプトの実行アクション内スクリプト

```ps1:PowerShell
$endpoint="/openapp/v1/files/upload/";
$node="1{2000";
$uri = "%API_Url%$endpoint$node";
$headers = @{access_token = "%access_token%" };
$FilePath = "%CurrentItem%";

$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString(); 
$LF = "`r`n";

$bodyLines = (
    "--$boundary",
    "Content-Disposition: form-data; name=`"Filedata`"; filename=`"%CurrentItem.Name%`"",
    "Content-Type: application/octet-stream$LF",
    $fileEnc,
    "--$boundary--$LF" 
) -join $LF;

$response = Invoke-RestMethod -Uri $uri `
    -Method 'POST' `
    -Headers $headers `
    -ContentType "multipart/form-data; boundary=`"$boundary`"" `
    -Body $bodyLines;
$response | ConvertTo-Json;
```
:::note info
%で囲ってある文字はPower Automate Desktopの変数です。
:::

まず$nodeについてはリファレンスを読んだところフォルダー名だと思いこんでしまい、最初にハマったポイントでした。
今回の例では共有フォルダー内のDocフォルダーを指定しているのですが 

$node="1{2000"

このような記述になります。
nodeの値を取得するためにはフォルダリストを取得しながら確認しました。以下にフォルダー取得のPowerShellsスクリプトをのせておきます。

```ps1:PowerShell
$uri = "https://api.directcloud.jp/openapp/v1/folders/index/"
$headers = @{access_token = "%access_token%" };

$response = Invoke-RestMethod -Uri $uri `
    -Method 'GET' `
    -Headers $headers;
$response | ConvertTo-Json;
```

$uriのindex以下にnode値を指定してフォルダーリストを取得できます。このままnode指定無しで実行するとMyBOXが"1"SharedBOXが"1{2"というnode値が取得できます。配信先ごとにフォルダーを分けるなどの処理を組み込みたいときはnode値を取得するフローをつくる必要があります。スクリプト自体はこれまでと同様Invoke-RestMethodのGETメソッドで可能です。

アップロードに話は戻りますがはmultipart/form-dataで行う必要があります。
そして今回最大のハマりポイントです。
```$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);```で
ファイルを読み込んだ後、文字列として読み込む際に必要な文字コードをutf-8にしていたことが原因でアップロードされたファイルが破損していました。
PowerShellを使う場合***ISO-8859-1***で設定する必要がありました。
```$fileEnc = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($fileBytes);```
https://ja.wikipedia.org/wiki/ISO/IEC_8859-1
アップロードのコードにつきましてはstackoverflowの記事を参考にさせていただき、Fiddlerで確認しながら作成ました。感謝です。

https://stackoverflow.com/questions/36268925/powershell-invoke-restmethod-multipart-form-data

#### PowerShellスクリプトの実行　DirectCloud-BOXのファイルへのリンク作成

https://directcloud.jp/api_reference/detail/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC/File#%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%AE%E4%BD%9C%E6%88%90

9行目PowerShellスクリプトの実行アクション内スクリプト
配信先の情報に応じてリンク作成の設定を行います。

```ps1:PowerShell
$endpoint = "/openapp/v1/links/create";
$uri = "%API_Url%$endpoint";
$headers = @{access_token = "%access_token%" };
$body = @{
    target_type     = "file"
    target_seq      = %file_seq%
    view_option     = "both" 
    expiration_date = "%expiration_date%"
    limit_count     = %DLCount% 
    password        = "%Password%"
};

$response = Invoke-RestMethod -Uri $uri `
    -Method 'POST' `
    -Headers $headers `
    -Body $body;
$response | ConvertTo-Json;
```
Mainフローの終了処理でおこなうアクセストークン廃棄のスクリプトです。
どの機能もほとんど同じ形式ですのでリファレンス通り設定すれば動くと思います。

```powershell
$endpoint = "/openapi/jauth/tokenExpire";
$uri = "%API_Url%$endpoint";
$body = @{
    service      = "********"
    service_key  = "********************************"
    access_token = "%access_token%" 
};

$response = Invoke-RestMethod -Uri $uri `
    -Method 'POST' `
    -Body $body;
$response | ConvertTo-Json;
```


### サブフロー「Error_Rec」

エラー吐いた時のために作っておきます。
![errorrec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/52c0bb20-b7a1-c345-67c4-d7667f81f261.jpeg)

## まとめ

* 事務のおじさんが、ローコードツールを使ってAPI連携でファイル配信自動化してみました。
* PowerShellスクリプト実行アクションを使って、Invoke-RestMethodとハッシュテーブルで記述すれば、DirectCloud-BOXとPower Automate Desktop連携できることがわかりました！
* GUI操作での自動化ではないため早く確実な自動化処理が見込まれます。
今回のフローでは組み込めませんでしたが、リンク先のパスワードを別途SMS等で送信できればパス付zipにかわる強力な仕組みがつくれそうです。
* はじめてDirectCloud-BOXを触ってみましたが、どのインターフェイスでも迷うことがない、すばらしいサービスだと感じました。
* 権限設定やログ関連も充実しとてもわかりやすいです。
* 現状のAPIリファレンスにサンプルがないため試行錯誤しました。結果的にはかなり勉強になったので個人的には楽しかったですがｗ

中小企業ではまだまだオンプレミスのシステムが残っています。オンプレミスとクラウドつなぐことは重要度が増すのではと想像しています。API+ローコードソリューションはそのカギのひとつだと思います。
考える機会を頂きありがとうございました😊

## 参考およびリンク

https://qiita.com/official-events/64ff6ba4e653a822fce9

https://directcloud.jp/

https://directcloud.jp/freeplan

https://directcloud.jp/api_reference

https://flow.microsoft.com/ja-jp/desktop/

https://docs.microsoft.com/ja-jp/power-automate/desktop-flows/manage#share-desktop-flows

https://developer.microsoft.com/ja-JP/microsoft-365/dev-program#Subscription

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7.1

https://docs.microsoft.com/ja-jp/powershell/scripting/learn/deep-dives/everything-about-hashtable?view=powershell-7.1#as-a-lookup-table

https://stackoverflow.com/questions/36268925/powershell-invoke-restmethod-multipart-form-data