Microsoft Power Automateはお好きですか?
なんでもできますよね。ぼくは苦手です。
どでかいハマりポイントがあったので、勉強のため整理してみました。
間違っている箇所があるかもしれません。教えていただけるとうれしいです。
問題の概要
Power Automate の「承認を作成」「メールを送付」アクションなど、SharePoint から取得したファイル(Excel等)を添付するアクションで、受信側でファイルが破損している現象が発生する。
環境・構成
Teams承認を作成の場合
- SharePoint ドキュメントライブラリからファイル取得(
ファイル コンテンツの取得アクション) - 承認アクション(
CreateAnApproval)に添付ファイルとして渡す - ファイルの種類:Excel(.xlsx)
症状のパターン
| 試した書き方 | 症状 |
|---|---|
@{body('ファイル_コンテンツの取得')} |
「問題が見つかりました。回復しますか?」(部分的に壊れる) |
@{body('ファイル_コンテンツの取得')?['$content']} |
「拡張子がおかしい」(ファイルとして認識されない) |
@{base64ToBinary(body('ファイル_コンテンツの取得')?['$content'])} |
「拡張子がおかしい」(悪化) |
@base64ToBinary(body('ファイル_コンテンツの取得')?['$content']) |
✅ 正常に開ける |
原因
ファイル コンテンツの取得 アクションの返却値
body('ファイル_コンテンツの取得') は以下のような構造を返す:
{
"$content-type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"$content": "UEsDBAoAAAAAAA..." // base64エンコードされたバイナリ
}
?['$content'] で base64 文字列を取り出せるのは正しい。
しかし、どう渡すか が問題。
@{} と @ の違いが諸悪の根源
Power Automate の式には2つの記法がある:
| 記法 | 意味 | バイナリへの影響 |
|---|---|---|
@{expression} |
文字列補間(テキストの中に埋め込む用) | ❌ バイナリ・バイナリオブジェクトが文字列に変換される |
@expression |
式をそのまま評価(値をそのまま渡す) | ✅ バイナリのまま渡せる |
@{base64ToBinary(...)} が破損する理由
base64ToBinary() → バイナリデータ
→ @{} が文字列化しようとする
→ バイナリが壊れる
@base64ToBinary(...) が成功する理由
base64ToBinary() → バイナリデータ
→ @ のみなのでそのまま評価
→ バイナリのまま承認アクションに渡る ✅
解決策
承認アクションの content フィールドに渡す際は @{} なし で記述する:
"ApprovalCreationInput/attachments": [
{
"name": "ファイル名.xlsx",
"content": "@base64ToBinary(body('ファイル_コンテンツの取得')?['$content'])"
}
]
なぜハマりやすいのか
-
Power Automate の GUI でダイナミックコンテンツを挿入すると、自動的に
@{}が付く場合がある、そして自動で除去される- スペースなどを挟んで変数を追加すると、文字列として結合しようと
{ }が残ります。Xボタンで当該変数を削除しても、一度設定されてしまったブラケットは自動で削除されない場合があります。
例えば、作成アクションでプロパティを作成するとき、"でプロパティを括ると残ります。(文字列として扱われるため)
- スペースなどを挟んで変数を追加すると、文字列として結合しようと
-
@{}はほとんどの場面(文字列フィールド)では問題ない -
バイナリを扱うフィールドでだけ問題が起きるため、原因に気づきにくい
-
エラーメッセージも「拡張子がおかしい」「回復しますか?」と、式の書き方が原因だとはわかりにくい
- ファイル情報を見ると明らかにバイト数が違っていて気がつきました
まとめ:バイナリを渡すときの鉄則
バイナリ値を渡すフィールドには
@{}を使わない。@expressionの形式で渡す。
❌ "@{base64ToBinary(...)}" → 文字列補間でバイナリが死ぬ
✅ "@base64ToBinary(...)" → バイナリのまま生きる
文字列フィールドには @{} を使い、バイナリフィールドには @ のみ使う。
この区別を意識するだけで、ファイル破損系のトラブルはほぼ防げるようです。
取得したコンテンツをそのまま次のアクションに渡す場合は問題なさそう(コードビューで見ると{ }がセットされていない)ので、素直じゃない人が陥る問題なのかもしれません。実際メールの場合は直前で取得してそのまま飛ばすフローだったので、大丈夫でした。
またbase64tobinary, $contentがなくても、メールの場合(ContentBytes)は大丈夫そうでした。
いまいち、PAのほうで何を補完して何を補完しないか、予測がつかないので、作ってみて試すことを繰り返さないと分からない。たくさんのアクションがあるので、それぞれに思想があるんでしょうね。