適材適所

PowerShellやVBAなどプログラミング系の話多めで

【PowerShell】ウィンドウのタイトル名からプロセスを停止する【Stop-Process】

色々なウィンドウを開いて作業をしていると、たまに処理がウィンドウがフリーズすることがあります。

一度そのような状態になってしまうと復帰するまで待つか、場合によっては復帰しないのでタスクマネージャーでタスクを終了するわけですが、どうせならPowerShellからできないものかと思いました。

PowerShellにはStop-Processコマンドレットというものがあります。

このコマンドレットを使うことでプロセスを停止することができます。

しかし難点はプロセス名やプロセスIDを指定しないといけない点。

プロセス名はアプリケーションごとに一貫性がなくわかりづらく、IDはいちいち調べなくてはなりません。

どうせならウィンドウのタイトル名から指定したいところです。

というわけで、Stop-Processを使ってタイトル名からプロセスを停止できるようにする方法を紹介していきたいと思います。

f:id:shinmai_papa:20210902132109p:plain

ウィンドウのタイトル名から停止するプロセス選択する

Get-Processコマンドレットを使ってウィンドウのタイトル名を取得してみます。

ウィンドウのタイトル名はMainWindowTitleというプロパティになります。

 
Get-Process|Where-Object{$_.MainWindowTitle -ne ''} |select MainWindowTitle

バックグラウンドで動いているプロセスはMainWindowTitleに何も設定されていないのでWhere-Objectでフィルタリングしています。

ウィンドウのタイトル名の取得方法がわかったところで、抽出したいプロセスを取得してみます。

例えば「chrome」という文字をタイトルに含んだプロセスを抽出したいとします。

 
Get-Process|Where-Object{$_.MainWindowTitle -like '*chrome*'}

-like演算子を使うことでワイルドカードを使って抽出することができます。

後は簡単。

抽出されたプロセスをパイプでStop-Processに渡すだけです。いきなり停止してしまうのは気が引けるので、-WhatIfパラメータを指定して何が起こるか確認してみます。

 
Get-Process|Where-Object{$_.MainWindowTitle -like '*chrome*'} |Stop-Process -WhatIf

-WhatIfを指定すると、実際に処理を行われませんが、コマンドで何が起こるか、どんな処理が行われるかを表示してくれます。

PS C:\> Get-Process|Where-Object{$_.MainWindowTitle -like '*chrome*'} |Stop-Process -WhatIf
WhatIf: 対象 "chrome (984)" に対して操作 "Stop-Process" を実行しています。

ちゃんとStop-Processされることが確認できました。

あとは、-WhatIfを外してコマンドを実行すればウィンドウのタイトル名からプロセスを停止することができます。

関数化する

パイプを使って処理するのも悪くはないのですが、いちいち打ち込むのが面倒なので関数を作成しました。

Stop-Processコマンドレットのラッパーにするのは少し面倒だったのでウィンドウのタイトル名を指定してStop-Processするだけの関数です。

コード

Stop-Processコマンドレットはプロセスを停止してしまうという、一歩間違えると危険なコマンドレットなので、-WhatIfと-Confirm、-Verboseを使えるように[CmdletBinding(SupportsShouldProcess=$True)]を指定しています。

また、-Verboseパラメータを指定することで処理の詳細を表示するようにしました。

ウィンドウのタイトル名は-like演算子でチェックしていますのであいまい検索を使用するときは*をつけるようにします。

例:Stop-ProcessByTitle chrome

 
Function Stop-ProcessByTitle
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateScript(
        {
            $myArg=$_
            if((Get-Process|?{$_.MainWindowTitle -like $myArg}).count -gt 0)
            {
                return $True
            }
                throw("$($myArg)をタイトルに含むプロセスは見つかりませんでした。")
            })]
        [string]$MainWindowTitle)
    begin
    {
        $target=(Get-Process|?{$_.MainWindowTitle -like $MainWindowTitle})
        Write-Verbose "[$(Get-Date)] Start Process:$($MyInvocation.MyCommand)"
        Write-Verbose "[$(Get-Date)] Target Count :$($target.count)"
        $target|%{Write-Verbose "[$(Get-Date)] Target Title :$($_.MainWindowTitle)"}
    }
    process{
       $target|Stop-Process
    }
    end
    {
        Write-Verbose "[$(Get-Date)] End Process  :$($MyInvocation.MyCommand)"
    }
}

実行例

-WhatIfと-Verboseを指定して実行した場合

f:id:shinmai_papa:20210902132121p:plain

ちなみに何もつけずに実行すると無言でプロセスが消されます。

存在しないタイトル名が指定された場合はValidateScriptでチェックされます。

f:id:shinmai_papa:20210902132116p:plain

終わりに

Stop-Processコマンドレットでタイトル名からプロセスを停止する方法について紹介してみました。

勢いあまって関数まで作りましたが、作り終わった後、思いました。

「別にタスクマネジャーでもよくね?」

結果ではなく、過程に意味があります。

きっとそうだと思います。

というわけでここまでお読みいただき、ありがとうございました。