4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【VBAForm2PowerShell】標準環境+VBAでPowerShellのGUIを簡単作成

4
Last updated at Posted at 2026-02-01

・はじめに

PowerShellという言語を知っていますか?
あまり使ったことのある人は多くないと思いますが、Windowsに標準で入っており、.NETの機能も扱えたりして結構多機能です
ちょっとした自作ツールならPowerShellで十分作成可能です
Windowsの標準環境(外部プログラムインストール禁止)でプログラミングをするとなった場合
C#, VB.NET, PowerShell, bat, VBScript(廃止が予告されている), VBA(厳密には標準ではないが大抵の職場で使える), JavaScript(ブラウザ内のみ), JScript
この選択肢から選ぶことになるのですが
C#・VB.NETはコンパイラ言語で開発のハードルが高め、JScript・VBS・VBAは言語としての機能が現代の言語に比べ貧弱、JavaScriptはブラウザ内のみ、batも用途が特殊で言語としての機能はさらに制約ありと
スクリプト言語で現代の言語と遜色ないプログラミング言語となるとPowerShellに絞られます

そしてPowerShellは.NETを扱えるのでGUI(WinForms)も作成することができます
しかし、C#やVBAのように専用のフォーム開発ツールはなく手でGUI作成となるとそこそこ大変です
PowerShellはC#と同じ.NETのGUIを作成しているのでVisual Studioで作成したC#のフォームを機械的に変換という裏技も使えますが、Visual Studioはインストールできないという仮定で話を進めていきます
また、Excel VBAのほうがGUIの作成は手軽にできます
そこで以前作成したExcel VBAからPythonのTkinterへの変換ツールをPowerShell用に改造しました
ツールはGitHubで公開しています
https://github.com/GUI-Conversion-Tools/VBAForm2PowerShell


変換後のイメージは以下のようになります
2026-03-02 003100.png

・動作要件

OS・・・Windows
(10/11で動作確認してますがもっと古くても動くと思います)
Excelバージョン・・・Excel 2010以降 (32bit/64bit両対応)
※マルチモニター環境の場合各モニターで異なるDPIが混在しているとウィンドウサイズの計算ロジックに影響が出るため、
一時的にシングルモニターにするかすべてのモニターの拡大率を統一した上で実行してください(解像度の違いは問題なし)

・1.ツールの導入

ここからVBAForm2PowerShellの最新版の「Source code (zip)」をダウンロードします、解凍すると.basファイルが入っておりそのファイルを後に使用します
ダウンロードが禁止されている場合はここにアクセスして全選択→メモ帳にコピペして.basファイルとして保存してください(コピペはOKと仮定します)
2026-03-03 210454.png

・2.basファイルのインポート

VBA Projectと書いてある場所の何もないところを右クリックしてファイルをインポートしてください

img3.png

・3.変換コマンドを実行する

イミディエイトウィンドウにコマンドを入力してEnterキーを押すとPowerShellスクリプト(.ps1)が生成されます
コマンドはこれです
「ユーザーフォームのオブジェクト名」のところは変換したいユーザーフォームのオブジェクト名に合わせて変えます

Call ConvertForm2PS(ユーザーフォームのオブジェクト名)

画像の場合はオブジェクト名が「UserForm1」なのでユーザーフォームのオブジェクト名のところは「UserForm1」に置き換えます

Call ConvertForm2PS(UserForm1)

2026-02-01 140325.png
イミディエイトウィンドウの使い方がよくわからない人は以下のように標準モジュールにSubプロシージャを作成して実行する形でもかまいません

Sub test()
    Call ConvertForm2PS(UserForm1)
End Sub

この時点でエラーが発生する場合はオブジェクト名に間違いがないか再度確認をお願いします
また、第二引数をTrueにすると実行ポリシー関係なくダブルクリックで起動できるbatファイルとして生成されます

' batファイルとして生成
Call ConvertForm2PS(UserForm1, True)

ConvertForm2PS には以下の引数を設定できます
v1.1.0より複数フォームの同時変換とクラス化に対応しました

引数 説明
frms Variant 必須
変換対象のUserFormオブジェクトまたはUserFormオブジェクトの配列を指定
saveAsBat Boolean 省略可能 (デフォルト: False).
Trueにした場合PowerShellスクリプトをダブルクリックで起動可能な.batファイルとして保存する
useCls Boolean 省略可能 (デフォルト: False).
Trueにした場合生成したPowerShellコードにおいて各フォームをクラス化する  frmsが配列の場合は自動的にTrueに設定される
noMainLoop Boolean 省略可能 (デフォルト: False).
Trueにした場合生成したPowerShellスクリプトに.ShowDialog()を含めなくする
' 実行例: 単一のフォームを変換
Call ConvertForm2PS(UserForm1)

