プログラミングのすすめ 第十三歩 VB Script SendKeys + トラックボール(ERGO M575S)で作業効率化

プログラミング

Windows PowerShell で作業する上で、PowerShell console の ls 等でファイルをリストした後、そのファイルをエディタで編集したいことが多々あると思います。そういう場合、ファイル名を一旦クリップボードにコピーしてエディタを立ち上げる時に、クリップボードの内容をエディタに引数として渡すという作業をすると思います。

この作業をpowershell consoleからマウスやトラックボールのボタンクリックのみで出来れば、作業の効率化が図れるのではと考えました。

私は、幸いにアプリ実行をボタンに登録できるトラックボール ERGO M575S というのを使っています。

ボタンクリックで、PowerShell に目標ファイルの編集が出来るようなコマンドをキーインする というのが今回のプログラミングの目的です。

PowerShell console に自動キーインするのには、VB Script の SendKeys メソッドが使えそうなので、先ずは VB Script から作っていきたいと思います。

【paters】

VB Script の作成

VB Script は、マイクロソフトが開発した Visual Basic を基本としたスクリプト言語で、プログラムの作成自体には、何も必要ありません。単にエディタでファイルにコードを書いて、エクステンションを .vbs にすれば、VB Script の実行可能ファイルとみなされます。

VB ScriptでSendKeys を使うために次のようなコードを記入します。

Dim WshShell
Set WshShell=WScript.CreateObject("WScript.Shell")

WshShell.AppActivate "Windows PowerShell"

WshShell.SendKeys "EmEditor.exe ${(}get-clipboard{)}"

WshShell.SendKeys "{ENTER}"

Dim WshShell
Set WshShell=WScript.CreateObject(“WScript.Shell”)

これらは、Windows シェルを使うための準備です。

WshShell.AppActivate “Windows PowerShell”

キーストロークを送る目標のアプリをアクティブにします。”Windows PowerShell” は、以下の PowerShell console の左上に表示されているWindow の名前と一致している必要があります。

WshShell.SendKeys “EmEditor.exe ${(}get-clipboard{)}”

SendKeys で “EmEditor.exe $(get-clipboard)” と送りたいのですが、SendKeys では () は特殊文字となるため () を送りたい場合は、{} で囲います。このコマンドをPowerShell に送る前に、クリップボードには編集したいファイルのファイル名が入っています。

WshShell.SendKeys “{ENTER}”

Enter キーを送ります。

このファイルを .vbs のエクステンションを付けて保存しておきます。

VB Script の実行

VBS ファイルは C:\VBS というディレクトリに SendKeysEmEditor.vbs という名前で保存しています。

コマンド・プロンプトと PowerShell Consoleを立ち上げます。

コマンド・プロンプトで “SendKeyEmEditor.vbs” をキーインして実行して、PowerShell Console に EmEditor.exe $(get-clipboard) とキーインされれば成功です。

トラックボールのボタンへのアプリ実行登録

ロジクール ワイヤレスマウス トラックボール 無線 M575S Bluetooth Unifying トラックボールマウス ワイヤレス マウス windows mac iPad 国内正規品 1年間無償保証

価格:4,980円
(2022/12/3 22:23時点)
感想(219件)

Ergo M575S には、Logi Option+ という設定用のアプリがあります。

設定したいボタンをクリックして、ボタン設定の画面へ進みます。

その他のアクションから アプリケーションを開く を選んで、 先ほどの .vbs ファイルを登録します。

作業の実行例

Windows PowerShell の作業ディレクトリで、Get-ChildItem(ls) で ディレクトリの内容をリストした後、編集したいファイルをダブルクリックしてハイライトし、右クリックしてハイライトが消えれば、ファイル名がクリップボードにコピーされます。

その後、先ほどVBS実行を登録したトラックボールのボタンを押します。

PowerShell には、EmEditor.exe $(get-clipboard) とキーインされて、EmEditor が立ち上がります。

管理者として実行されている PowerShell へのキー送信

管理者モードでPowerShellを実行して作業することも多々あります。管理者として実行されているPowerShell には現在のままでは、キーの送信は出来ません。これは、管理者として実行されているアプリに対して、非管理者からの変更は受け付けられないからです。

管理者として実行されているPowerShellに対してキーストロークを送る場合は、VB Script も管理者として実行されている必要があります。

VB Scriptを管理者として実行するためには、VBS の ShellExecute を使って wscript.exe から目的の .vbs を runas 引数を付けて起動します。

