🤖
PowerShellで自動操作中にマウス操作を無効にしたい
目的
PowerShellで自動化を行っている場合に、ユーザのマウス入力が行われると自動化がうまくいかないことがある。このため、自動操作中はマウスのイベントを無効にしたい。
環境:
PSVersion 5.1.22000.1335
Windows11
管理者権限ありで動かす場合
WindowsAPIのBlockInputを使用する。
# 管理者権限が必要になる
# クリックを受け付けなくなって困ったらCTRL+ALT+DEL
# メモ帳を動かすスクリプトは以下から
# https://www.tekizai.net/entry/2021/10/02/063000
$Win32 = &{
$cscode = @"
[DllImport("User32.dll")]
public static extern bool BlockInput(
bool fBlockIt
);
"@
return (add-type -memberDefinition $cscode -name "Win32ApiFunctions" -passthru)
}
# マウスの操作禁止
$Win32::BlockInput($TRUE)
Write-Output "操作できなくなる"
#ウィンドウの新しい幅 (ピクセル単位)
$width=300
#ウィンドウの新しい高さ (ピクセル単位)。
$height=300
#コントロールの左側の絶対画面座標。
$x=0
#コントロールの上部の絶対画面座標。
$y=0
Add-Type -AssemblyName UIAutomationClient
$notepad=Start-Process notepad -PassThru
Start-Sleep 1
$hwnd=$notepad.MainWindowHandle
#ハンドルからウィンドウを取得する
$window=[System.Windows.Automation.AutomationElement]::FromHandle($hwnd)
#ウィンドウサイズの状態を把握するためにWindowPatternを使う
$windowPattern=$window.GetCurrentPattern([System.Windows.Automation.WindowPattern]::Pattern)
#ウィンドウサイズを変更する準備としてサイズを通常に変更する
$windowPattern.SetWindowVisualState([System.Windows.Automation.WindowVisualState]::Normal)
#ウィンドウサイズを変更するためのパターン。
$transformPattern=$window.GetCurrentPattern([System.Windows.Automation.TransformPattern]::Pattern)
#Maximamだと移動もサイズ変更もできないので適当なサイズに変更する。
$transformPattern.Resize($width,$height)
#暴れる間隔
$sleep=0.5
#暴れる秒数
$duration=5
$startTime=Get-Date
while($true)
{
Start-Sleep $sleep
$transformPattern.Move($x,$y)
$x=Get-Random -Maximum 1000 -Minimum 0
$y=Get-Random -Maximum 1000 -Minimum 0
$currentTime=Get-Date
$durationMinute=($currentTime-$startTime).Seconds
if(($durationMinute -ge $duration) -or $notepad.HasExited){
Stop-Process $notepad
break
}
}
# マウスの操作復活
$Win32::BlockInput($FALSE)
Write-Output "操作できる"
管理者権限なしの場合
WH_MOUSE_LLのイベントをフックしてイベントを握り潰す.
# 管理者権限が必要ない
# クリックを受け付けなくなって困ったらCTRL+ALT+DEL
# 中身のメモ帳を動かすスクリプトは以下から
# https://www.tekizai.net/entry/2021/10/02/063000
# フックロジックは以下から
# https://www.ipentec.com/document/csharp-get-mouse-pointer-screen-position-using-global-hook
$cscode = @"
using System;
using System.Runtime.InteropServices;
public class WinHelper
{
[StructLayout(LayoutKind.Sequential)]
struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEHOOKSTRUCT
{
public POINT pt;
public IntPtr hwnd;
public int wHitTestCode;
public int dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEHOOKSTRUCTEX
{
public MOUSEHOOKSTRUCT mouseHookStruct;
public int MouseData;
}
[StructLayout(LayoutKind.Sequential)]
struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
const int HC_ACTION = 0;
private delegate IntPtr MouseHookCallback(int nCode, uint msg, ref MSLLHOOKSTRUCT msllhookstruct);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, MouseHookCallback lpfn, IntPtr hMod, IntPtr dwThreadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, uint wParam, ref MSLLHOOKSTRUCT msllhookstruct);
private static IntPtr MyHookProc(int nCode, uint wParam, ref MSLLHOOKSTRUCT lParam)
{
if (nCode == HC_ACTION) {
// 0以外を返すことでイベントを握りつぶす
return (IntPtr)1;
}
return CallNextHookEx(hHook, nCode, wParam, ref lParam);
}
static IntPtr hHook = IntPtr.Zero;
static MouseHookCallback proc;
const int WH_MOUSE_LL = 14;
public static IntPtr Block()
{
proc = MyHookProc;
hHook = SetWindowsHookEx(WH_MOUSE_LL,proc, IntPtr.Zero, IntPtr.Zero);
return hHook;
// return IntPtr.Zero;
}
public static bool UnBlock() {
if (hHook == IntPtr.Zero) return false;
return UnhookWindowsHookEx(hHook);
}
}
"@
Add-Type -TypeDefinition $cscode
Write-Output $Win32
# 操作禁止
[WinHelper]::Block()
Write-Output "操作できなくなる"
#ウィンドウの新しい幅 (ピクセル単位)
$width=300
#ウィンドウの新しい高さ (ピクセル単位)。
$height=300
#コントロールの左側の絶対画面座標。
$x=0
#コントロールの上部の絶対画面座標。
$y=0
Add-Type -AssemblyName UIAutomationClient
$notepad=Start-Process notepad -PassThru
Start-Sleep 1
$hwnd=$notepad.MainWindowHandle
#ハンドルからウィンドウを取得する
$window=[System.Windows.Automation.AutomationElement]::FromHandle($hwnd)
#ウィンドウサイズの状態を把握するためにWindowPatternを使う
$windowPattern=$window.GetCurrentPattern([System.Windows.Automation.WindowPattern]::Pattern)
#ウィンドウサイズを変更する準備としてサイズを通常に変更する
$windowPattern.SetWindowVisualState([System.Windows.Automation.WindowVisualState]::Normal)
#ウィンドウサイズを変更するためのパターン。
$transformPattern=$window.GetCurrentPattern([System.Windows.Automation.TransformPattern]::Pattern)
#Maximamだと移動もサイズ変更もできないので適当なサイズに変更する。
$transformPattern.Resize($width,$height)
#暴れる間隔
$sleep=0.5
#暴れる秒数
$duration=5
$startTime=Get-Date
while($true)
{
Start-Sleep $sleep
$transformPattern.Move($x,$y)
$x=Get-Random -Maximum 1000 -Minimum 0
$y=Get-Random -Maximum 1000 -Minimum 0
$currentTime=Get-Date
$durationMinute=($currentTime-$startTime).Seconds
if(($durationMinute -ge $duration) -or $notepad.HasExited){
Stop-Process $notepad
break
}
}
# 操作復活
[WinHelper]::UnBlock()
Write-Output "操作できる"
参考
【PowerShell】メモ帳が暴れ回る最高のスクリプト
グローバルフックを利用して常時 マウスポインタのスクリーン座標を取得する (C#プログラミング)
○特定のキーボードのキーを使用不能にする
Discussion