none
PowerShell Scripting: “What is the best way to extract "ContextInfo" properties for EventID 4100 in “Microsoft-Windows-PowerShell%4Operational.evtx” event log?

    Question

  • Hi All,

    How are you guys doing? I hope you all doing good. I need some advice regarding “What is the best way to extract "ContextInfo" properties for EventID 4100 in “Microsoft-Windows-PowerShell%4Operational.evtx” event log?”. I manage to extract the event ID 4100 properties from “Microsoft-Windows-PowerShell%4Operational.evtx” event log using the XML format conversion. However I want to further extract the "ContextInfo" properties. I have create below PowerShell script to extract the properties. The script work fine using "If" statement, however I think this is not the best way to do it.

    I am still learning PS everyday and having fun with it. I am open for any suggestion from the experts. Thank you so much in advances.

    mimiAufa

    Input:
    $ContextInfo ="
            Severity = Warning
            Host Name = ConsoleHost
            Host Version = x.x.xxxxxx.xxxx
            Host ID = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx
            Host Application = powershell -nop -exec bypass -EncodedCommand XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            Engine Version = x.x.xxxxxx.xxxx
            Runspace ID = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
            Pipeline ID = 1
            Command Name =
            Command Type =
            Script Name =
            Command Path =
            Sequence Number = 18
            User = DOMAIN1\MARRY2
            Connected User =
            Shell ID = Microsoft.PowerShell"

    Output:
    Severity: Warning
    Host Name: ConsoleHost
    Host Application: powershell -nop -exec bypass -EncodedCommand XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    User: DOMAIN1\MARRY2

    Sample PowerShell Script: Extract-ContextInfoProperties.ps1
    ----------------------code start-----------------------
    $ContextInfo ="
            Severity = Warning
            Host Name = ConsoleHost
            Host Version = x.x.xxxxxx.xxxx
            Host ID = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx
            Host Application: powershell -nop -exec bypass -EncodedCommand XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            Engine Version = x.x.xxxxxx.xxxx
            Runspace ID = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
            Pipeline ID = 1
            Command Name =
            Command Type =
            Script Name =
            Command Path =
            Sequence Number = 18
            User = DOMAIN1\MARRY2
            Connected User =
            Shell ID = Microsoft.PowerShell"

    If ($ContextInfo -Match "Severity")
    {
        # Multiline replace, remove everything before "Severity = "
        $ContextInfo1 = $ContextInfo -Replace "(?ms)^.*Severity = ",""
        
        # Remove every line after the "Severity = " line.
        $ContextInfo2 = $ContextInfo1 -Replace "(?ms)`n.*$",""
        
        Write-Host "Severity: $ContextInfo2"
    }
    Else
    {
        Write-Host "Severity: Not match"
    }

    If ($ContextInfo -Match "Host Name")
    {
        # Multiline replace, remove everything before "Host Name = "
        $ContextInfo3 = $ContextInfo -Replace "(?ms)^.*Host.Name = ",""
        
        # Remove every line after the "Host Name = " line.
        $ContextInfo4 = $ContextInfo3 -Replace "(?ms)`n.*$",""
        
        Write-Host "Host Name: $ContextInfo4"
    }
    Else
    {
        Write-Host "Host Name:Not match"
    }

    If ($ContextInfo -Match "Host Application")
    {
        # Multiline replace, remove everything before "Host Application = "
        $ContextInfo5 = $ContextInfo -Replace "(?ms)^.*Host.Application = ",""
        #Write-Host "Host Application: $ContextInfo"
        
        # Remove every line after the "Host Application = " line.
        $ContextInfo6 = $ContextInfo5 -Replace "(?ms)`n.*$",""
        
        Write-Host "Host Application: $ContextInfo6"
    }
    Else
    {
        Write-Host "Host Application:Not match"
    }

    If ($ContextInfo -Match "        User =")
    {
        # Multiline replace, remove everything before "        User = "
        $ContextInfo7 = $ContextInfo -Replace "(?ms)^.*        User = ",""
        
        # Remove every line after the "Host Application = " line.
        $ContextInfo8 = $ContextInfo7 -Replace "(?ms)`n.*$",""
        
        Write-Host "User: $ContextInfo8"
    }
    Else
    {
        Write-Host "User:Not match"
    }
    ----------------------code end-----------------------

    PowerShell Console Output:

    PS C:\Users\mimi\tools\PowerShell\EventID_4100> .\Extract-ContextInfoProperties.ps1
    Severity: Warning
    Host Name: ConsoleHost
    Host Application: powershell -nop -exec bypass -EncodedCommand XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    User: DOMAIN1\MARRY2

    Thursday, January 31, 2019 9:57 AM

