6️⃣

PowerShell 6.0以降(Core Edition)でイベントログを出力する方法

2024/03/25に公開

概要

Windowsで標準インストールされているPowerShell 5.1のバージョンでは、
New-EventLogコマンドレットやWrite-EventLogコマンドレットなどを使用して自作のイベントログが出力できます。

ただ、PowerShell 6.0以降のCore Editionでは、それらのコマンドレットは仕様変更により使えなくなりました。
今回、バージョンが6.0以降でも自作のイベントログを出力する方法を調べました。

※ PowerShell 5.1でイベントログを出力する方法は、こちらの記事を参照してください。

この記事のターゲット

  • PowerShell ユーザーの方
  • PowerShell バージョン 6.0以降の環境(Core エディション)でイベントビューアーにログを出力したい方
    • 【パターンA】自作のイベントソースとイベントIDで出力
    • 【パターンB】既存のイベントソースとイベントIDで出力

環境

PS C:\Users\"ユーザー名"> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

PS C:\Users\"ユーザー名">

対応方法

【パターンA】自作のイベントソースとイベントIDで出力

PowerShell 6.0以降の環境で登録済みのソース・イベントIDを出力したい場合は、New-WinEventコマンドレットで対応可能ですが、
PowerShell 6.0以降の環境で自作のイベントソース(イベントプロバイダー)・イベントIDを作成するPowerShellコマンドレットの情報は見つけられませんでした。
(おそらく、何かしらの方法はあると思っています。)

今回、「PowerShell 6.0以降 + 自作のイベントログを出力」の場合、.NET FrameworkのSystem.Diagnostics.EventLogクラスを使用する方法で紹介します。

  1. 管理者権限でPowerShellを起動
    コンソール(PowerShellウィンドウ)で実行する場合、「 ⊞ Windowsキー + R 」 でファイル名を指定して実行(R)を起動。
    pwsh」と入力し、Ctrl + Shift + Enter で管理者として実行。

  2. ログの種類とイベントソースを指定
    ログの種類を Application とすることで、イベントビューアーの Windowsログ -> アプリケーション 内に記録する。
    また、自作のイベントソースである MyAppSource を出力するための準備。

    ログの種別とイベントソースの名前を変数に代入
    $target_logtype = "Application"
    $target_eventsource = "MyAppSource"
    
    補足情報:作成するソース名の存在チェックを行う場合 < クリックで折りたたみが開く >
    SourceExistsメソッドにて判定
    if ([System.Diagnostics.EventLog]::SourceExists($target_eventsource)) {
        # 存在する場合の処理
    }
    else {
        # 存在しない場合の処理
    }
    
  3. イベントソースの作成

    “管理者として実行”の必要あり
    # ソース作成用のオブジェクトを作成
    $eventsource_data = New-Object System.Diagnostics.EventSourceCreationData($target_eventsource, $target_logtype)
    # 自作のソースを作成
    [System.Diagnostics.EventLog]::CreateEventSource($eventsource_data)
    
    補足情報:作成したイベントソースを削除する方法 < クリックで折りたたみが開く >

    PowerShellコンソールを管理者として実行し、下記のコマンドレットを実行。

    コピー用
    [System.Diagnostics.EventLog]::DeleteEventSource("削除対象のソース名")
    
    実際に実行した結果
    PS C:\WINDOWS\system32> Write-Host "$target_eventsource"
    MyAppSource
    PS C:\WINDOWS\system32>
    PS C:\WINDOWS\system32> [System.Diagnostics.EventLog]::DeleteEventSource($target_eventsource)
    PS C:\WINDOWS\system32>
    
  4. 自作のイベントログを出力
    イベントログの出力に関しては、管理者権限は不要です。
    なお、前段の作業であるイベントソースを作成していなくとも、管理者権限でここの「WriteEntry」メソッドを実行すると、
    「 イベントソースの作成 + イベントログの出力 」を2つ自動で実行してくれます。

    補足情報:“管理者権限で自作のイベントソースの登録”と“一般権限でそのイベントソースをログ出力”をわける必要性 < クリックで折りたたみが開く >

    管理者権限で「WriteEntry」メソッドを実行すると、イベントソース と イベントログ の両方を実行するのであれば、
    わざわざイベントソースのみを登録する「CreateEventSource」は不要と判断される方がいるかもしれませんが、
    運用方法によっては「CreateEventSource」メソッドは必要です。

    たとえば、管理者権限を持たない一般ユーザーで“自作のイベントログを出力するPowerShellスクリプト”を実行させたい場合、
    管理者権限が必要な範囲は極力、最小限にした方が良いです。

    管理者権限があれば両方実行してくれるという理由で、一般ユーザーに管理者権限のユーザー名とパスワードを開示してしまうと、不要なトラブルが発生してしまう可能性があります。

    このケースで私が良いと思う方法は、“自作のイベントソースを登録するPowerShellスクリプト”と“自作のイベントソースを指定してイベントログを出力するPowerShellスクリプト”の2つにわける方法です。

    そうすることでセットアップは管理者権限を持っているユーザーのみが行い、実作業のイベントログを出力するPowerShellスクリプトでは、一般ユーザーで実施する事となり、管理者権限の作業範囲が必要最小限となります。
    (セットアップする端末の台数が多い場合は、また別の運用を検討する必要あり。)

    コピー用
    # 対象の ログの種類 と イベントソース を確認
    Write-Host "LogType: [$target_logtype], EventSource: [$target_eventsource]"
    # イベントログ書き込み用のオブジェクトを作成
    $eventlog_data = New-Object System.Diagnostics.EventLog($target_logtype)
    # ソースを指定
    $eventlog_data.Source = $target_eventsource
    # 「メッセージ内容、レベル、イベントID」を指定してイベントログに出力
    $eventlog_data.WriteEntry("メッセージ内容", "エラーレベル", "イベントID")
    
    一般ユーザーでも実行可能
    # 対象の ログの種類 と イベントソース を確認
    Write-Host "LogType: [$target_logtype], EventSource: [$target_eventsource]"
    # イベントログ書き込み用のオブジェクトを作成
    $eventlog_data = New-Object System.Diagnostics.EventLog($target_logtype)
    # ソースを指定
    $eventlog_data.Source = $target_eventsource
    # 「メッセージ内容、レベル、イベントID」を指定してイベントログに出力
    $eventlog_data.WriteEntry("Test Message.", "Information", 1001)
    

    WriteEntryコマンドにより出力したログをイベントビューアーで確認(自作のイベントソース・イベントIDの場合)
    画像:WriteEntryコマンドにより出力したログをイベントビューアーで確認(自作のイベントソース・イベントIDの場合)

