こんにちは
好奇心で身を滅ぼすタイプ 零壱(ゼロイチ)テクトです。

VBSから乗り換えのため、PowerShellを弄っていますが
MsgboxすらGUI系の命令はなく、WindowsシステムやVBオブジェクト等
間接的に呼び出してGUIに触れる必要があると知りました。
であれば、MsgboxだけでなくGUI全体に触れてみようと考えた次第です。
そうなると、「PowerShell製のメモ帳」開発は誰もが思いつくと思います。
ですが、WEBやQiitaで探しても、見つからないか
リンクが消えていたので、勉強がてら作ったので公開します。
1.概要/仕様
・メモ帳の基本機能を踏襲
・コードを減らすため自分が使わない機能は削除
・少なくとも自分は業務に使うイメージで作成
2.コード
############################################
# PowerShell メモ帳
############################################
# GUI用アセンブリ読込
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName Microsoft.VisualBasic
# ファイルパス変数
$currentFilePath = ""
# アプリ名定義
$appName = "PowerShell メモ帳"
# 検索用:グローバル変数初期化
$global:searchText = ""
$global:searchIndex = 0
# タイトル更新関数
function Update-Title {
if ([string]::IsNullOrWhiteSpace($currentFilePath)) {
$form.Text = $appName
} else {
$fileName = [System.IO.Path]::GetFileName($currentFilePath)
$form.Text = "$fileName - " + $appName
}
}
# フォーム作成
$form = New-Object System.Windows.Forms.Form
$form.Text = $appName
$form.Size = New-Object System.Drawing.Size(800,600)
$form.StartPosition = "CenterScreen"
# テキストボックス(メイン)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Multiline = $true
$textBox.Dock = "Fill"
$textBox.ScrollBars = "Both"
$textBox.Font = New-Object System.Drawing.Font("Consolas", 11)
$textBox.AcceptsTab = $true
$form.Controls.Add($textBox) | Out-Null
# メニューバー作成
$menu = New-Object System.Windows.Forms.MenuStrip
$form.MainMenuStrip = $menu
$form.Controls.Add($menu) | Out-Null
# メニュー:ファイル
$fileMenu = New-Object System.Windows.Forms.ToolStripMenuItem "ファイル"
$menu.Items.Add($fileMenu) | Out-Null
# 新規作成:Ctrl+N
$newItem = New-Object System.Windows.Forms.ToolStripMenuItem "新規作成"
$newItem.ShortcutKeys = "Control, N"
$newItem.Add_Click({
$textBox.Clear()
$currentFilePath = $null
Update-Title
})
$fileMenu.DropDownItems.Add($newItem) | Out-Null
# 開く:Ctrl+O
$openItem = New-Object System.Windows.Forms.ToolStripMenuItem "開く"
$openItem.ShortcutKeys = "Control, O"
$openItem.Add_Click({
$openDialog = New-Object System.Windows.Forms.OpenFileDialog
$openDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
if ($openDialog.ShowDialog() -eq "OK") {
$currentFilePath = $openDialog.FileName
$textBox.Text = Get-Content $currentFilePath -Raw -Encoding UTF8
Update-Title
}
}) | Out-Null
$fileMenu.DropDownItems.Add($openItem) | Out-Null
# 保存(上書き):Ctrl+S
$saveItem = New-Object System.Windows.Forms.ToolStripMenuItem "保存"
$saveItem.ShortcutKeys = "Control, S"
$saveItem.Add_Click({
$saveDialog = New-Object System.Windows.Forms.SaveFileDialog
$saveDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
if ($saveDialog.ShowDialog() -eq "OK") {
$currentFilePath = $saveDialog.FileName
[System.IO.File]::WriteAllText($currentFilePath, $textBox.Text)
Update-Title
}
})
$fileMenu.DropDownItems.Add($saveItem) | Out-Null
# 名前を付けて保存:Ctrl+Shift+S
$saveAsItem = New-Object System.Windows.Forms.ToolStripMenuItem "名前を付けて保存"
$saveAsItem.ShortcutKeys = "Control, Shift, S"
$saveAsItem.Add_Click({
$saveDialog = New-Object System.Windows.Forms.SaveFileDialog
$saveDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
if ($saveDialog.ShowDialog() -eq "OK") {
$currentFilePath = $saveDialog.FileName
[System.IO.File]::WriteAllText($currentFilePath, $textBox.Text)
Update-Title
}
})
$fileMenu.DropDownItems.Add($saveAsItem) | Out-Null
# 区切り
$fileMenu.DropDownItems.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
# メニュー:終了
$exitItem = New-Object System.Windows.Forms.ToolStripMenuItem "終了"
$exitItem.Add_Click({ $form.Close() })
$fileMenu.DropDownItems.Add($exitItem) | Out-Null
# メニュー:編集
$editMenu = New-Object System.Windows.Forms.ToolStripMenuItem "編集"
$menu.Items.Add($editMenu) | Out-Null
# 元に戻す:Ctrl+Z
$undoItem = New-Object System.Windows.Forms.ToolStripMenuItem "元に戻す"
$undoItem.ShortcutKeys = "Control, Z"
$undoItem.Add_Click({ $textBox.Undo() })
$editMenu.DropDownItems.Add($undoItem) | Out-Null
# 区切り
$editMenu.DropDownItems.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
# 切り取り:Ctrl+X
$cutItem = New-Object System.Windows.Forms.ToolStripMenuItem "切り取り"
$cutItem.ShortcutKeys = "Control, X"
$cutItem.Add_Click({ $textBox.Cut() })
$editMenu.DropDownItems.Add($cutItem) | Out-Null
# コピー:Ctrl+C
$copyItem = New-Object System.Windows.Forms.ToolStripMenuItem "コピー"
$copyItem.ShortcutKeys = "Control, C"
$copyItem.Add_Click({ $textBox.Copy() })
$editMenu.DropDownItems.Add($copyItem) | Out-Null
# 貼り付け:Ctrl+V
$pasteItem = New-Object System.Windows.Forms.ToolStripMenuItem "貼り付け"
$pasteItem.ShortcutKeys = "Control, V"
$pasteItem.Add_Click({ $textBox.Paste() })
$editMenu.DropDownItems.Add($pasteItem) | Out-Null
# 削除:Delete
$deleteItem = New-Object System.Windows.Forms.ToolStripMenuItem "削除"
$deleteItem.ShortcutKeys = [System.Windows.Forms.Keys]::Delete
$deleteItem.Add_Click({
$start = $textBox.SelectionStart
$length = $textBox.SelectionLength
$textBox.Text = $textBox.Text.Remove($start, $length)
})
$editMenu.DropDownItems.Add($deleteItem) | Out-Null
# 区切り
$editMenu.DropDownItems.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
# 全て選択:Ctrl+A
$selectAllItem = New-Object System.Windows.Forms.ToolStripMenuItem "すべて選択"
$selectAllItem.ShortcutKeys = "Control, A"
$selectAllItem.Add_Click({ $textBox.SelectAll() })
$editMenu.DropDownItems.Add($selectAllItem) | Out-Null
# 日付と時刻:F5
$timeDateItem = New-Object System.Windows.Forms.ToolStripMenuItem "日付と時刻"
$timeDateItem.ShortcutKeys = "F5"
$timeDateItem.Add_Click({
$dateTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss"
$textBox.SelectedText = $dateTime
})
$editMenu.DropDownItems.Add($timeDateItem) | Out-Null
# 区切り
$editMenu.DropDownItems.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
# 検索:Ctrl+F
$findItem = New-Object System.Windows.Forms.ToolStripMenuItem "検索"
$findItem.ShortcutKeys = "Control, F"
$findItem.Add_Click({
$input = [Microsoft.VisualBasic.Interaction]::InputBox("検索する文字列を入力してください", "検索")
if ($input) {
$global:searchText = $input
$global:searchIndex = 0 # 先頭から検索開始
$index = $textBox.Text.IndexOf($global:searchText, $global:searchIndex)
if ($index -ge 0) {
$textBox.SelectionStart = $index
$textBox.SelectionLength = $global:searchText.Length
$textBox.ScrollToCaret()
$global:searchIndex = $index + $global:searchText.Length
} else {
[System.Windows.Forms.MessageBox]::Show("文字列が見つかりません。", "検索")
$global:searchText = ""
$global:searchIndex = 0
}
}
})
$editMenu.DropDownItems.Add($findItem) | Out-Null
# 次を検索:F3
$findNextItem = New-Object System.Windows.Forms.ToolStripMenuItem "次を検索"
$findNextItem.ShortcutKeys = [System.Windows.Forms.Keys]::F3
$findNextItem.Add_Click({
if ([string]::IsNullOrEmpty($global:searchText)) {
[System.Windows.Forms.MessageBox]::Show("先に検索してください。", "次を検索")
return
}
$index = $textBox.Text.IndexOf($global:searchText, $global:searchIndex)
if ($index -ge 0) {
$textBox.SelectionStart = $index
$textBox.SelectionLength = $global:searchText.Length
$textBox.ScrollToCaret()
$global:searchIndex = $index + $global:searchText.Length
} else {
[System.Windows.Forms.MessageBox]::Show("これ以上見つかりません。", "次を検索")
}
})
$editMenu.DropDownItems.Add($findNextItem) | Out-Null
# 置換:Ctrl+H
$replaceItem = New-Object System.Windows.Forms.ToolStripMenuItem "置換"
$replaceItem.ShortcutKeys = "Control, H"
$replaceItem.Add_Click({
$find = [Microsoft.VisualBasic.Interaction]::InputBox("置換したい文字列を入力してください", "置換(検索)")
if ($find) {
$replace = [Microsoft.VisualBasic.Interaction]::InputBox("新しい文字列を入力してください", "置換(置換後)")
if ($replace -ne $null) {
$textBox.Text = $textBox.Text.Replace($find, $replace)
}
}
})
$editMenu.DropDownItems.Add($replaceItem) | Out-Null
# アプリ実行
$form.Add_Shown({ $form.Activate() })
$form.ShowDialog() | Out-Null
お好きにコードをお使いください。
3.備考
✅ 改良案1:時間経過で自動保存する機能
→これは便利機能ですがコードが長くなりそうだったので割愛
✅ 改良案2:フォントサイズや文字色は固定なので変更できるように
→僕の現在の用途には不要な機能だったので割愛しました
→文字コードも同じです。
✅ タブ化したり、文字数や行数表示したり、弄り方は色々あると思います。
・「Out-Null
」は「.Add
」を実行する時にISEのログに返り値が表示されるため
消す為に入れてあります。邪魔であれば削除しても動作に問題ないです。
・置換機能として、1つのダイアログに入力を2つ持たせる画面は
コードが長くなりそうだったのでやめました。
・友人知人からプログラムを勉強したいだけど何をしたら良いか
と聞かれる事があるのですが、その時まず提案するのが「メモ帳」アプリ作りです。
・WEBアプリやサイトを作るのでなければ、メモ帳開発はとても良い教材だと思います。
それでは
どこかの誰かの何かの足しになれば幸いです。
01000010 01011001 01000101
4.参考
■ @Tadataka_Takahashi様:[備忘録] PowerShellで作る「リアルタイム システム監視ダッシュボード」- PropertyGridの活用
■ @K014C様:PowerShellでフォームの作成とファイルパスの取得
■ @tatsuki1112様:PowerShellでGUIアプリを作って、勤怠を少しだけ効率化した話