前提・実現したいこと
VBAからpowershellスクリプトを利用したいです。
尚且つ 非同期で実行したいです。
ホントは引数や返値で配列、もっと欲を言えばオブジェクトをやり取りしたいところですが
引数はVBA側で自身の最新状態のコピーを作成してpowershell側でそれを別プロセスで開いてアクセスすればいけそう。。。
返値もpowershell側でExcelを開ければVBA側でオブジェクトを特定できる文字列が返せる気がするので
後回しにします...(でもいい方法があれば知りたいです!)
powershell非表示で実行で調べるとWshのRunを使って非表示で実行する方法が出てくるのですが
返値がテキストファイルに書き出して読み込みとかしないと受け取れなかったりとか
Exec
ならステータスの確認が出来たり, stdin
なるもの が何かに使えそうだと思ったので
今のところはそちらを使いたいと考えています。(もっといい方法があればためらいなく乗り換えます。)
試したこと
とりあえず powershellのウィンドウが一瞬表示されてしまうのは
諦めて作成してみました。
windows script host object model
を参照設定しています。
使用例ではStdOut.ReadAll
を実行した際 処理が終わってなければ勝手に待機してくれることが分かったので
Status
の確認はしていません。
Run
等で実行した後にプロセスを取得できないか?等といろいろ探してみたのですがいい方法が見つけられませんでした。
何か良い手はないのでしょうか
作成したコード
vba
1Function MyPowershell(Optional ByVal ScriptName As String, Optional ByVal FunctionName As String, Optional Argument As String, Optional Exec As WshExec, Optional ByVal StdinClose As Boolean = True) As WshExec 2'Powershellスクリプトを実行してWshExecオブジェクトとして返す 3 4 Dim Wsh As New WshShell 5 If StdinClose And FunctionName <> "" And Exec Is Nothing Then 6 '処理一括実行 7 Dim Cmd As String 8 If ScriptName <> "" Then 9 Cmd = ". '" & ScriptName & "';" 10 End If 11 Set Exec = Wsh.Exec("powershell -NoLogo -ExecutionPolicy RemoteSigned -windowstyle hidden -command " & "Set-Location -Path('" & ThisWorkbook.Path & "');" & Cmd & FunctionName & " " & Argument) 12 Else 13 '処理随時実行 14 If Exec Is Nothing Then 15 Set Exec = Wsh.Exec("powershell -NoLogo -ExecutionPolicy RemoteSigned -windowstyle hidden") 16 End If 17 Call Exec.StdIn.WriteLine("Set-Location -Path('" & ThisWorkbook.Path & "')") 18 If ScriptName <> "" Then 19 Call Exec.StdIn.WriteLine(". '" & ScriptName & "'") 20 End If 21 If FunctionName <> "" Then 22 Call Exec.StdIn.WriteLine(FunctionName & " " & Argument) 23 Else 24 StdinClose = False 25 End If 26 If StdinClose Then 27 Exec.StdIn.Close 28 End If 29 End If 30 Set MyPowershell = Exec 31End Function 32 33Function MyPowershellStdOut(ByVal Exec As WshExec) As String 34'Powershellの返値を余分な文字を削除して返す 35 36 '標準出力を受け取る 37 Dim Str As String 38 Str = Exec.StdOut.ReadAll 39 40 '除外対象の文字列の削除 41 Dim BefStr As String 42 Dim RegExp_ As New RegExp 43 RegExp_.Pattern = "PS .:\.+?\n" 44 Do 45 BefStr = Str 46 Str = RegExp_.Replace(BefStr, "") 47 Loop While (BefStr <> Str) 48 RegExp_.Pattern = "PS .:\.+?> $" 49 Str = RegExp_.Replace(BefStr, "") 50 BefStr = Str 51 RegExp_.Pattern = "\n$" 52 Str = RegExp_.Replace(BefStr, "") 53 MyPowershellStdOut = Str 54End Function
実行されるpowershellスクリプト
powershell
1function test([String]$Str){ 2 Start-Sleep -s 3; write-host $Str 3}
使用例
vba
1Sub test() 2'LoopCountに設定されている数分同時実行を行う 3'Boundary の指定以上は随時実行に変更 4 5 Const LoopCount As Long = 10 6 Const Boundary As Long = 5 7 8 Dim Exec() As WshExec 9 Dim i As Long 10 ReDim Exec(LoopCount) 11 For i = 0 To LoopCount 12 If i <= Boundary Then 13 Set Exec(i) = MyPowershell(".\t est.ps1", "test", """入力テスト" & i & "`r`n二行目の入力テスト""") 14 Else 15 Set Exec(i) = MyPowershell(".\t est.ps1") 16 End If 17 Next i 18 19 '追加の実行 20 Dim j As Long 21 For j = 0 To LoopCount 22 If j > Boundary Then 23 Set Exec(j) = MyPowershell(, "test", """入力テスト" & j & "`r`n二行目の入力テスト""", Exec(j)) 24 End If 25 26 Next j 27 28 '結果の取得 29 Dim Str() As String 30 Dim k As Long 31 ReDim Str(LoopCount) 32 For k = 0 To LoopCount 33 Str(k) = MyPowershellStdOut(Exec(k)) 34 Next k 35 36 '結果の表示 37 MsgBox Join(Str, vbCrLf) 38End Sub

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/11 04:52
2018/08/11 05:35
2018/08/11 05:59 編集
2018/08/11 06:05
2018/08/11 06:22
2018/08/11 06:28
2018/08/11 07:26
2018/08/11 07:35
2018/08/13 01:50