Automation Anywhere から PowerShell やPython などの外部プログラムを呼び出す

# 概要
Automation Anywhere でのボット作成にある程度慣れてくると、外部モジュールを実行してできることを拡張したくなります。たとえば、Automation Anywhere から PowerShell スクリプトの処理を呼び出したり、Python を呼び出して機械学習の処理をさせたり、といったことをしたくなります。これらをどう実行できるかについて整理したいと思います。

**前提**

* Automation Anywhere
 - Enterprise 11.3.2
 - Community Edition (2019年8月現在、UIは英語です)
* Windows 10 バージョン1903

# Automation Anywhere で実行できる外部モジュール呼び出し方法
まず、Automation Anywhereでどのように外部モジュール呼び出し (=任意の操作の実行) ができるかについて一覧にしてみました。

|方法|カテゴリ/コマンド名|概要と特徴|
|:--|:--|:--|
|別タスクの呼び出し|Task / Run Task|Automation Anywhere で作成した別のボットを呼び出す。自分で作成したよく使うアクションリストをサブルーチン的に使うのに便利。**引き継ぐローカル変数をダイアログボックスでビジュアルに任意数設定できる**ので、情報の受け渡しはとても楽。リピート有無や実行スピードも設定可能。|
|Meta Bot (およびBot Store)|Run Logic|Meta Bot Designerの権限を持つ人が汎用的につくったボットや、Bot Storeからインストールしたボットを部品として呼び出すのに使う。通常のボットでは使えない **.DLL の呼び出しが可能**なので、パッケージ内での複雑で汎用的なタスクが可能。Meta Botで定義されているInput / Output パラメータをダイアログボックスでビジュアルに設定可能。|
|Excelマクロの呼び出し|Excel / Run Excel Macro|開いているExcelファイルの中のExcelマクロを引数リストを渡して呼び出せる。|
|Windowsアプリの呼び出し|Open Program/File|Windows 実行形式ファイル(.exe)や、**これに関連付けられたファイル**を指定して実行できます。ファイルの開始ディレクトリや引数も指定可能。**さまざまな種類の外部モジュールを最も汎用的に呼び出せる。**ただし、グラフィカルユーザーインターフェイス (GUI) を持っている必要がある(持っていなくても実行されるがエラーが出る)。|
|OS サービスの呼び出し|Services / Start Service|インストール済みのサービスを開始できる。サービスモジュールを自分でプログラミングすることは少ないと思われるので、この方法はほぼ使わないかも。|
|VBScript/JScriptの呼び出し|Run Script|ローカルにある .vbs / .js を指定して実行します。パラメータや戻り値を得るための変数を設定することもできます。**コマンドラインユーザーインターフェイス (CUI) のみでも実行可能。**|
|データベース内のスクリプトの呼び出し|Database / Run Stored Procedure|ストアドプロシージャの関数名/引数を指定して実行できます。引数は任意数追加でき、結果をCSVにエクスポートするオプションもあります。|
|ウェブページ内のスクリプトの呼び出し|Web Recorder / Execute JavaScript Function|ウェブページ内のJavaScript関数と、実行結果を返す変数を指定して呼び出せます。|
|XML内のスクリプトの呼び出し|XML / Execute XPath Function|XPath Function を実行できます。実行するXPath 式と、戻り値を得る変数を指定します。|
|SOAP/REST ウェブサービスの呼び出し|SOAP Web Service|SOAP/REST ウェブサービスのURIを呼び出してサービスを実行して戻り値を変数に返します。必要に応じてヘッダーパラメーターを任意数、出力結果をXMLとして保存、認証がある場合のアカウント情報やクライアント証明書を指定できます。|

今回呼び出したいPowerShellスクリプトの場合、**Open Program/File** アクションを利用するのが良さそうです。

# Open Program/File による外部モジュールの呼び出し

Open Program/Fileは以下のダイアログボックスでパラメーターの指定が可能です。
![aa-openprogram01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/7b10e238-c870-7a1f-06b5-ecef161856a1.png)


ここに呼び出したいPowerShellスクリプトを指定するのですが、今回は2つの方法を考えてみました。
ちなみに、PowerShellスクリプトは以下のものを用意します。
![hello-ps1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/884896f3-72e5-3681-13af-35c10221ffa6.png)


```PowerShell:Hello.ps1
Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("Hello World!!", "こんにちは")

```

#### 方法1: PS1ファイルの関連付けを利用して実行する
PowerShell のスクリプトファイル .ps1 はアイコンを見ればわかる通り、関連付けがされています。
したがって、.ps1 を以下のダイアログボックスの「**Program/File パス**」に直接指定しても動作するはずです。
![aa-openprogram02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/e235dd7e-4f7a-c4d8-0150-6652f0ce44f9.png)

この状態で保存すると、以下のアクションリストができます。
![aa-openprogram03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/404a3d29-4202-6536-92e4-68beaae75a49.png)

これで実行してみると...スクリプトの中身が実行される代わりにメモ帳でスクリプトファイルが開かれてしまいました...
![aa-openprogram04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/b12ba164-50fd-47c6-b3a9-285716d2552e.png)

これがなぜだったかを見てみると、実は.ps1のアクションの関連付けは、少なくともWindows 10の環境ではメモ帳にされていることがわかります。
![aa-openprogram05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/7682ffd9-6b72-4779-c476-e91167224ca5.png)


