UIPathでPowerShellを実行する方法

Table of Content

はじめに

UiPathでPowerShellを起動することを考えてみます。

アクティビティの一覧を見ていると2つほど案が思いつくと思います。

1つ目はStartProcessアクティビティでプロセスを開始する方法
2つ目はInvokePowerShellアクティビティで実行する方法です。

今回は以下のようなPowerShellを実行する方法を考えてみます。

list.ps1

Param(
    [String]$Path
)
$ErrorActionPreference="Stop"
if ($Path -eq "") {
    Set-Content C:\share\test\result.txt -Value "error "
    throw "Error"
}
try {
    $ret = Get-ChildItem -Path $Path -Filter *.txt
    Set-Content C:\share\test\result.txt -Value $ret
    return $ret
} catch {
    Set-Content C:\share\test\result.txt -Value $_
    throw "Error"
}

動作環境

・UiPath Community Edition 2019.6.0
・C#プロジェクト
・Windows 10
・PowerShell5.1

StartProcessアクティビティ

単純な例では以下のようなフローになります。
image.png

プロセスを開始

プロパティ名 設定値
ファイル名 @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell"
引数 @"-ExecutionPolicy RemoteSigned -File C:\share\test\list.ps1 C:\share\"

これでPowerShellが起動してスクリプトが実行されます。
しかし、StartProcessアクティビティは非同期な処理でプロセスの終了を待ちません。
このことは、PowerShellスクリプト実行後に後続の処理がある場合に問題になります。
※list.ps1の例だと作成されたresult.txtを利用してなにかをする場合

この問題の回避策は下記で議論されています。

Make Start Process wait until the end of the command in cmd
https://forum.uipath.com/t/make-start-process-wait-until-the-end-of-the-command-in-cmd/15551

ここで挙げられた回避策は以下の3つになります。

  • 案1:画面要素を監視してスクリプトの終了を検知する
  • 案2:もしファイルを出力するスクリプトであるなら、そのファイルの更新を検知する
  • 案3:PowerShellのWait-Process を使用してプロセスの終了を検知する。

案1はOnUiElementVanishアクティビティを使用することになりますが、非同期で動作しているためこのアクティビティに到達した時点で、すでに画面が終了している可能性もありますし、逆にこのアクティビティを通過してしまった後に画面が表示される可能性があります。

案2はMonitorEventsアクティビティ内にFileChangeTriggerアクティビティを配置してファイルの最終更新日やサイズを監視して変化があったら終了とみなす方法ですが、これもイベント監視の前にファイルの操作が終わる可能性があります。

案3はStartProcessアクティビティで対応する方法でなく、InvokePowerShellアクティビティで対応する方法になります。

つまり結論を述べると、StartProcessアクティビティでPowerShellを起動して終了を待つのは適していません。

InvokePowerShellアクティビティ

TypeArgumentプロパティについての注意

InvokePowerShellアクティビティを使用する場合、TypeArgumentプロパティには注意をする必要があります。

これはスクリプト内で返却されたオブジェクトの型にキャストできるものでなければなりません。
たとえば、「コマンドテキスト」プロパティに以下のコマンドレットを記述したとします。

Get-ChildItem

FileInfoDirectoryInfoのコレクションが返却されます。TypeArgumentプロパティにはコレクション内の型がキャスト可能な値、すなわちベースクラスであるObjectやFileSystemInfoを指定する必要があります。

もしこのことを守らないと以下のようなエラーが発生します。
image.png

次に、以下のようなコマンドレットを記述します。

Get-Process
Get-ChildItem

またスクリプトの入力にはチェックを付けてください。

image.png

これを実行すると、System.Diagnostics.Processのアイテムが続いたあとに、FileInfoDirectoryInfoのアイテムが続くコレクションが返されます。

つまり、スクリプト内で出力されたオブジェクトは全て受け取れることを意味しており、また、そのオブジェクトを受け入れられる型をTypeArgumentに指定する必要があります。

PowerShellのスクリプトファイルパスを指定

以下にlist.ps1のPowerShellのスクリプトを実行してその結果をデバッグ出力するサンプルを記載します。

image.png

PowerShellを呼び出し

プロパティ名 設定値
TypeArgument System.IO.FileSystemInfo
スクリプト入力 チェックON
コマンドテキスト @"C:\share\test\list.ps1 C:\share\"
パラメータ なし
出力 result※ctrl+kで変数を作成

繰り返し(コレクションの各要素)

プロパティ名 設定値
TypeArgument System.IO.FileSystemInfo
コレクション値 result

image.png

1行を書き込み

プロパティ名 設定値
テキスト item.FullName

InvokePowerShellアクティビティの「コマンドテキスト」プロパティにはファイル名を与えることができます。
この場合、「パラメータ」プロパティによるスクリプトによるパラメータの設定はできないようなので、「コマンドテキスト」プロパティのスクリプト名に続けてスクリプトに与えたいパラメータを記載します。

PowerShellのスクリプトの内容を指定

スクリプトの内容をあらかじめ読み込んでおいて、実行することも可能です。
この場合、「パラメータ」プロパティを利用してPowerShellのスクリプトのパラメータを指定することができます。
PowerShellのスクリプトファイルパスを指定する場合と異なり、.NETの型をそのまま渡せるメリットがあります。

image.png

テキストファイルを読み込む

プロパティ名 設定値
ファイル名 @"C:\share\test\list.ps1"
出力 script※ctrl+kで作成

PowerShellを呼び出し

プロパティ名 設定値
TypeArgument System.IO.FileSystemInfo
スクリプト入力 チェックON
コマンドテキスト script
パラメータ 名前:Path 型:String 値:@"C:\share"
出力 result※ctrl+kで変数を作成

繰り返し(コレクションの各要素)
PowerShellのスクリプトファイルパスを指定する場合と同じ

まとめ

UiPathでPowerShellを起動する場合はInvokePowerShellアクティビティを使用します。
ファイルパスを直接与えるか、一旦、スクリプトファイルを読み込んでから渡すかは、パラメータを文字で渡すかオブジェクトで渡すかで検討した方がいいでしょう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です