【パターンB】既存のイベントソースとイベントIDで出力

※ 既存のイベントソースやイベントIDを確認する方法は、こちらの記事を参照してください。

B-1)dotNET Frameworkを使う方法

初期状態で登録されているイベントソース・イベントIDの場合、一般ユーザー権限のユーザーだけで対応可能。

登録済みのイベントソース・イベントIDの場合は、一般ユーザーで実行可能
[System.Diagnostics.EventLog]::WriteEntry("イベントソース", "出力するメッセージ", "エラーの種類", "イベントID")

なお、WriteEntryメソッドにはオーバーロードがあり、引き渡す引数の数によって動作が変わります。
引数を増やすと、よりログ出力する際の情報を追加可能。

WriteEntryメソッドのオーバーロードについて
引数の数 オーバーロードの指定方法 説明
6個 WriteEntry(String, String, EventLogEntryType, Int32, Int16, Byte[]) 引数1:イベント ソース、引数2:メッセージ テキスト、引数3:エラーレベル、引数4:イベントID、引数5:カテゴリー、引数6:付加するバイナリ データ
5個(引数で渡すデータ型の違い) WriteEntry(String, String, EventLogEntryType, Int32, Int16) 引数1:イベント ソース、引数2:メッセージ テキスト、引数3:エラーレベル、引数4:イベントID、引数5:カテゴリー
5個(引数で渡すデータ型の違い) WriteEntry(String, EventLogEntryType, Int32, Int16, Byte[]) 引数1:メッセージ テキスト、引数2:エラーレベル、引数3:イベントID、引数4:カテゴリー、引数5:付加するバイナリーデータ
4個(引数で渡すデータ型の違い) WriteEntry(String, String, EventLogEntryType, Int32) 引数1:イベント ソース、引数2:メッセージ テキスト、引数3:エラーレベル、引数4:イベントID
4個(引数で渡すデータ型の違い) WriteEntry(String, EventLogEntryType, Int32, Int16) 引数1:メッセージ テキスト、引数2:エラーレベル、引数3:イベントID、引数4:カテゴリー
3個(引数で渡すデータ型の違い) WriteEntry(String, String, EventLogEntryType) 引数1:イベント ソース、引数2:メッセージ テキスト、引数3:エラーレベル
3個(引数で渡すデータ型の違い) WriteEntry(String, EventLogEntryType, Int32) 引数1:メッセージ テキスト、引数2:エラーレベル、引数3:イベントID
2個(引数で渡すデータ型の違い) WriteEntry(String, EventLogEntryType) 引数1:メッセージ テキスト、引数3:エラーレベル
2個(引数で渡すデータ型の違い) WriteEntry(String, String) 引数1:イベント ソース、引数2:メッセージ テキスト
1個 WriteEntry(String) 引数1:メッセージ テキスト

