none
Set-WMIInstanceのComamndoLineEventConsumerで%Targetinstance.Message%を引数に使用したいのですが RRS feed

  • 質問

  • Set-WMIInstanceで任意のOSイベントが書き込まれた際にPowerShellスクリプトを実行したいと考えています。

    Set-WmiInstanceでフィルターを設定し、コンシューマーとしてComamndLineEventConsumerでPowerShellスクリプトを

    実行するようにしています。

    このComamndoLineEventConsumerでOSイベントログの[全般](ログメッセージの詳細)をPowerShellスクリプトに引き渡したいのですが、%Targetinstance.Message%を引数にしていすると、%Targetinstance.Message%の内容が1行の場合は問題なく動作するのですが、

    2行以上になるとエラーになるようでスクリプトが起動されません。改行が含まれているとだめなような気がしますがその改行を取り除くことは可能でしょうか -replaceをいれてみましたが

    CommandLineTemplaet= 内では動作しないようです。指定の仕方が悪いのかもしれませんが・・・

    コンシューマの引数の設定は以下のようにしています。

    CommandLineTemplate =Powershell.exe test.ps1 "%Targetinstance.Message%"

    なお、ファイルへ記録するコンシューマーで複数行のメッセージの場合どうなのか確認しましたが問題なくファイルへ書き込むことができました。

    (LogFileEventConsumerで同様に引数として使用すると2行以上のメッセージでも任意のファイルに書き込むことができました。)

    2016年3月22日 3:43