したがって、この関連付けをpowershell.exeに変更すると動作するはずですので、変更してみましょう。
![aa-openprogram06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/bca85291-d3ee-774c-b0c6-143a28a98cb4.png)

PowerShell.exe は`"%systemroot%\system32\windowspowershell\v1.0\powershell.exe"`にあるので、このファイルを指定します。
![aa-openprogram07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/f8a5c27c-3b95-9366-29ab-d425ab3af7ce.png)

また、表の中でも記載した通り、このコマンドはGUIがあるプログラムを前提としており、CUIのプログラムを呼び出した場合は「WaitForInputIdleに失敗しました。プロセスがグラフィック インターフェイスを含んでいない可能性があります。」というエラーが出ます。これは無視できるので、Error Handlingで囲みます。
![aa-openprogram08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/65514982-9421-1b17-d8eb-75f6471697b8.png)


これで実行すると、以下の通りスクリプトが実行されることがわかります。
![aa-openprogram09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/01bee95a-2fa3-c003-6a6d-002883c7eab8.png)

>(注) デフォルトのセキュリティレベルではPowerShellはスクリプトとして実行が禁止されているので、スクリプトを実行する前にPowerShellコマンド`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`を実行しておくようにしましょう。終わったら`Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser`でセキュリティを元に戻します。

#### 方法2: 「PowerShell実行ファイル」+「引数=PS1ファイル」を指定して実行する
さて、関連付けがされていればファイルを直接「**Program/File パス**」に指定すれば実行されることはわかりましたが、この関連付けは通常はされていないため、実行形式ファイルと引数としてのスクリプトファイルの2つを指定する方法を試してみたいと思います。また、複数のバージョンの.exeがある場合も、こちらの方法を使う必要があります。

「**Program/File パス**」には[システム変数](https://qiita.com/RPAbot/items/4f03665cac09dcf6a246)をうまく使って汎用的に`$System(SystemRoot)$\System32\WindowsPowerShell\v1.0\powershell.exe`と記載します。「**パラメータ**」にはHello.ps1のパスを指定します。
![aa-openprogram10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/2cff005b-5a62-0e54-ae77-11f131dfb62f.png)

前述のエラー処理も取り入れると、アクションリストは以下のようになります。
![aa-openprogram11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/15c42fe3-13b7-b8c9-b847-1c66c8711ba2.png)

これで実行すると、やはり以下の通りスクリプトが実行されることがわかります。
![aa-openprogram09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/01bee95a-2fa3-c003-6a6d-002883c7eab8.png)

#### 外部モジュールでの処理を待つようにする
ちなみに、今回の**Open Program/File** アクションは、外部スクリプト呼出し後、処理を待たずに次のアクションに移ってしまうので、外部スクリプトの結果を待つには、たとえば共通のテキストファイルをコミュニケーション用に用意して、値が書き込まれたら次の処理に移る、などの工夫が必要です。たとえば以下のようにアクションリストを設定してみると、PowerShellでのダイアログボックスで「OK」ボタンをクリックした直後に、アクションリストの次のダイアログボックスが表示されることがわかります。
![aa-openprogram12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/d2b8e5e9-39af-febe-653d-a090e86d1f88.png)

```PowerShell:Hello.ps1
Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("Hello World!!", "こんにちは")
"Done`n" > "C:\Automation-Anywhere-Temporary-Folder\result.txt"
```


# (おまけ) 同様の方法でPython スクリプトも実行
以上の方法は、PowerShellに限らず、ほかのスクリプトでも応用可能です。Python については、インストーラでセットアップを行うと、.pyファイルがpython.exeに関連付けられているので、そのまま.pyファイルを指定して実行可能です。以下のようなアクションリストとPythonスクリプトを組むことで、同様の処理を行うことができます。(以下はPython 3.6以上での例)

(注) [Python.org](https://www.python.org/downloads/)または[Windows Store](https://www.microsoft.com/ja-jp/p/python-37/9nj46sx7x90p)よりPythonモジュールがインストール済みであることを前提としています。
Anaconda ([最新版](https://www.anaconda.com/distribution/)および[アーカイブ](https://repo.continuum.io/archive/))は.pyとの関連付けはされません。
![aa-openprogram13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/1471cbc3-f9e8-2313-c91b-75baa24d6b70.png)


```Python:Hello.py
import pathlib
key = input('Hello World!')

p_text = pathlib.Path('C:\Automation-Anywhere-Temporary-Folder\result.txt')
p_text.write_text('Done')
```

# (おまけ) Python 実行用の Meta Bot が Bot Store にあります
実施している内容は上記と似ているようですが、Bot Store からのダウンロードで実施する方法もあります。Python.mbot が追加されます。

* [Execute Python Code](https://botstore.automationanywhere.com/bot/execute-python-code/) (By  Intellimorph)


|ロジック|Inputパラメータ|Outputパラメータ|説明|
|:--|:--|:--|:--|
|RunPythonCode|vPythonPath, vScriptPath, vWaitForCompletion, vArgs|vReturnValue|vPythonPath にあるpython.exeを実行して、任意の数の引数を配列として渡して戻り値を得る。Pythonの処理を待つかどうかを選べる。|
|RunPythonCodeWithStringArgs|vArgs, vPythonPath, vScriptPath, vWaitForCompletion|vReturnValue|道場だが、引数の形式が文字列1つになっている。|