参考情報:WriteEntryメソッド
参考情報:エラーの種類で設定する数値

実際に実行した結果
PS C:\Users\"ユーザー名"> [System.Diagnostics.EventLog]::WriteEntry("Winsrv", "テストメッセージ", 1, 10001)
PS C:\Users\"ユーザー名">

WriteEntryコマンドにより出力したログをイベントビューアーで確認(登録済みのイベントソース・イベントIDの場合)
画像:WriteEntryコマンドにより出力したログをイベントビューアーで確認(登録済みのイベントソース・イベントIDの場合)

B-2)PowerShellコマンドレット「New-WinEvent」を使う方法

登録済みのイベントソース・イベントIDの場合は、一般ユーザーで実行可能
New-WinEvent -ProviderName "イベントソース" -id "イベントID" -Payload("イベントIDに即したデータを指定")
実際に実行した結果
New-WinEvent -ProviderName "Microsoft-Windows-RestartManager" -id 10000 -Payload(99, [System.Datetime]::UtcNow.ToFileTime())

New-WinEventコマンドレットにより出力したログをイベントビューアーで確認(登録済みのイベントソース・イベントIDの場合)
画像:New-WinEventコマンドレットにより出力したログをイベントビューアーで確認(登録済みのイベントソース・イベントIDの場合)

まとめ

  • PowerShell 6.0 以降では、New-EventLogやWrite-EventLogなどバージョン5.1で使えていたコマンドレットが使用不可
  • PowerShell 6.0 以降では、大きくわけて2通りの方法でイベントログに出力
    • 【パターンA】自作のイベントソース・イベントIDを出力
      .NET Frameworkを使い、WriteEntryメソッドにより対応

      1. ログの種類とイベントソースを指定

        ログの種別とイベントソースの名前を変数に代入
        $target_logtype = "Application"
        $target_eventsource = "MyAppSource"
        
      2. イベントソースの作成

        コピー用
        # ソース作成用のオブジェクトを作成
        $eventsource_data = New-Object System.Diagnostics.EventSourceCreationData("作成するイベントソース名", "ログの種類")
        # 自作のソースを作成
        [System.Diagnostics.EventLog]::CreateEventSource($eventsource_data)
        
        “管理者として実行”の必要あり
        # ソース作成用のオブジェクトを作成
        $eventsource_data = New-Object System.Diagnostics.EventSourceCreationData($target_eventsource, $target_logtype)
        # 自作のソースを作成
        [System.Diagnostics.EventLog]::CreateEventSource($eventsource_data)
        
      3. 自作のイベントログを出力

        一般ユーザーでも実行可能
        # 対象の ログの種類 と イベントソース を確認
        Write-Host "LogType: [$target_logtype], EventSource: [$target_eventsource]"
        # イベントログ書き込み用のオブジェクトを作成
        $eventlog_data = New-Object System.Diagnostics.EventLog($target_logtype)
        # ソースを指定
        $eventlog_data.Source = $target_eventsource
        # 「メッセージ内容、レベル、イベントID」を指定してイベントログに出力
        $eventlog_data.WriteEntry("メッセージ内容", "エラーレベル", "イベントID")
        
    • 【パターンB】既存のイベントソース・イベントIDを出力

      • B-1)dotNET Frameworkを使う方法

        登録済みのイベントソース・イベントIDの場合は、一般ユーザーで実行可能
        [System.Diagnostics.EventLog]::WriteEntry("イベントソース", "出力するメッセージ", "エラーの種類", "イベントID")
        
      • B-2)PowerShellコマンドレット「New-WinEvent」を使う方法

        登録済みのイベントソース・イベントIDの場合は、一般ユーザーで実行可能
        New-WinEvent -ProviderName "イベントソース" -id "イベントID" -Payload("イベントIDに即したデータを指定")
        

関連記事

https://zenn.dev/haretokidoki/articles/48de2dc693f9c0
https://zenn.dev/haretokidoki/articles/0a179fe71a2cc8
https://haretokidoki-blog.com/pasocon_powershell-startup/
https://zenn.dev/haretokidoki/articles/7e6924ff0cc960

GitHubで編集を提案

Discussion