📝

Power Automate Desktop を気軽なコード置き場に使う

2023/05/16に公開

Power Automate Desktop を気軽なコード置き場に使う

概要

Power Automate Desktop は作業を自動化する RPA ツールで、Windows に標準搭載されています。
使ってみたところ Windows の機能と各スクリプト言語が今までよりもずっと簡単につながる感触です。

グルー言語としてだけでなくアイデアの試行錯誤に使っても楽しかったので、手軽に使えるプラットフォームとして評価してみました。

コンピュータ・ランタイムを入れると Power Automate のクラウドフローからデスクトップフローを呼び出すような使い方もできますが、今回は未評価です。

特徴

フロー変数

名前を気にしないで済むようにできています。
アクションの結果がフロー変数に入るのですが、その変数名は自動で付けられます。命名はアクションごとに規則性があります。
後からの変更も容易です。フロー変数の一覧から変更すると、参照箇所がすべて書き換わります。

さらに、新規フローの作成でも名前を付けなければ無題で開始することができます。
フローを一度も保存しなければ後に残らないので、手軽に書いて試して使えないアイデアなら保存しないというやり方でスクラッチから試すことができます。

何か仕組みを実現したい、と考えているときに最初から適切な名前を付けることは容易でありません。
とりあえずで自動的に名前がついていて、作り手が理解した後でよりふさわしい名前に変えられるというのは敷居を下げてくれます。

スクリプト言語

Windows に組み込まれた多種のスクリプト言語が呼び出せます。さらに Python が組み込まれています。
実行するスクリプトはアクションの中に保存しますが、入力欄が広げられないのでそこは改善してほしい点です。

  • コマンド プロンプト
  • PowerShell
  • Windows Scripting Host (VBScript, JScript)
  • IronPython (ただし、2.7.9)

IronPython は .NET で実装された Python です。.NET の機能が呼び出せます。
この中に Python の標準ライブラリは組み込まれていませんが、ダウンロードして後から追加できます。

制御構造

Power Automate Desktop はアクションを並べたフローがあり順番に実行していきます。
スクリプト言語の呼び出しは専用のアクションの内部で実行されます。スクリプトが終了しなければ次のアクションに進めません。
フロー制御構造もアクションを並べて作ります。そのため複雑な制御構造を作るには向いていません。

一つのフローに作れるアクションは最大 500 step に制限されています。
この制限はサブフローを作ることで緩和されます。

Robin

変数のスカラ値は数値、文字列、真偽値があります。
それ以外は、テーブル、リスト、カスタムオブジェクトなどがあります。

変数を埋め込んで参照するには %NewVar% のようにパーセントで囲みます。バッチファイルっぽい見た目になります。
% % に囲まれた中は式となり Robin の構文で評価されます。
変数名以外にいくつかの演算子と If 文と同等の判定関数が書けます。

  • %'abc'%: 文字列 (abc と同じ意味)
  • %NewVar + 1% %NewVar - 2% %NewVar * 3% %NewVar / 4%: 四則演算
  • %NewVar + 'x'%: 文字列結合
  • %''%: 長さ 0 の文字列
  • %True% %False%: 真偽値
    詳しくは 変数と % 表記を使用する で。

変数には型があります。変数に設定されたリテラルの評価は .NET の Decimal の数値とみなせれば数値型に、そうでなければ文字列型になります。
たとえば 79228162514264337593543950335 は数値型ですが、一つ多い整数 79228162514264337593543950336 は Decimal で表せる範囲から外れてしまうため文字列型と解釈されます。
また、E 表記には対応していません。

アクションで定義された変数は巻き上げが起きます。最初に利用される直前に既定値で初期化されます。
未初期化の変数はカスタムオブジェクトの例外を除いてありません。
例外のカスタムオブジェクトは、値が null のプロパティを持った JSON を変換することで生成できます。
ですが、未初期化のプロパティにアクセスするとランタイムエラーが発生します。未初期化の判断を関数で行うことはできません。

