VBAからPowerShellを起動し、任意コマンドを実行する


VBAからPowerShellを任意コマンドで実行するため、いろいろ調べて辿り着いた結果を記しました。

コード

runPshell.bas
Function runPshell(psCmd As String, intVsbl As Integer, waitFlg As Boolean)
'**** VBAからPowerShellを起動し、任意のコマンドを実行する  *********
' psCmd   : PowerShellコマンド(PowerShell仕様により260文字以内)
' intVsbl : PowerShell画面表示(1)/非表示(0)
' waitFlg : PowerShell実行終了を待つ(True)/待たない(False)
'***************************************************************
    Dim objWSH As Object
    Set objWSH = CreateObject("WScript.Shell")

    objWSH.Run "powershell -NoLogo -ExecutionPolicy RemoteSigned -Command " & psCmd, intVsbl, waitFlg

End Function

使用例として、txtファイルをコピーするコードを示しました。

hoge.bas
Option Explicit
Sub TestPs()
    Dim sPath As String
    Dim dPath As String
    Dim psCmd As String
    Dim hoge As Variant

    sPath = "C:\work\hoge.txt"
    dPath = Replace(sPath, "hoge", "huga")
    psCmd = "Copy-Item " & sPath & " " & dPath
    hoge = runPshell(psCmd, 0, True)
End Sub

コメント

  • 参照設定をユーザに操作させたくなかったのでCreateObject("WScript.Shell")を使っています。
  • 変数intVsblでPowerShell画面の表示(1)/非表示(0)を選択できます。
  • 変数waitFlgでPowerShell実行完了を待つ(True)/待たない(False)を選択できます。
  • PowerShellの仕様上、コマンド格納変数psCmdの文字長は260文字以内です。パスが深いファイルのコピーなどは注意が必要です。

開発経緯など

ファイルを圧縮してサーバに転送したい!という仕事での要望に応えるために開発しました。圧縮、転送中もVBAが動くようにできない?という要望から、処理をOSに渡すのがいいと思い、PowerShell使用となりました。
VBAのFileCopyだとコピー処理完了まで他のことができませんが、PowerShellに渡してしまえばVBAが次の処理に入れるので効率的です。なお、変数waitFlgでPowerShellの処理完了を待つようにも設定できます。
# 待つならFileCopyでもよくね?というのは置いといて。。。
参考サイトは各機能に特化したコードでしたが、もしかしてコマンド自体を引数で渡せば汎用化できる?と思い今回のFunctionとなりました。
最初は.Execで作っていましたが、PowerShell画面が邪魔!ということで、画面非表示機能を追加するために.Runを採用しました。
開発過程で、PowerShellコマンドに文字長制限があることが分かりました。ファイル転送がうまく行かずよくよく調べると、パスが深すぎて文字長制限に引っかかっていたようでした。Cドライブ直下に転送用フォルダを掘り、対応しました。
ひと段落ついて、さて記事にしようかとふと調べると、ほぼ同じことしているQiita記事を見つけたので一緒に紹介しておきました。

参考サイト

VBAでZIP圧縮と解凍を行う
PowerShell VBAでPowerShellを実行して結果を取得する(Run編)【初実験編08】
VBAからpowershellコマンドを実行(Qiita)