2026/06/16(火)WSL2の中からPowershellでOSへ通知トーストを投げる

投稿日:

PowerShellはWSL2の中から叩けるため、WSL2の中から通知を出したいときに使える。

PowerShellなのでホスト側のWindowsからも使える。

確認環境

PowerShell 7では動かないので注意。

Env Ver
OS Windows 11 Pro 25H2 (OSビルド 26200.8655)
PowerShell 5.1.26100.8655

やり方

  1. この内容をtoast.ps1など適当な名前で保存する。文字コードはUTF-8 BOM, 改行コードはLFにしておく

    param (
        [String]$subject = "WSL Notice",
        [String]$title   = "たいとるですー",
        [String]$message = "お知らせでーす",
        [String]$icon    = "C:/env/1e1b9fdf82a6a544.png",
        [switch]$keep
    )
    
    [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
    $template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastImageAndText04)
    $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
    
    $xml.LoadXml($template.GetXml())
    $toastTextElements = $xml.GetElementsByTagName("text")
    $toastTextElements.Item(0).AppendChild($xml.CreateTextNode($title)) > $null
    $toastTextElements.Item(1).AppendChild($xml.CreateTextNode($message)) > $null
    $toastImageElements = $xml.GetElementsByTagName("image")
    $toastImageElements.Item(0).SetAttribute("src", $icon) > $null
    
    if ($keep) {
        $xml.DocumentElement.SetAttribute("scenario", "reminder") > $null
        $actions = $xml.CreateElement("actions")
        $action = $xml.CreateElement("action")
        $action.SetAttribute("content", "閉じる") > $null
        $action.SetAttribute("arguments", "dismiss") > $null
        $action.SetAttribute("activationType", "background") > $null
        $actions.AppendChild($action) > $null
        $xml.DocumentElement.AppendChild($actions) > $null
    }
    
    $toast = [Windows.UI.Notifications.ToastNotification]::new($xml)
    $appId = $subject
    $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($appId)
    
    $notifier.Show($toast)
    
  2. 次の書式で叩くと通知トーストが出る
    powershell.exe -File 'C:/path/to/toast.ps1' -subject hoge -title fuga -message piyo -icon C:/path/to/icon.png -keep
    

このスクリプトのオプション

オプション 役割
-subject 通知の表題。ここを変えると別の通知として扱われる
-title 通知のタイトル
-message メッセージ本文。一行のみ
-icon アイコン。Windowsホストの絶対パスで指定
-keep このフラグを立てると通知が消えなくなる

-subjectを変えると別の通知扱いになるため、通知を別々に貯めることができるようになる。

Windows側から叩く方法

powershell 'C:/path/to/toast.ps1' -subject hoge -title fuga -message piyo -icon C:/path/to/icon.png -keep

Windows側から叩く場合、-Fileは省略できる。

参考情報

あとがき

Claude Codeの確認と終了のイベントで通知が出ると便利かなと思って作ってみたが、まだ試せていない。

取りあえずWSL2の中と、Windowsホスト側から叩いたときに通知が出ることは確認している。

PowerShell 7で動かそうと思ったらエラーまみれで動かず、PowerShell 7の場合、NuGetパッケージを取得するか、DLLのパスを直に指定するか、サードパーティの通知ライブラリを使うかということで、諦めた。

2026/05/15(金)Windows 11でPowerShellを使って画面をオフにする方法

投稿日:

Win32APIをPowerShellから叩くことで実現できる。

確認環境

  • Windows 11 25H2 (OSビルド 26200.8457)

コード

(Add-Type -MemberDefinition @"
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);
"@ -Name "Win32API" -PassThru)::SendMessage(0xFFFF, 0x0112, 0xF170, 2)

パラメーターを解説すると0xFFFFHWND_BROADCAST0x0112WM_SYSCOMMAND0xF170SC_MONITORPOWERに相当し、2はモニタ電源を落とす固定値である。

つまり内容としては第一引数のパラメーターがHWND_BROADCASTである場合、最上位のウィンドウにWM_SYSCOMMAND指令が出され、そのパラメーターはSC_MONITORPOWER2であるということで、つまりモニタ電源をオフにするシステムコマンドを最上位のウィンドウに送っている内容になっている。

