Power Automate DesktopでSAPデータ抽出の自動化

社内では定型業務としてSAPからデータ抽出を行っている人が多かったので、Power Automate Desktop(PAD)とSAP GUI Scriptingで自動化できないか試したときのことを記載します。

この記事ではPADの基本的な使い方は説明していません。また、ざっと作ったレベルでエラーハンドリングは考慮されていないのでご了承ください。

## シナリオ
毎週月曜日にR1Pのトランザクションコード「ZZZYYY」を使用し、下記の条件でデータを抽出し、ファイルを指定の場所に保存    

「Layout」：BBB_BBB
「Plant」：A001
「Actual Start Date/End Date」：実行日の前週を指定（1/10が実行日の場合、1/4~1/9の日にちを指定）
「Order Type」：AB01

## 事前準備
・SAP GUIの設定
スクリプト実行を許可するために、SAP GUI OptionのAccessibility & Scripting => Scriptingで"Enable Scripting"にチェックし、その他はチェックを外して、"OK"をクリックして保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/168a193b-d6a3-9060-aa6a-f6618fc0f15a.png)

ファイルの保存時にセキュリティ用の確認画面を表示させないようにするため、SAP GUI OptionのSecurity => Security Settingsをクリックし、Open Security Configurationをクリックし、Default actionを"Allow"に変更し、"OK"をクリックして保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/d79143a6-5b1e-e615-ce62-3ee4487a3d22.png)

## Flowの概要
アクションを４つのSubflowにわけて構成し、Main Flowで繋げました。Subflowは、フローを分割して部品化することができる機能です。Main Flowにアクションを追加していくこともできるのですが、長くなっていくと見づらい&メンテナンスがしづらいので主なアクション毎にSubflowにわけて作成することをお勧めします。他の方が見たときに見やすいというメリットもあるかと思います。

Subflowは下記の４つです。
①Extract_Date_from_CurrentDay：抽出データの範囲指定をするための日付情報を取得する動作
②SAP_logon：SAP GUIを使ってR1Pにログインする動作
③Extract_Data：SAP GUI Scriptingを使ってデータを抽出する動作
④SAP_logout：SAP GUIをクローズする動作

#### Main Flow
４つのSubflowを下記の順番で実行するようにつなげています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/f4d84ea7-b1ee-5cb7-ac1e-83e27d8aaa71.png)


#### Subflow：① Extract_Date_from_CurrentDay

データ抽出を日付で範囲指定するために、フローの実行日を基準に日付情報を変数として設定するフローです。フローの実行日を取得するためにGet current date and timeを使用しています。

データ抽出の範囲は実行日の１週間前になるため、実行日以外にAdd to datetimeを使って７日前の日付と１日前の日付も変数として設定しています。SAPに日付を入力する際に、20221201という形で入力したかったので、最終的に日付はConvert datetime to textを使ってテキスト型に変換しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/ee33fdb5-0a55-5266-06a6-75e84a88d682.png)


#### Subflow：② SAP_logon

Run applicationを使ってSAP GUIを起動＆ログオンするフローです。私のPCの環境ではSAP GUIはC:\Program Files (x86)\SAP\FrontEnd\SapGui\saplogon.exeにインストールされていますので、起動するアプリケーションのパスを設定する箇所にはこちらを指定しました。

その後、デスクトップレコーダーで操作を記録します。フローデザイナー画面にある◎をクリックしてデスクトップレコーダーを起動し、一連の操作を記録してください。デスクトップレコーダーの操作は要素が認識されていることを確認しながら行ってください。記録した操作は後で編集することも可能です。デスクトップレコーダーの使い方の詳細はこちらをご覧ください。

https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/recording-flow

※デスクトップレコーダーを使うときはブラウザがPowerAutomate Desktop Extensionをダウンロードするためのポップアップが表示されるため、事前に全てのブラウザを閉じておくことをお勧めします。

※画面の切り替わりに時間がかかるところに適宜Waitを入れることをお勧めします。

※SAPのログインはSAP起動（Run application）のステップで、コマンドライン引数に /SHORTCUT="-system="R1P" -client="100" " を入力ことでも対応できます。トランザクションコードまで指定することも可能です。コマンドライン引数で指定した方が失敗する確率は下がります。

例) ユーザーに MEIFAN_MMMを指定して、実行するTransaction CodeがAB12の場合

コマンドライン引数に下記を追加

/SHORTCUT="-system="R1P" -client="100" -user="MEIFAN_MMM" -type="Transaction" -command="AB12" "

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/5d9ee48f-9f59-ce90-2e54-ddc91036d5e1.png)


​​​​​
#### Subflow：③ Extract_Data