' 実行例: 単一のフォームを変換 (クラス化を行う)
Call ConvertForm2PS(UserForm1, useCls:=True)

' 実行例: 複数のフォームを変換 (自動的にクラス化される)
Call ConvertForm2PS(Array(UserForm1, UserForm2))

noMainLoopは生成スクリプトを別のファイルでモジュールとして扱い、importした側で.ShowDialog()を書きたい場合に使用することを想定しています

・4.変換成功可否を確認

2026-02-01 142048.png

変換に成功したら「Saved: 保存先」のメッセージが出現し.ps1または.batファイルが保存されます、保存先はExcelブックと同じフォルダに設定されています
失敗した場合は「Control type "XXXX" is not supported」→「Conversion failed」と出ます
その場合、XXXXに当たる部分のコントロールタイプは変換非対応なので該当のコントロールを削除してからもう一度コマンドを実行してください

対応しているコントロールは以下の通りです

VBA Formのクラス WinFormsのクラス
Label Label
CommandButton Button
Frame (Captionなし) Panel
Frame (Captionあり) GroupBox
TextBox TextBox
SpinButton NumericUpDown
ListBox ListBox
CheckBox CheckBox
ToggleButton CheckBox
(Appearance = [System.Windows.Forms.Appearance]::Button)
OptionButton RadioButton
Image PictureBox
ScrollBar HScrollBar / VScrollBar
ComboBox ComboBox
MultiPage TabControl

・5.ファイルを実行してみる

実行してVBAと同じ見た目か確認します
違う場合は後述の「VBAと見た目の表示が異なる場合の対処法」を参照してください
この時点ではボタンには何もイベントは登録されていません
2026-03-03 194202.png

・6.ボタンの動作を設定する

「登録」ボタンを押したらメッセージボックスに登録内容を表示するようにしてみます

function ShowRegistrationInfo($name, $email, $region){
    $registrationInfo = "名前: $name E-mail: $email 地域: $region"
    [System.Windows.Forms.MessageBox]::Show($registrationInfo, "登録内容")
}

生成されたコードと組み合わせます
設定内容は.ShowDialog()の直前に記述するのがおすすめです
動作の定義をこの位置で行うのはレイアウトを再調整する場合に再度生成したコードへコピペが楽になるためです

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()

$UserForm1 = New-Object System.Windows.Forms.Form
$UserForm1.Text = "登録フォーム"
$UserForm1.ClientSize = New-Object System.Drawing.Size(304, 201)
$UserForm1.MaximizeBox = $false
$UserForm1.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle
$UserForm1.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#F0F0F0")
$UserForm1.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::None
$UserForm1.Cursor = $null

$CommandButton2 = New-Object System.Windows.Forms.Button
$UserForm1.Controls.Add($CommandButton2)
$CommandButton2.Location = New-Object System.Drawing.Point(160, 152)
$CommandButton2.Size = New-Object System.Drawing.Size(96, 32)
$CommandButton2.ForeColor = "#000000"
$CommandButton2.BackColor = "#FF80FF"
$CommandButton2.Text = "キャンセル"
$CommandButton2.FlatStyle = [System.Windows.Forms.FlatStyle]::Popup
$CommandButton2.Font = New-Object System.Drawing.Font("MS ゴシック", 12)
$CommandButton2.Cursor = $null

$CommandButton1 = New-Object System.Windows.Forms.Button
$UserForm1.Controls.Add($CommandButton1)
$CommandButton1.Location = New-Object System.Drawing.Point(32, 152)
$CommandButton1.Size = New-Object System.Drawing.Size(96, 32)
$CommandButton1.ForeColor = "#000000"
$CommandButton1.BackColor = "#00FFFF"
$CommandButton1.Text = "登録"
$CommandButton1.FlatStyle = [System.Windows.Forms.FlatStyle]::Popup
$CommandButton1.Font = New-Object System.Drawing.Font("Arial Narrow", 12)
$CommandButton1.Cursor = $null

