Power Automate Desktopでpyファイルを実行

# 書いた背景
Power Automate DesktopでWebスクレイピングや、文字列処理をしたいとき組み込みの関数では工数が多いor実現できないことが多い。
「pythonを実行する」アクションではpython2しか使用できず、モジュールのimport設定も面倒

# 解決策
DOSコマンド実行、からpyファイルを実行する

# 引数無し
## シンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/71704bcd-6133-30b8-bf09-0a936510a61d.png)

```python:1.py
print("test")
```

- .pyファイルとそのファイルが存在するフォルダを指定して実行
- print文で記載した内容が`CommandOutput`に文字列として格納されます


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/7e008319-6791-8cd7-dd7b-55b07cf30cd4.png)

## 複数print
```python:2.py
print("test1")
print("test2")
print(3)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/34d5360e-aa39-4388-117e-ecc6e5623882.png)
- 複数print文を記載すると改行ありで内容がテキストとして取得できます


## 辞書型
```python:3.py
data = {"a": 1, "b": 2, "c": 3, 4: "four"}
print(data)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/96cafed9-33d1-8c5b-7f55-8157f7164b50.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/1cc7f321-a6b3-6113-cde1-bba4b3feda25.png)
- 辞書型としてprint出力し、得られた値をJSON→オブジェクト変換することで、カスタムオブジェクトとして使用できます
- 1対1のデータがあるときに重宝する

# リスト
```python:4.py
data = []
for i in range(10):
    data.append(i)
print(data)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/d82ece7a-6077-613c-b959-c3b46e0edfce.png)

- 辞書型の際と同じくJSONをオブジェクト変換でリスト取得可能


# 引数あり
## 引数少なめ
```python:5.py
import sys

args = sys.argv
print(args[0])
print(args[1])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/c7e6fc3d-f36e-f162-9fa8-e7a93c9bed8a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/2a2962f5-acb2-687a-5bfe-524d727af586.png)
- `args[0]`に実行ファイル名（full path）
- `args[1]`以降に空白区切りで実行時に記載した値がテキストとして表示される


## 引数がリスト
```python:6.py
import sys

txt = sys.argv[1]
data = eval(txt)
print(data[0])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/56c46307-db7a-1e79-4b31-cd056457d6b4.png)
- リストに文字列が入っている場合は全体をダブルクオーテーションで囲み、文字列自体はシングルクオーテーションで囲む


## 引数が辞書型
```python:7.py
import json
import sys

txt = sys.argv[1]
jsonData = txt.replace("'", '"')
data = json.loads(jsonData)
print(data["a"])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/0315079a-9996-9bf3-90e6-09c1d276ef01.png)
- 全体をダブルクオーテーションで囲み、Keyをシングルクオーテーションで囲む
- windowsのdosコマンドでは`"`が消える仕様のため、一旦`'`で囲んでおいて`"`に置換することでJSON形式として認識させている

# PADコマンド間でのデータの受け渡し
## Excel→Python
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/cd112a68-7738-d2b4-af57-d3132c009d3f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/00fc61c0-8f14-06ca-b7bf-43c4da51c977.png)
```python:8.py
import json
import sys

print(sys.argv)
txt = sys.argv[1]
jsonData = txt.replace("'", '"')
data = json.loads(jsonData)
print(data["ExcelData"][0]["name"])
```

4工程も含まれてしまって少々面倒ですが、実現自体は可能です。
1. 変数の設定
    - あえて変数に`{'ExcelData': %ExcelData%}`を格納することでカスタムオブジェクトを作成します
2. カスタムオブジェクトをJSONに変換
    - JSON（テキスト）に変換することで、DOSコマンド実行時に渡せる形に変更します
3. テキストを置換する
    - `"`を`'`に変更します
4. DOSコマンドの実行
    - `8.py "%json%"`
    - 上記のように`'`で囲って指定することで「引数が辞書型」の時に指定した形を実現します

## Python→Python
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/bf026c62-58c5-eefb-4f30-40f5d4729416.png)


```txt:PAD flow
@@copilotGeneratedAction: 'False'
Scripting.RunDOSCommand.RunDOSCommand DOSCommandOrApplication: $'''9.py''' WorkingDirectory: $'''C:\\Users\\xxxx\\programs\\Qiita\\pad''' StandardOutput=> CommandOutput StandardError=> CommandErrorOutput ExitCode=> CommandExitCode
Text.Replace Text: CommandOutput TextToFind: $'''\"''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''\'''' ActivateEscapeSequences: False Result=> json
@@copilotGeneratedAction: 'False'
Scripting.RunDOSCommand.RunDOSCommand DOSCommandOrApplication: $'''10.py \"%json%\"''' WorkingDirectory: $'''C:\\Users\\xxxx\\programs\\Qiita\\pad''' StandardOutput=> outputdata StandardError=> CommandErrorOutput ExitCode=> CommandExitCode

```
```python:9.py
data = {"a": 1, "b": 2, "3": "data"}
print(data)
```
```python:10.py
import json
import sys

txt = sys.argv[1]
jsonData = txt.replace("'", '"')
data = json.loads(jsonData)
print(data["3"])
```
- pythonを実行して返ってくるのはテキスト型→つまりJSON
- シンプルに`"`を`'`に置換して渡せばよい


## Python→Excel
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/7393bb20-06ba-fcf2-462f-a3811dc5088f.png)

```PAD flow
@@copilotGeneratedAction: 'False'
Scripting.RunDOSCommand.RunDOSCommand DOSCommandOrApplication: $'''11.py''' WorkingDirectory: $'''C:\\Users\\xxxx\\programs\\Qiita\\pad''' StandardOutput=> CommandOutput StandardError=> CommandErrorOutput ExitCode=> CommandExitCode
Variables.ConvertJsonToCustomObject Json: CommandOutput CustomObject=> object
Excel.LaunchExcel.LaunchUnderExistingProcess Visible: True Instance=> ExcelInstance
Excel.WriteToExcel.WriteCell Instance: ExcelInstance Value: object['area1'] Column: $'''A''' Row: 1
Excel.WriteToExcel.WriteCell Instance: ExcelInstance Value: object['area2'] Column: $'''B''' Row: 1
```
```python: 11.py
data = {"area1": [], "area2": []}
data["area1"] = [i for i in range(10)]
data["area2"] = [i * 2 for i in range(10)]

print(data)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2150464/3113387f-45cd-579a-76e7-d42af7ff78d4.png)

- Python側で、Excelに渡したいデータをリスト型で定義しておく
- Pythonから返ってきたテキストをカスタムオブジェクトに変換して、そのままExcelに書き込めばOK
- リストの値は縦に入力される


# まとめ
ローカルでpyファイルを実行することで、モジュールの制限なし＆Python3で実行することができました。
PADでのデータのやり取りも問題なくできそうなので、ぜひ活用してみてください！