'管理者として実行させる
Set obj = Wscript.CreateObject("Shell.Application")
  obj.ShellExecute "wscript.exe", "c:\vbs\SendKeysEmEditor.vbs" & " runas", "", "runas", 1
Wscript.Quit 

ユーザーアカウント制御

管理者モードでVBSを実行しようとすると、毎回 ユーザーアカウント制御で “このアプリがデバイスに変更を加えることを許可しますか?” と聞かれます。

毎回聞かれないようにするには、詳細表示 -> これらの通知を表示するタイミングを変更する をクリックします。

ここで一番下の 通知しない に設定すると聞かれなくなります。 推奨ではないので、作業が終わったあとは元に戻すことをお勧めします。

ユーザーアカウント制御を元に戻す

ユーザーアカウント制御を元にもどすには、 Windows システム ツール から コントロール パネル を立ち上げます。

コントロールパネルでユーザーアカウントをクリックします。

出てきた画面で更に ユーザーアカウント をクリックします。

ユーザーアカウント制御設定の変更 をクリックします。

一番上の 常に通知する に変更します。

PowerShell が管理者権限で実行されているかの判断

目的のPowerShell が管理者権限で実行されているかどうかを判断して、実行するVBScriptを管理者権限で実行するかどうかを決定するようにします。

一々、トラックボールのボタン登録を変えるのは馬鹿らしいので、プログラムで判断することにします。

MainWindowTitle

PowerShell が管理者で実行されている場合は、PowerShell の Get-Process で得られる MainWindowTitle が “管理者: Windows PowerShell” になっています。

PS >Get-Process powershell | Format-List *