$ComboBox1 = New-Object System.Windows.Forms.ComboBox
$UserForm1.Controls.Add($ComboBox1)
$ComboBox1.Location = New-Object System.Drawing.Point(120, 104)
$ComboBox1.Size = New-Object System.Drawing.Size(168, 24)
$ComboBox1.ForeColor = "#000000"
$ComboBox1.BackColor = "#FFFFFF"
$ComboBox1_items_value = @()
$ComboBox1.Items.AddRange($ComboBox1_items_value)
$ComboBox1.Text = ""
$ComboBox1.Font = New-Object System.Drawing.Font("Arial Narrow", 10)
$ComboBox1.Cursor = $null

$TextBox2 = New-Object System.Windows.Forms.TextBox
$UserForm1.Controls.Add($TextBox2)
$TextBox2.Location = New-Object System.Drawing.Point(120, 64)
$TextBox2.Size = New-Object System.Drawing.Size(168, 24)
$TextBox2.ForeColor = "#000000"
$TextBox2.BackColor = "#FFFFFF"
$TextBox2.Text = ""
$TextBox2.Multiline = $false
$TextBox2.Font = New-Object System.Drawing.Font("Arial Narrow", 10)
$TextBox2.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
$TextBox2.TextAlign = "Left"
$TextBox2.Cursor = $null

$TextBox1 = New-Object System.Windows.Forms.TextBox
$UserForm1.Controls.Add($TextBox1)
$TextBox1.Location = New-Object System.Drawing.Point(120, 24)
$TextBox1.Size = New-Object System.Drawing.Size(168, 24)
$TextBox1.ForeColor = "#000000"
$TextBox1.BackColor = "#FFFFFF"
$TextBox1.Text = ""
$TextBox1.Multiline = $false
$TextBox1.Font = New-Object System.Drawing.Font("Arial Narrow", 10)
$TextBox1.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
$TextBox1.TextAlign = "Left"
$TextBox1.Cursor = $null

$Label4 = New-Object System.Windows.Forms.Label
$UserForm1.Controls.Add($Label4)
$Label4.Location = New-Object System.Drawing.Point(16, 104)
$Label4.Size = New-Object System.Drawing.Size(96, 24)
$Label4.ForeColor = "#000000"
$Label4.BackColor = "#F0F0F0"
$Label4.Text = "地域"
$Label4.Font = New-Object System.Drawing.Font("MS ゴシック", 12)
$Label4.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$Label4.TextAlign = [System.Drawing.ContentAlignment]::TopCenter
$Label4.Cursor = $null

$Label2 = New-Object System.Windows.Forms.Label
$UserForm1.Controls.Add($Label2)
$Label2.Location = New-Object System.Drawing.Point(16, 64)
$Label2.Size = New-Object System.Drawing.Size(96, 24)
$Label2.ForeColor = "#000000"
$Label2.BackColor = "#F0F0F0"
$Label2.Text = "E-mail"
$Label2.Font = New-Object System.Drawing.Font("MS ゴシック", 12)
$Label2.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$Label2.TextAlign = [System.Drawing.ContentAlignment]::TopCenter
$Label2.Cursor = $null

$Label1 = New-Object System.Windows.Forms.Label
$UserForm1.Controls.Add($Label1)
$Label1.Location = New-Object System.Drawing.Point(16, 24)
$Label1.Size = New-Object System.Drawing.Size(96, 24)
$Label1.ForeColor = "#000000"
$Label1.BackColor = "#F0F0F0"
$Label1.Text = "名前"
$Label1.Font = New-Object System.Drawing.Font("MS ゴシック", 12)
$Label1.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$Label1.TextAlign = [System.Drawing.ContentAlignment]::TopCenter
$Label1.Cursor = $null

# 関数を定義
function ShowRegistrationInfo($name, $email, $region){
    $registrationInfo = "名前: $name E-mail: $email 地域: $region"
    [System.Windows.Forms.MessageBox]::Show($registrationInfo, "登録内容")
}

# ボタンに関数を紐づける
$CommandButton1.Add_Click({
    $null = ShowRegistrationInfo $TextBox1.Text $TextBox2.Text $ComboBox1.Text
})  

$UserForm1.ShowDialog() | Out-Null

再度実行してボタンを押したら、登録内容がちゃんと表示されました
2026-03-03 195139.png

・VBAと見た目の表示が異なる場合の対処法

以下のように、ボタンが隠れてしまう場合があります
これは、VBAのユーザーフォームの前面・背面が変換されたコードに反映されないためです
変換される順番はVBAでの設置順のため、ボタンを先に設置した後にラベルを設置すると隠れてしまいます
2026-02-01 105800.png