SAPでデータを抽出するためのフローです。トランザクションコードの入力以降のステップもデスクトップレコーダーで作成しようと思ったところ、認識できない要素があったため、コードの指定にはSAP GUI Scriptingの機能を使いました。SAP GUI Scriptingもデスクトップレコーダーのように記録したものを自動でスクリプトに起こしてくれるので便利です。SAP GUI Scriptingの使い方はこちらをご覧ください。

SAP GUI Scriptingで下記の値を指定しながら操作を行い、データの抽出＆ファイル保存をします。

「トランザクションコード」：ZZZYYY
「Layout」：BBB_BBB
「Plant」：A001
「Actual Start Date/End Date」：実行日の前週を指定（1/10が実行日の場合、1/4~1/9の日にちを指定）
「Order Type」：AB01

保存されたスクリプトを開いてコードを確認し、一旦このコードをそのままRun VBScriptにコピペします。"#ここを書き換え"と追記したところが値が指定されているところになります。日付については実行日に応じて変更するのでSubflow: Extract_Date_from_CurrentDayで作成した変数をそれぞれ指定します。保存するファイル名にも日付データをつけたので、変数を指定しています。

またPADでは%は変数の文字として扱うため、スクリプト内に変数以外で使われている%の文字があれば%%と変更してください。変更しないと保存時にSyntax errorが発生します。

```
If Not IsObject(application) Then
   Set SapGuiAuto  = GetObject("SAPGUI")
   Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
   Set connection = application.Children(0)
End If
If Not IsObject(session) Then
   Set session    = connection.Children(0)
End If
If IsObject(WScript) Then
   WScript.ConnectObject session,     "on"
   WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/tbar[0]/okcd").text = "ZZZYYY"　#ここを書き換え
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ssub%%_SUBSCREEN_TOPBLOCK:PPIO_ENTRY:1100/ctxtPPIO_ENTRY_SC1100-ALV_VARIANT").text = "/BBB_BBB"　#ここを書き換え
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_WERKS-LOW").text = "A001"　#ここを書き換え
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_PWERK-LOW").text = ""
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_AUART-LOW").text = "AB01"　#ここを書き換え
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_ISTST-LOW").text = "%FormattedDateTimeStart%"　#ここを書き換え
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_ISTST-HIGH").text = "%FormattedDateTimeEnd%"　#ここを書き換え
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_ISTST-HIGH").setFocus
session.findById("wnd[0]/usr/tabsTABSTRIP_SELBLOCK/tabpSEL_00/ssub%%_SUBSCREEN_SELBLOCK:PPIO_ENTRY:1200/ctxtS_ISTST-HIGH").caretPosition = 8
session.findById("wnd[0]/mbar/menu[0]/menu[0]").select
session.findById("wnd[0]/usr/cntlCUSTOM/shellcont/shell/shellcont/shell").pressToolbarContextButton "&MB_EXPORT"
session.findById("wnd[0]/usr/cntlCUSTOM/shellcont/shell/shellcont/shell").selectContextMenuItem "&XXL"
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[1]/usr/ctxtDY_PATH").text = "C:\Users\username\Downloads"　#ここを書き換え
session.findById("wnd[1]/usr/ctxtDY_FILENAME").text = "SAP_%FormattedDateTime%.xlsx"　#ここを書き換え
session.findById("wnd[1]/usr/ctxtDY_FILENAME").caretPosition = 15
session.findById("wnd[1]/tbar[0]/btn[0]").press
```

スクリプトの実行後、Excelファイルが開いたままになるため、クローズの処理を行っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/1f9d81ca-7b95-2873-df4d-33f01b6923f2.png)


#### Subflow：④ SAP_logout

最後にSAP GUIのログアウト/クローズを行います。デスクトップレコーダーで操作を記録しましたが、認識しない要素でショートカットで代替できるところはSend keysを使ってショートカットキーを送信しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/98503214-de83-528a-962a-0a09bb912346.png)


#### 最後に
このフローをスケジュール実行するためにPower Automateでスケジュール設定のフローを作成＆設定をします。

今回は毎週月曜日朝10時に実行するように設定しました。スケジュール実行するためのライセンスとしてUnattendedかAttendedのモードを選択できますが、手元にはPower Automate per user with attended RPA planのライセンス（※）しかなかったのでAttendedモードで設定しています。その場合は実行時間にPCに実行ユーザーでログインされている状態を準備する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952241/984cecfd-7d9b-622d-656e-188e6b2464e6.png)


## 参考サイト​​​​​​
このフローを作成するにあたり、下記のサイトを参考にしました。

https://docs.microsoft.com/ja-jp/power-automate/guidance/rpa-sap-playbook/action-based-sap-gui-automation-recorder-overview


https://blogs.sap.com/2021/10/21/auto-login-sap-gui-with-power-automate-desktop/

https://www.youtube.com/watch?v=1206jLK0byU

以上。