-Name "Win32API" -PassThruを外したくなるが、外すとエラーで動かなくなるので付ける必要がある。

-PassThruがあることで戻り値が生まれ、-Name "Win32API"をつけることでクラスが生まれるらしい。

参考情報

  • SendMessage function (winuser.h) - Win32 apps | Microsoft Learn
    • > HWND_BROADCAST ((HWND)0xffff)
    • LRESULT SendMessage(
      [in] HWND hWnd,
      [in] UINT Msg,
      [in] WPARAM wParam,
      [in] LPARAM lParam
      );
  • WM_SYSCOMMAND message (Winuser.h) - Win32 apps | Microsoft Learn
    • > #define WM_SYSCOMMAND 0x0112
    • > SC_MONITORPOWER 0xF170
  • GET MONITOR STATE POWER ON OR OFF | Microsoft Learn
    • •-1 (the display is powering on)
      • 2 (the display is being shut off)
  • Add-Type (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Learn
    • -Name

      作成するクラスの名前を指定します。 このパラメーターは、メンバー定義から型を生成するときに必要です。

      型名と名前空間は、セッション内で一意である必要があります。 型をアンロードしたり、変更したりすることはできません。 型のコードを変更するには、名前を変更するか、新しい PowerShell セッションを開始する必要があります。 それ以外の場合、コマンドは失敗します。

    • -PassThru
      追加された型を表す System.Runtime オブジェクトを返します。 既定では、このコマンドレットは出力を生成しません。 OUTPUTAssembly 使用して DLL ファイルを作成し、新しく作成したアセンブリから型を返す場合は、このパラメーターを使用します。

あとがき

これは私物PCと業務PCでモニタを共有しており、排他制御で利用してる時に便利な技だ。

例えばリモートワークで昼休みに私物PCにスイッチする時で、業務PCをスリープや休止にするとWSLの中身が死んだりして面倒だが、画面オフならそういうことが起きないので便利に切り替えできるという訳。

2025/07/31(木)ps1ファイルをダブルクリックで動かせるようにする

投稿日:

Windowsに入っている古くて使いづらいPowerShellをアップグレードするところから始める。

  1. Powershell 7.xを入れる
  2. PowerShellを管理者権限で起動
  3. Set-ExecutionPolicy RemoteSignedを流す
  4. hoge.ps1などの名前で適当にファイルを作り、C:\Program Files\PowerShell\7\pwsh.exeに関連付けする

2025/06/20(金)PowerShellでネットワークアダプタの状態を取得して何かを処理するサンプル

投稿日:

InterfaceDescriptionの取り方(Get-NetAdapterだけでは見切れる)

Get-NetAdapter | Format-List -Property Name,InterfaceDescription

Shell Scriptとは思想が違うためif ('Up' -eq ($adaptor | Format-List -Property status))では上手くいかない

while ($true) {
    $adaptor=Get-NetAdapter -InterfaceDescription "Intel(R) Ethernet Connection XXX" -ErrorAction SilentlyContinue
    if ($adaptor -eq $null) {
        Write-Host 'イーサネット3のStatus: UPを待機しています...'
        Start-Sleep -Seconds 5
    } else if ('Up' -eq $adaptor.status) {
        Write-Host 'イーサネット3の疎通が確認できたため、Hogeを起動します...'
        Start-Process -FilePath 'C:/path/to/Hoge.exe'
        break
    } else {
        Write-Host 'イーサネット3のStatus: UPを待機しています...'
        Start-Sleep -Seconds 5
    }
}

2023/03/28(火)バッチファイルでコマンドを管理者権限で実行する

更新日:
投稿日:

runasでは上手く出来ないっぽいのでPowerShellを呼んで実行する。管理者実行したいコマンドを分けたい時に活用できる。

確認環境

Env Ver
Windows 11 Pro 22621.1413

サンプルコード

powershell start-process <ここにコマンド> -verb runas

備考

PowerShellのリファレンスに沿って書くなら大文字小文字を書き分ける方がより正しいが、基本的に大文字と小文字を区別しないため、どっちでも動く。

powershell Start-Process <ここにコマンド> -Verb runAs