Name                       : powershell
Id                         : 9088
PriorityClass              : Normal
FileVersion                : 10.0.19041.2248 (WinBuild.160101.0800)
HandleCount                : 661
WorkingSet                 : 76726272
PagedMemorySize            : 62406656
PrivateMemorySize          : 62406656
VirtualMemorySize          : 713129984
TotalProcessorTime         : 00:00:01.3281250
SI                         : 1
Handles                    : 661
VM                         : 2204031352832
WS                         : 76726272
PM                         : 62406656
NPM                        : 31768
Path                       : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Company                    : Microsoft Corporation
CPU                        : 1.328125
ProductVersion             : 10.0.19041.2248
Description                : Windows PowerShell
Product                    : Microsoft® Windows® Operating System
__NounName                 : Process
BasePriority               : 8
ExitCode                   :
HasExited                  : False
ExitTime                   :
Handle                     : 2584
SafeHandle                 : Microsoft.Win32.SafeHandles.SafeProcessHandle
MachineName                : .
MainWindowHandle           : 1182246
MainWindowTitle            : 管理者: Windows PowerShell
MainModule                 : System.Diagnostics.ProcessModule (powershell.exe)
MaxWorkingSet              : 1413120
MinWorkingSet              : 204800
Modules                    : {System.Diagnostics.ProcessModule (powershell.exe), System.Diagnostics.ProcessModule (ntdll.dll), Sy

VB で MainWindowTitle を表示する

MainWindowTitle は、VBからも知ることが出来ることが分かったので、VBで表示するアプリを作りました。

Imports System
Imports System.Diagnostics
Module Program
    Sub Main(args As String())
        Dim p As System.Diagnostics.Process
        For Each p In System.Diagnostics.Process.GetProcesses()
            If p.ProcessName = "powershell" Then
                Console.WriteLine(p.MainWindowTitle)
            End If
        Next
    End Sub
End Module

これをビルドして、 WhatPSTitle.exe というコンソールアプリを作りました。

以下が作成したアプリ WhatPSTitle.exe の実行結果です。

PowerShell が管理者権限で立ち上げられている場合

C:\vbs>whatpstitle
管理者: Windows PowerShell

管理者権限でない場合

C:\vbs>whatpstitle
Windows PowerShell

バッチファイル作成

ここまでで作成した、プログラムを組み合わせて 管理者権限で実行されているPowerShell には管理者権限で VBS を実行、そうでない場合は、ノーマルでVBSを実行するように BAT ファイルを作ります。

@Echo off
whatPStitle.exe > tempPStitle.tmp
Set /p TitlePS=<tempPStitle.tmp
If "%TitlePS%" == "管理者: Windows PowerShell"  (
 AdminSendKeyEmEditor.vbs
 ) else (
 SendKeysEmEditor.vbs
 ) 

このバッチをトラックボールのボタンに登録すれば、PowerShell がノーマルモードでも管理者モードでもSendKeysが出来るようになります。

BAT 実行のたびにコマンドプロンプト窓が開くのを防ぐ

トラックボールのボタンでEmEditorが立ち上がって、ファイル編集が出来るようになったのですが、一々 コマンドプロンプトの窓が開くのが気になります。これを防ぐために、BAT ファイルのショートカットを作成して、ショートカットを最小化で実行するように設定します。

バッチファイルのショートカットを作成

ファイル・エクスプローラでショートカットを作成したいバッチファイルをマウスの右クリックでドラッグして同じディレクタ内でドロップします。出て来たオプションから ショートカットをここに作成(S) をクリックします。

以下のようにショートカットが作成されます。

シュートカットのプロパティで実行時の大きさを最小化に設定

作成されたショートカットを選択し、マウスの右クリックで出て来たメニューから プロパティ をクリックし、プロパティから下記の 実行時の大きさ(R) を 最小化 に設定します。

ショートカットの名前を変更

コマンドプロンプトでショートカットを作成したディレクトリを表示します。

作成されたショートカットのファイル名は “SendKEmE.bat – ショートカット.lnk” です。

2022/12/05  15:28               336 SendKEmE.bat
2022/12/05  20:53               930 SendKEmE.bat - ショートカット.lnk

このままでも問題はないのですが、ファイル名にカナとかスペースがあると、後々ややこしいので短い名前に変更します。

C:\vbs>ren "SendKEmE.bat - ショートカット.lnk" SendKEmESC.lnk

2022/12/05  20:53               930 SendKEmESC.lnk

名前を変更したショートカット c:\vbs\SendKEmESC.lnk をトラックボールのボタンに設定します。

以上、VB Script の SendKeys メソッドを使って PowerShell にキーストロークを送るスクリプトとPowerShellの管理者権限を知るためのアプリ、およびそれらを組み合わせたバッチのご紹介でした。

PowerShell の現在の Working Directory(Current Directory) を外部から知ることが出来れば、SendKeys を使わなくても EmEditor に、そのディレクトリとファイル名を渡せば済む話なのですが、Working Directoryを外部から知る方法が中々見つかりません。可能か不可能なのかも分かりませんが目下模索中です。

追記

管理者権限の判断をPowerShell のスクリプトで実施

PowerShell の Get-Process で PowerShell が管理者権限かどうかを知ることが出来ることは分かっていました。しかし、PowerShell の Process の判定を powershellをもう一つ走らせてスクリプト実行で判定しようとすることはPowerShellのprocessが二つになるので難しいだろうと諦めていました。念のため実験してみるとスクリプトを走らせるために立ち上げたPowerShell の MainWindowTitle は 空白のため本来の目的には邪魔にならないことが分かりました。

実験

次のようなPoweShell スクリプトを記述します。

Pause
get-Process powershell | select MainWindowTitle

PowerShell を管理者で実行で立ち上げて、さらに コマンドプロンプトで 上記の スクリプトを実行します。

C:\vbs>powershell ./gptest.ps1
続行するには、Enter キーを押してください...:

この状態で、PowerShell Console から PowerShell Process をリストします。

PS >get-Process powershell

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    523      25    55516      60200       0.58   8332   1 powershell
    623      30    61564      76192       1.27  10640   1 powershell

確かに、PowerShell のプロセスは二つあります。しかし、下記のように一つのプロセスの MainWindowTitle は空白です。

PS >get-Process powershell | select MainWindowTitle

MainWindowTitle
---------------

管理者: Windows PowerShell

新たな PowerShell スクリプト

PowerShell スクリプトで管理者で実行を判断するようにして、新たにスクリプトを書きました。次のようにたった一つの IF文 で間に合うようになりました。

if ($(Get-Process powershell | select MainWindowTitle | ? { $_ -Match "管理者" })) {
       ./AdminSendkeyEmEditor.vbs }
else {
       ./SendKeysEmEditor.vbs }

トラックボール・ボタンへの登録用のバッチファイル

トラックボールのボタン登録に C:\VBS\PowerShell ./SendKEmEditor.ps1 と記述しても動かないので バッチファイルを作ります。

@Echo off
Powershell ./SendKEmEditor.ps1

前述のように、BAT ファイルのショートカットを作成し、最小化で実行するように設定したショートカットをトラックボールのボタンに登録します。

コメント