回答

  • 最初にご提示された、
    CommandLineTemplate =Powershell.exe test.ps1 "%Targetinstance.Message%"
    が何なのかよく分からずに返信してしまいましたが、これはPowerShellの連想配列の一部だったんですね。(クォーテーションで値を括ってなかったので勘違いしてました…)

    ご提示の、
    CommandLineTemplate ="Powershell.exe test.ps1 " + """" + '%Targetinstance.Message%' + """"
    だと、
    CommandLineTemplate =”Powershell.exe test.ps1 ""%Targetinstance.Message%"""
    と等価なので、実際のコマンドラインとして渡される値は、
    Powershell.exe test.ps1 "%Targetinstance.Message%"
    となります。

    なので、コマンドライン引数パーサーがダブルクォーテーションを外して、powershell.exeには%Targetinstance.Message%に含まれる文字列がそのまま渡ってしまうので、もしそこに半角スペースが入っていれば、今度はpowershellの引数パーサーが、複数の引数が指定されたと解釈してしまいます。

    であれば、やはり

    CommandLineTemplate = "Powershell.exe test.ps1 '%Targetinstance.Message%'"

    で良いのではないかと思いますが、やはりダメでしょうか…


    ところで、

    > Powershell.exe test.ps1 "AAA BBB CCC"

    これはやはり3つの引数として解釈されませんか?

    Powershell.exe test.ps1 'AAA BBB CCC'

    であれば、1つの引数としてpowershell.exeに渡るかと思います。
    • 回答としてマーク nhy67ujm 2016年3月25日 9:15
    2016年3月25日 2:35
    モデレータ

すべての返信

  • 追加情報です。

    CommandLineTemplate =Powershell.exe test.ps1 "%Targetinstance.Message%"

    CommandLineTemplateに展開する際、"%Targetinstance.Message%"は、半角スペースが含まれている場合区切られているようです。1行のメッセージの場合は、”(ダブルクォーテーション)でくくっていても区切られてスクリプトに渡されてしまうようです。

    その上で2行にわたるメッセージの場合はスクリプトが実行されない状態になります。

    2016年3月22日 6:37
  • ダブルクォートだと引数パーサーが"を外してからpowershell.exeに引数を渡すみたいですね。

    CommandLineTemplate =Powershell.exe test.ps1 '%Targetinstance.Message%'

    のように、シングルクォートで囲ってみるのはいかがでしょうか?

    2016年3月23日 8:26
    モデレータ
  • 返信ありがとうございます。

    シングルクォートは、変数を展開せずにそのまま文字列として展開されると思っていたので試していませんでした。

    半分あきらめていて、%Targetinstance.RecordNumber%をスクリプトに引き渡して、RecordNumberをキーにしてwevtutil.exeを使用して目的のイベントログの情報を取得する方法を試していました。Get-WmiObjectやGet-WinEventでイベントログを検索するとレスポンスがわるく使用に耐えれないと感じました。Get-EventLogは負荷が高すぎて使用できないのでGet-WinEventが使用できるようになってからは使用していません。

    %TargetInstance.Message%がそのまま使用できれば不要な処理を追加しなくてよいので所としてもすっきりするので期待しています。

    2016年3月24日 13:58
  • %%は環境変数であり、powershell.exeに渡される前に展開されると思うのですが、違うのでしょうか?
    2016年3月24日 18:46
    モデレータ
  • > %%は環境変数であり、powershell.exeに渡される前に展開されると思うのですが、違うのでしょうか?

    展開されるかどうかということでは展開されています。

    ただ、それを引き渡す際に%TargetInstance.Message%の内容にスペースが含まれているとPowershellスクリプトが別の引数として受け取るようです。

    シングルクォーテーションで%TargetInstance.Message%をくくってみましたが結果は同じでした。

    例えば、%TargetInstance.Message%の内容が "AAA BBB CCC"だったとすると、以下のように%TargetInstance.Message%をダブルクォーテーションでくくったとしてもPowershellスクリプトには、AAAとBBBとCCCという3つの引数として受け取るようです。

    CommandLineTemplate =”Powershell.exe test.ps1" + """" + '%Targetinstance.Message%' + """"

    スクリプト内で入力された引数をArgsで出力するとArgs[0]にAAA、Args[1]にBBB、Args[2]にCCC、という形で格納されるので別々の変数として受け取ったと理解しています。

    なお、Powershellスクリプトを以下のように単体で実行すると1つの引数として受け取るのでSet-WmiInscatnce内での問題(事象)と思います。

    Powershell.exe test.ps1 "AAA BBB CCC"

    また、%TargetInstance.Message%に改行が含まれている場合はスクリプトは実行されませんでした。(変数の展開に失敗しているようです)

    2016年3月25日 0:52
  • 最初にご提示された、
    CommandLineTemplate =Powershell.exe test.ps1 "%Targetinstance.Message%"
    が何なのかよく分からずに返信してしまいましたが、これはPowerShellの連想配列の一部だったんですね。(クォーテーションで値を括ってなかったので勘違いしてました…)

    ご提示の、
    CommandLineTemplate ="Powershell.exe test.ps1 " + """" + '%Targetinstance.Message%' + """"
    だと、
    CommandLineTemplate =”Powershell.exe test.ps1 ""%Targetinstance.Message%"""
    と等価なので、実際のコマンドラインとして渡される値は、
    Powershell.exe test.ps1 "%Targetinstance.Message%"
    となります。

    なので、コマンドライン引数パーサーがダブルクォーテーションを外して、powershell.exeには%Targetinstance.Message%に含まれる文字列がそのまま渡ってしまうので、もしそこに半角スペースが入っていれば、今度はpowershellの引数パーサーが、複数の引数が指定されたと解釈してしまいます。

    であれば、やはり

    CommandLineTemplate = "Powershell.exe test.ps1 '%Targetinstance.Message%'"

    で良いのではないかと思いますが、やはりダメでしょうか…


    ところで、

    > Powershell.exe test.ps1 "AAA BBB CCC"

    これはやはり3つの引数として解釈されませんか?

    Powershell.exe test.ps1 'AAA BBB CCC'

    であれば、1つの引数としてpowershell.exeに渡るかと思います。
    • 回答としてマーク nhy67ujm 2016年3月25日 9:15
    2016年3月25日 2:35
    モデレータ
  • シングルクォーテーションでくくったところ、%TargetInstance.Message%を取得することが分割されずに引数として渡すことができました。

    なお、%TargetInstance.Message%の内容が複数行である場合、これは複数の引数に分かれるようです。

    受け取ったスクリプトでは%TargetInstance.Message%の1行目を$Args[0]、2行目を$Args[1]に格納されました。

    これはForEachで必要な分取り込めばよいので問題ありません。

    ちなみにこちらは3つの引数として受け取っていました。

    >> Powershell.exe test.ps1 "AAA BBB CCC"
    > これはやはり3つの引数として解釈されませんか?

    なお、Powershellのプロンプト上でPowershell.exe test.ps1 "AAA BBB CCC"を実行するとこれは1つの引数として受け渡していました。

    シングルクォーテーションの解釈が少々間違っていたようです。

    最終的に目的としていたフィルターで設定したイベントログの情報をコンシューマーに引き渡すことができましたので大変うれしく思っております。

    大変感謝しております。ありがとうございました。

    2016年3月25日 9:38
  • 訂正します。

    > なお、%TargetInstance.Message%の内容が複数行である場合、これは複数の引数に分かれるようです。

    > 受け取ったスクリプトでは%TargetInstance.Message%の1行目を$Args[0]、2行目を$Args[1]に格納されました。

    %TargetInstance.Message%は、内容が複数行でも1つの値として引き渡されていました。$Args[0]に改行コードを含んだ文字列が格納されていました。

    2016年3月25日 10:20