これの解決法は.BringToFront()を使用して前面に部品を持ってくることです
動作設定と同じ位置に以下のコードを記述します

$部品名.BringToFront()

また、逆に背面に部品を配置したい場合は.SendToBack()を使用します

$部品名.SendToBack()

コードに記述すると以下のようになります

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()

$UserForm2 = New-Object System.Windows.Forms.Form
$UserForm2.Text = "UserForm2"
$UserForm2.ClientSize = New-Object System.Drawing.Size(304, 201)
$UserForm2.MaximizeBox = $false
$UserForm2.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle
$UserForm2.BackColor = "#F0F0F0"
$UserForm2.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::None
$UserForm2.Cursor = $null

$Label1 = New-Object System.Windows.Forms.Label
$UserForm2.Controls.Add($Label1)
$Label1.Location = New-Object System.Drawing.Point(24, 24)
$Label1.Size = New-Object System.Drawing.Size(240, 144)
$Label1.ForeColor = "#000000"
$Label1.BackColor = "#80FFFF"
$Label1.Text = ""
$Label1.Font = New-Object System.Drawing.Font("MS UI Gothic", 9)
$Label1.BorderStyle = [System.Windows.Forms.BorderStyle]::None
$Label1.TextAlign = [System.Drawing.ContentAlignment]::TopLeft
$Label1.Cursor = $null

$CommandButton1 = New-Object System.Windows.Forms.Button
$UserForm2.Controls.Add($CommandButton1)
$CommandButton1.Location = New-Object System.Drawing.Point(64, 72)
$CommandButton1.Size = New-Object System.Drawing.Size(152, 40)
$CommandButton1.ForeColor = "#000000"
$CommandButton1.BackColor = "#F0F0F0"
$CommandButton1.Text = "CommandButton1"
$CommandButton1.FlatStyle = [System.Windows.Forms.FlatStyle]::Popup
$CommandButton1.Font = New-Object System.Drawing.Font("MS UI Gothic", 9)
$CommandButton1.Cursor = $null

# ボタンを前面に持ってくる
$CommandButton1.BringToFront()

$UserForm2.ShowDialog() | Out-Null

これで正常に表示されました
2026-03-03 195253.png

・画像の設定について

2026-02-01 124744.png

ImageオブジェクトはPictureBoxに変換されますが、設定してある画像までは変換されないので自分で設定を行います
生成されたコードにコメントアウトされた設定用コードがあるのでコメントアウトを解除して設定します
VBAのフォームではbmp画像を設定するのに対して、WinFormsではbmp, png, jpgどれも設定できます

# コメントアウトを解除して画像のPathを設定

#$Image1.Image = [System.Drawing.Image]::FromFile("C:\path\to\your\image.png")
#$Image1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Normal

# ↓ ↓ ↓

$Image1.Image = [System.Drawing.Image]::FromFile("C:\image.bmp")
$Image1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Normal
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()

$UserForm3 = New-Object System.Windows.Forms.Form
$UserForm3.Text = "UserForm3"
$UserForm3.ClientSize = New-Object System.Drawing.Size(304, 201)
$UserForm3.MaximizeBox = $false
$UserForm3.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle
$UserForm3.BackColor = "#F0F0F0"
$UserForm3.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::None
$UserForm3.Cursor = $null

$Image1 = New-Object System.Windows.Forms.PictureBox
$UserForm3.Controls.Add($Image1)
$Image1.Location = New-Object System.Drawing.Point(40, 16)
$Image1.Size = New-Object System.Drawing.Size(224, 160)
$Image1.BackColor = "#F0F0F0"
$Image1.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$Image1.Cursor = $null
$Image1.Image = [System.Drawing.Image]::FromFile("C:\image.bmp")
$Image1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Normal


$UserForm3.ShowDialog() | Out-Null

これで正常に表示されました
2026-02-01 125333.png

表示方法は以下の中から変更できます

Normal	        画像をそのままのサイズで表示(PictureBoxの左上基準)
StretchImage	PictureBoxのサイズに合わせて画像を引き伸ばす/縮める
AutoSize	    画像のサイズに合わせてPictureBox自体のサイズが変わる
CenterImage	    画像を中央に配置して表示(サイズは変更しない)
Zoom	        縦横比を維持したまま、PictureBoxに収まる最大サイズで表示
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?