- ねらい:VBAから「WindowsのShell」を使いこなし、外部処理を安全に操る
- 実行モデルと共通枠(必ず復帰させる)
- コマンドライン実行:WScript.Shell.Runで「待つ・判定する」
- 既定アプリで開く・印刷する:Shell.ApplicationのShellExecute
- ZIP圧縮・展開:Shell 名前空間で“使い勝手重視”
- ショートカット(.lnk)作成:WScript.Shellで“起動器”を配布
- エクスプローラの操作:フォルダを開く・選択を表示する
- PowerShellブリッジ:JSON・API・高度処理は外部へ委譲
- ファイル・フォルダのShell拡張操作:プロパティ、リサイクル、タイムスタンプ
- 例題の通し方と確認ポイント
- 落とし穴と対策(深掘り)
- まとめ:Shellは「待つ・クオート・後片付け」を徹底すれば、強い相棒になる
ねらい:VBAから「WindowsのShell」を使いこなし、外部処理を安全に操る
Shell拡張は、VBAからWindowsのコマンド、エクスプローラ、既定アプリ、ZIP、ショートカットなど“OS標準の力”を呼び出す設計です。最優先は「完了待ち」「引数の正しいクオート」「後片付け(例外でも到達)」の枠を入れること。これだけで、初心者でも壊れにくく、実務で回せる外部連携が組めます。
重要ポイントの深掘り
Shellは「投げっぱなし」だと壊れます。見えない失敗を防ぐため、非表示実行+戻り値チェック+待機が基本です。ファイルパスは必ずダブルクォートで囲み、UTF-8やロケールの違いを吸収します。ShellExecuteは「既定アプリで開く/印刷/ZIP」に強く、WScript.ShellのRunは「戻り値で成否判定」ができ、使い分けが肝心です。
実行モデルと共通枠(必ず復帰させる)
開始・終了の共通枠
' ModApp.bas
Option Explicit
Public Sub AppEnter(Optional ByVal status As String = "")
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
If Len(status) > 0 Then Application.StatusBar = status
End Sub
Public Sub AppLeave()
Application.StatusBar = False
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
VB例外でも復帰する入口テンプレ
' ModEntry.bas
Option Explicit
Public Sub Run_SafeShell()
On Error GoTo EH
AppEnter "Shell"
' …ここで外部処理…
AppLeave
Exit Sub
EH:
AppLeave
MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
VBコマンドライン実行:WScript.Shell.Runで「待つ・判定する」
非表示実行+戻り値で判定(最短で実用)
' ModShellExec.bas
Option Explicit
Public Function RunCmdWait(ByVal cmd As String) As Long
Dim sh As Object: Set sh = CreateObject("WScript.Shell")
RunCmdWait = sh.Run(cmd, 0, True) ' 0=非表示, True=完了まで待つ
End Function
Public Sub Demo_CmdEcho()
On Error GoTo EH
AppEnter "Cmd"
Dim outPath As String: outPath = ThisWorkbook.Path & "\hello.txt"
Dim cmd As String
cmd = "cmd /c echo Hello World> """ & outPath & """"
Dim rc As Long: rc = RunCmdWait(cmd)
If rc <> 0 Then Err.Raise 8001, , "外部コマンドがエラー終了: " & rc
AppLeave: MsgBox "完了: " & outPath
Exit Sub
EH:
AppLeave: MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
VB重要ポイントの深掘り
「待たない」Runは事故の素です。必ず True で待機し、戻り値で成否判定します。パスや引数はダブルクォートで囲み、スペースや日本語を確実に通します。cmd /c は一度きりの実行に適し、複雑系はPowerShellへ委譲すると安定します。
既定アプリで開く・印刷する:Shell.ApplicationのShellExecute
既定プログラムで “開く” “印刷” を指示
' ModShellVerb.bas
Option Explicit
Public Sub OpenWithDefault(ByVal path As String)
Dim sh As Object: Set sh = CreateObject("Shell.Application")
sh.ShellExecute path, "", "", "open", 1 ' 1=通常ウィンドウ
End Sub
Public Sub PrintWithDefault(ByVal path As String)
Dim sh As Object: Set sh = CreateObject("Shell.Application")
sh.ShellExecute path, "", "", "print", 0 ' 印刷は非表示が多い
End Sub
Public Sub Demo_Open_Print()
OpenWithDefault ThisWorkbook.FullName
PrintWithDefault ThisWorkbook.Path & "\report.pdf"
End Sub
VB重要ポイントの深掘り
ShellExecuteは「関連付け」に従うため、PDFや画像、txtを“既定アプリ”で処理できます。操作は“verb(動詞)”で指定し、open/print/preview などが使えます。印刷はアプリやプリンタに依存するので、運用PCでの事前確認が必須です。
ZIP圧縮・展開:Shell 名前空間で“使い勝手重視”
フォルダをZIPに圧縮する
' ModZip.bas
Option Explicit
Public Sub ZipFolder(ByVal srcFolder As String, ByVal zipPath As String)
On Error GoTo EH
If Dir(zipPath, vbNormal) <> "" Then Kill zipPath
CreateEmptyZip zipPath
Dim sh As Object: Set sh = CreateObject("Shell.Application")
Dim src As Object: Set src = sh.NameSpace(srcFolder)
Dim dst As Object: Set dst = sh.NameSpace(zipPath)
If src Is Nothing Or dst Is Nothing Then Err.Raise 8002, , "パス不正"
dst.CopyHere src.Items, 16 ' 16=進捗なし・非表示
Application.Wait Now + TimeValue("0:00:02") ' ざっくり待機(必要ならファイル数で待ち調整)
MsgBox "圧縮完了: " & zipPath
Exit Sub
EH:
MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
Private Sub CreateEmptyZip(ByVal zipPath As String)
Dim h As Integer: h = FreeFile
Open zipPath For Binary As #h
Put #h, , Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String$(18, Chr$(0))
Close #h
End Sub
VBZIPを展開する
Public Sub UnzipToFolder(ByVal zipPath As String, ByVal dstFolder As String)
On Error GoTo EH
Dim sh As Object: Set sh = CreateObject("Shell.Application")
If Dir(dstFolder, vbDirectory) = "" Then MkDir dstFolder
Dim zipNs As Object: Set zipNs = sh.NameSpace(zipPath)
Dim dstNs As Object: Set dstNs = sh.NameSpace(dstFolder)
If zipNs Is Nothing Or dstNs Is Nothing Then Err.Raise 8003, , "パス不正"
dstNs.CopyHere zipNs.Items, 16
Application.Wait Now + TimeValue("0:00:02")
MsgBox "展開完了: " & dstFolder
Exit Sub
EH:
MsgBox "失敗: " & Err.Description, vbExclamation
End Sub
VB重要ポイントの深掘り
ShellのZIPは「簡単で互換性が高い」反面、進捗や厳密な完了検知が弱いです。大容量や多数ファイルでは待機ロジックを少し厚めにし、実務では7zなど外部ツール+RunCmdWaitの組み合わせがより正確です。
ショートカット(.lnk)作成:WScript.Shellで“起動器”を配布
デスクトップにショートカットを作る
' ModShortcut.bas
Option Explicit
Public Sub CreateShortcut(ByVal targetPath As String, ByVal args As String, ByVal iconPath As String, ByVal linkName As String)
Dim sh As Object: Set sh = CreateObject("WScript.Shell")
Dim desk As String: desk = sh.SpecialFolders("Desktop")
Dim lnk As Object: Set lnk = sh.CreateShortcut(desk & "\" & linkName & ".lnk")
With lnk
.TargetPath = targetPath
.Arguments = args
.IconLocation = iconPath
.WorkingDirectory = CreateObject("Scripting.FileSystemObject").GetParentFolderName(targetPath)
.Save
End With
MsgBox "ショートカット作成: " & desk & "\" & linkName & ".lnk"
End Sub
Public Sub Demo_Shortcut()
CreateShortcut "notepad.exe", """" & ThisWorkbook.Path & "\readme.txt""", "notepad.exe", "Readmeを開く"
End Sub
VB重要ポイントの深掘り
配布や起動導線を“固定”できるのがショートカットの利点です。Argumentsは必ずダブルクォートで囲み、作業ディレクトリを設定して相対パスの誤動作を防ぎます。アイコン設定で現場の識別性も向上します。
エクスプローラの操作:フォルダを開く・選択を表示する
フォルダを開く/ファイルを選択表示する
' ModExplorer.bas
Option Explicit
Public Sub OpenFolder(ByVal folderPath As String)
Dim sh As Object: Set sh = CreateObject("Shell.Application")
sh.Open folderPath
End Sub
Public Sub SelectInExplorer(ByVal filePath As String)
Dim cmd As String
cmd = "explorer /select,""" & filePath & """"
Dim rc As Long: rc = RunCmdWait(cmd)
If rc <> 0 Then MsgBox "Explorer選択失敗: " & rc, vbExclamation
End Sub
VB重要ポイントの深掘り
ユーザーに「ここ」を見せる導線は復旧や運用効率に直結します。Openはフォルダを開くだけ、/select は対象ファイルを選択表示します。権限やネットワークパスの前提を運用で揃えると安定します。
PowerShellブリッジ:JSON・API・高度処理は外部へ委譲
PowerShellスクリプトを安全に呼ぶ
' ModPowerShellBridge.bas
Option Explicit
Public Sub RunPs1(ByVal ps1Path As String, ByVal args As String)
Dim sh As Object: Set sh = CreateObject("WScript.Shell")
Dim cmd As String
cmd = "powershell -ExecutionPolicy Bypass -File """ & ps1Path & """ " & args
Dim rc As Long: rc = sh.Run(cmd, 0, True)
If rc <> 0 Then Err.Raise 8010, , "PowerShell失敗: " & rc
End Sub
VB重要ポイントの深掘り
VBAはファイルI/OとExcel操作が得意、APIやJSONはPowerShellが得意。無理はせず、役割分担して“ファイルで契約”すると壊れにくく拡張しやすいです。ExecutionPolicyは運用ルールに従い、信頼済みフォルダや署名で安全性を高めます。
ファイル・フォルダのShell拡張操作:プロパティ、リサイクル、タイムスタンプ
ごみ箱へ送る(安全な削除)
' ModRecycle.bas
Option Explicit
Public Sub SendToRecycleBin(ByVal path As String)
Dim sh As Object: Set sh = CreateObject("Shell.Application")
Dim ns As Object: Set ns = sh.NameSpace(CreateObject("Scripting.FileSystemObject").GetParentFolderName(path))
Dim it As Object: Set it = ns.ParseName(CreateObject("Scripting.FileSystemObject").GetFileName(path))
If Not it Is Nothing Then it.InvokeVerb "delete" ' 既定はごみ箱へ
End Sub
VBタイムスタンプ確認(差分検知)
' ModStamp.bas
Option Explicit
Public Function LastWrite(ByVal path As String) As Date
Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(path) Then LastWrite = fso.GetFile(path).DateLastModified
End Function
VB重要ポイントの深掘り
削除は“ごみ箱送り”で事故を減らせます。ShellのInvokeVerbはエクスプローラの動詞(open, edit, delete など)を使えるため、簡単に既定の操作を呼べます。更新日時の差分監視は、外部ファイル取り込みのトリガー設計に役立ちます。
例題の通し方と確認ポイント
例題シナリオ
WordでPDF作成→エクスプローラで出力場所を開く→ZIPでまとめる→Outlookへ下書きメール作成→ショートカット配布、といった一連の流れを各テンプレで繋ぎます。
確認ポイント
完了待ちが機能しているか、戻り値で失敗を検知できているか、パスのクオート漏れがないか、外部アプリが確実に終了しているか。運用PCの権限・既定アプリ設定・ネットワークパス前提を最初に整えると、現場で安定します。
落とし穴と対策(深掘り)
待機不足による不定挙動
Runの待機(第三引数=True)と、Shell操作後の短いWaitを入れて安定化。ZIPや印刷のように“裏で続く処理”は余裕を持たせます。
クオート漏れによる失敗
すべてのパス・引数は “”” & path & “”” で囲む。日本語・スペース・記号を含む運用で必須です。
権限・既定アプリの差
企業環境ではポリシー差が出ます。既定アプリ、プリンタ、PowerShell実行ポリシーを運用ルールで固定し、事前にPCセットアップガイドを用意します。
UI自動化の不安定さ
SendKeysは最終手段。可能な限りShellExecuteやCOM、外部コマンドに置き換えます。
まとめ:Shellは「待つ・クオート・後片付け」を徹底すれば、強い相棒になる
WScript.Shell.Runで“待って判定”、ShellExecuteで“既定アプリ操作”、Shell名前空間で“ZIP・エクスプローラ”、WScript.Shellで“ショートカット”。この道具を「完了待ち」「正しいクオート」「例外でも復帰」の枠に乗せれば、VBAはExcelの外でも十分に戦えます。