変数展開

文字列変数でなくても、文字変数が来るべき箇所の変数は暗黙に文字列化されます。

スクリプト言語のアクションに変数を差し込むと、一部を動的に差し替えることが可能ですが、単純な文字列置換のため、構文を壊してしまうことがあります。
その意味でバッチファイルの変数並みに注意が必要です。

Power Automate Desktop には SQL を実行するアクションがありますが、変数をチェックなしに使えば SQL インジェクションがすぐにできてしまいます。

起動ショートカットキー

フローの実行は Power Automate Desktop コンソールを開いて実行ボタンを押すのが一般的ですが、キーコンビネーションによるショートカット起動にも対応しています。
頻繁に実行するなら、ショートカットキーを設定すると実用的です。

欠点

起動に時間がかかる

フローはクラウドに保存され、実行前に毎回ダウンロードを行います。
そのせいで起動は少し時間がかかります。

順次実行のみ

アクションの並列処理、非同期処理ができません。
スクリプト言語も実行が終わるまで待つことになります。
パイプやストリームといったものも活用できません。

ユーザ間の知見の共有が難しい

作ったフローは Ctrl-C のショートカットでクリップボードにコピーができます。
テキストエディタに張り付けてみるとわかりますが Robin 言語の構文になっています。

しかし、これらを SNS などで貼り付けても見栄えがしません。
標準的なシンタックス・ハイライトで対応していないのが原因なのですが、さりとてスクリーンショットをいちいち貼るのも大変です。
コードの共有について標準的な方法がないのは残念なところです。

有料機能

プレミアム機能を使うと、デスクトップにショートカットを作成できたり URL 経由でバッチ起動ができたりするらしいです。

Python Tips

Python 言語のプラットフォームとして使う上での Tips です。

入力変数

スクリプトに注入するフロー変数はコード中に文字列で埋め込みます。
文字列変数は三重引用符で囲んで渡します。これで改行があってもエラーになりません。

new_var = """%NewVar%"""

文字列変数に記号を含む可能性がある場合、事前に \ " をエスケープします。

(上記をコピーしたもの)

Text.Replace Text: NewVar TextToFind: $'''[\\\\\"]''' IsRegEx: True IgnoreCase: False ReplaceWith: $'''\\$0''' ActivateEscapeSequences: False Result=> NewVar

文字列以外のテーブル型などのベクトル変数を取り扱うには、記号のエスケープ処理がすべての値に必要となります。
他の手段で、変数を CSV ファイルに保存してファイルパスを渡し、Python 側でファイルを読み出すようにすればエスケープの手間が減ります。

出力変数

標準出力の内容がフロー変数 PythonScriptOutput に格納されます。
Python 側でテキスト出力するか、JSON 出力して後でカスタムオブジェクトに変換します。

PythonScriptOutput の先頭は出力の内容にかかわらず Unicode の BOM が入るようになっています。
おそらく Windows で Unicode を指定してパイプを開いたときの挙動がそうなっているせいだと思いますが、後処理で邪魔なため、参照する際に PythonScriptOutput[1:] のように先頭一文字を削ります。

ランタイムエラーがあった場合、 ScriptError に標準エラー出力が格納されます。
このフロー変数は既定で生成されないため、アクションの「生成された変数」から有効にします。

モジュールパス

組み込まれている Python のモジュールはごく少数です。
後からモジュールを追加することができます。

例として IronPython の標準ライブラリをダウンロードして組み込めます。
IronPython.StdLib.2.7.9.zip をダウンロード[1]して、 C:¥Python27¥Lib などに展開します。
アクションの「詳細」からモジュール フォルダー パスにフォルダパスを指定すると import で利用することができます。
また、Python スクリプトの中で sys.path に追加もできます。この方法なら、.zip ファイルのままでも指定できます。

import sys
sys.path.append(r"""%PythonModuleZip%""")
脚注
  1. Release IronPython 2.7.9 ↩︎

Discussion