Answers

  • You can also do this:

    $event = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-PowerShell/Operational";Id=4100} -MaxEvents 1
    $hash = $event.Properties[0].Value -replace '\\','\\'| ConvertFrom-StringData
    $contextInfo = [pscustomobject]$hash
    $contextInfo.Severity
    $contextInfo.User
    $contextInfo.'Command Name'


    \_(ツ)_/



    • Edited by jrv Friday, February 1, 2019 8:48 AM
    • Marked as answer by mimiAufa Tuesday, February 12, 2019 8:36 AM
    Friday, February 1, 2019 8:45 AM
  • This is how to do the whole thing:

    $filter = @{ 
        Logname = 'Microsoft-Windows-PowerShell/Operational'
        Id = 4100 
    }
    Get-WinEvent -FilterHashtable $filter -MaxEvents 10 |
        ForEach-Object{
            $hash = $_.Properties[0].Value -replace '\\', '\\' | ConvertFrom-StringData
            [pscustomobject]$hash
        } |
        Where-Object{ $_.User -eq 'alpha\jones' } |
        Select-Object User, Severity, 'Script Name', 'Command Name'


    \_(ツ)_/


    Friday, February 1, 2019 8:58 AM

All replies

  • You would use an XMLFilter or an XPath filter and extract the XML from the event.

    help Get-WinEvent -online.

    Some examples of XPath and XML queries.

    $xmlquery=@'
    <QueryList>
      <Query Id="0" Path="Security">
        <Select Path="Security">
         *[System[(EventID='4624')]
         and
         EventData[Data[@Name='LogonType'] and (Data='2' or Data='3')]
         ] 
        </Select>
      </Query>
    </QueryList>
    '@
    
    $xmlquery=@'
    <QueryList>
      <Query Id="0" Path="Security">
        <Select Path="Security">
         *[System[(EventID='4624') and TimeCreated[timediff(@SystemTime) &lt;= 2592000000]]
         and
         EventData[Data[@Name='LogonType'] and (Data='2' or Data='3')]] 
        </Select>
      </Query>
    </QueryList>
    '@
    Get-WinEvent -FilterXml $xmlquery -MaxEvents 10
    
    # Get event data as XML
    #build a filter
    $filter=@'
         *[System[(EventID='4624')]
         and
         EventData[Data[@Name='LogonType'] and (Data='2' or Data='3')]
         ]
    '@
    
    $xmltext=Get-WinEvent -LogName Security -FilterXPath $filter |%{$_.ToXML()}
    $xml=[xml]"<Events>$xmltext</Events>"
    
    # you now have the XML for all selected events.
    $xml.Events.Event
    
    
    $filter = @'
         *[System[(EventID='4624')]
         and
         EventData[Data[@Name='LogonType'] and (Data='2')]
         ]
    '@
    
    $xmltext = Get-WinEvent -LogName Security -FilterXPath $filter -MaxEvents 10 -ComputerName WS701 |
    	ForEach-Object{ $_.ToXML() }
    $xml = [xml]"<Events>$xmltext</Events>"
    $xml.Events.event[0].Eventdata.Data
    
    $filterXML = @'
    <QueryList>
      <Query Id="0" Path="System">
        <Select Path="System">
    		*[System[Provider[@Name='Microsoft-Windows-Kernel-General']
    			and (Level=4 or Level=0) 
    			and (EventID=12)]]
    	</Select>
      </Query>
    </QueryList>
    '@
    Get-WinEvent -ComputerName WS701 -MaxEvents 1 -FilterXml $filterXML
    
    


    \_(ツ)_/

    Thursday, January 31, 2019 4:51 PM
  • The simplest query would be a hashtable:

    get-winevent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';id=4100;Level=3}

    Search for numerous blogs that discuss how to use the event logs


    \_(ツ)_/

    Thursday, January 31, 2019 4:57 PM
  • This will dig out the embedded text block:

    $events.events.Event |%{$_.EventData.Data[0].'#text'}


    \_(ツ)_/

    Thursday, January 31, 2019 5:07 PM
  • Hi Jrv,

    Thank you for all the suggestion. However I am using below method to get the "ContextInfo" data for one record only. I am looking for a better way to extract the "ContextInfo" properties like "Severity" value, "Host Name" value, "Host Application" value and "User" value individually so that I can tabulate it in a CSV file. If you can see my coding above, I am using "If and else" statement only to extract the value. Is there a better way to do this? like using "switch" or "match" or "regex" statement to get the value of each fields in the"ContextInfo".

    Really appreciate your advice. Thank you

    MimiAufa

    #Get one recored for Event ID 4100 from Microsoft-Windows-PowerShell%4Operational.evtx
    PS C:\Users\mimi\tools\PowerShell\EventID_4100> $Event = Get-WinEvent -FilterHashtable @{Path="C:\folder_Winevt_log\Microsoft-Windows-PowerShell%4Operational.evtx";Id=4100} -MaxEvents 1

    # Convert the event to XML
    PS C:\Users\mimi\tools\PowerShell\EventID_4100> $EventXML = [xml]$Event.ToXml()

    # Get the ContextInfo data
    PS C:\Users\mimi\tools\PowerShell\EventID_4100> $EventXML.Event.EventData.Data."#text"[0]
        Severity = Warning
            Host Name = ConsoleHost
            Host Version = x.x.xxxxxx.xxxx
            Host ID = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx
            Host Application: powershell -nop -exec bypass -EncodedCommand XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            Engine Version = x.x.xxxxxx.xxxx
            Runspace ID = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
            Pipeline ID = 1
            Command Name =
            Command Type =
            Script Name =
            Command Path =
            Sequence Number = 18
            User = DOMAIN1\MARRY2
            Connected User =
            Shell ID = Microsoft.PowerShell"

    PS C:\Users\mimi\tools\PowerShell\EventID_4100>


    • Edited by mimiAufa Friday, February 1, 2019 8:27 AM
    Friday, February 1, 2019 8:26 AM
  • You have to parse the string with RegEx:

    PS D:\scripts> $event = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-PowerShell/Operational";Id=4100} -MaxEvents 1
    PS D:\scripts> $event.Properties[0].Value -match 'severity = (.*)'
    True
    PS D:\scripts> $matches[1]
    Warning
    PS D:\scripts>


    \_(ツ)_/


    • Edited by jrv Friday, February 1, 2019 8:39 AM
    Friday, February 1, 2019 8:38 AM
  • You can also do this:

    $event = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-PowerShell/Operational";Id=4100} -MaxEvents 1
    $hash = $event.Properties[0].Value -replace '\\','\\'| ConvertFrom-StringData
    $contextInfo = [pscustomobject]$hash
    $contextInfo.Severity
    $contextInfo.User
    $contextInfo.'Command Name'


    \_(ツ)_/



    • Edited by jrv Friday, February 1, 2019 8:48 AM
    • Marked as answer by mimiAufa Tuesday, February 12, 2019 8:36 AM
    Friday, February 1, 2019 8:45 AM
  • This is how to do the whole thing:

    $filter = @{ 
        Logname = 'Microsoft-Windows-PowerShell/Operational'
        Id = 4100 
    }
    Get-WinEvent -FilterHashtable $filter -MaxEvents 10 |
        ForEach-Object{
            $hash = $_.Properties[0].Value -replace '\\', '\\' | ConvertFrom-StringData
            [pscustomobject]$hash
        } |
        Where-Object{ $_.User -eq 'alpha\jones' } |
        Select-Object User, Severity, 'Script Name', 'Command Name'


    \_(ツ)_/


    Friday, February 1, 2019 8:58 AM
  • Hi jrv,

    Yes, this is the method that I am looking for. I know this is easy for you once you understand my question. I have tried the code and I understand now why you put "-replace '\\','\\'". Thank you very much for the help. I really appreciate it. You are the man :).

    PS C:\Users\mimi\tools\PowerShell\EventID_4100> $event.Properties[0].Value | ConvertFrom-StringData
    ConvertFrom-StringData : parsing "DOMAIN1\MARRY2" - Unrecognized escape sequence \S.
    At line:1 char:30
    + $event.Properties[0].Value | ConvertFrom-StringData
    +                              ~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [ConvertFrom-StringData], ArgumentException
        + FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromStringDataCommand

    Tuesday, February 12, 2019 9:14 AM