1

How to get Security ID 4663 where the Message is 0x1|0x4|etc.

I have tried different code, I only want to log about 5 codes to a CSV, I can export to CSV, and I can pull 4663 ID's only, but I can't filter on the Message Access Mask which is text in the Message field, anyone got any ideas, here is the code I have built up so far:-

$Results = foreach($server in "server-name")
{
    Get-WinEvent -ComputerName $Server -logname security -MaxEvents 10 -ErrorAction SilentlyContinue | where {$_.id -eq "4663"} | select Timecreated, ID, Message | Get-EventLog "Security" -before 4/10/2013 -InstanceId 4663 | % {
    New-Object psobject -Property @{
        Index = $_.Index
        TimeGenerated = $_.TimeGenerated
        "Account Name" = $_.ReplacementStrings[1]
        "Object Type" = $_.ReplacementStrings[5]
        "Object Name" = $_.ReplacementStrings[6]
    }
} | Write-Host

This gets the records

#$Results = foreach($server in "file-server")
#{
#    Get-WinEvent -ComputerName $Server -logname security -MaxEvents 10 -ErrorAction SilentlyContinue | where {$_.id -eq "4663"} | select #Timecreated, ID, Message | Write-Host

Results should be

Account Name: Object Name: WHERE record is one of Access Mask: "0x0","0x1","0x2","0x4","0x20","0x40","0x10000"

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343

2 Answers2

2

So lets take a deeper look into Window Event Messages.

Each message has a template. You can look at the templates like

(Get-WinEvent -ListProvider * -ErrorAction Ignore).Events |
    select Id, Version, Template |
    Format-List

We can dig down to find the event we are looking for also like

(Get-WinEvent -ListProvider * -ErrorAction Ignore).Events |
        Where-Object {$_.Id -eq 4663} |
        select Id, Version, Template |
        Format-List

We can see there are 2 versions of the template used in windows. We can also see what the proper names are also.

Template : <template xmlns="http://schemas.microsoft.com/win/2004/08/events">
             <data name="SubjectUserSid" inType="win:SID" outType="xs:string"/>
             <data name="SubjectUserName" inType="win:UnicodeString" outType="xs:string"/>
             <data name="SubjectDomainName" inType="win:UnicodeString" outType="xs:string"/>
             <data name="SubjectLogonId" inType="win:HexInt64" outType="win:HexInt64"/>
             <data name="ObjectServer" inType="win:UnicodeString" outType="xs:string"/>
             <data name="ObjectType" inType="win:UnicodeString" outType="xs:string"/>
             <data name="ObjectName" inType="win:UnicodeString" outType="xs:string"/>
             <data name="HandleId" inType="win:Pointer" outType="win:HexInt64"/>
             <data name="AccessList" inType="win:UnicodeString" outType="xs:string"/>
             <data name="AccessMask" inType="win:HexInt32" outType="win:HexInt32"/>
             <data name="ProcessId" inType="win:Pointer" outType="win:HexInt64"/>
             <data name="ProcessName" inType="win:UnicodeString" outType="xs:string"/>
             <data name="ResourceAttributes" inType="win:UnicodeString" outType="xs:string"/>
           </template>

In the post we want to get access mask. We can see in the template

<data name="AccessMask" inType="win:HexInt32" outType="win:HexInt32"/>

So we are going to get all events that meet the ID we want which is 4663 and limit the output to 10

Get-WinEvent -logname security -FilterXPath "*[System[EventID=4663]]" -MaxEvents 10

We will turn that output into XML and parse down to we get to those settings then create a PSObject to store all those settings. Then we will add each PSObject to a ArrayList.

$ArrayList = New-Object System.Collections.ArrayList
Get-WinEvent -logname security -FilterXPath "*[System[EventID=4663]]" -MaxEvents 10 | %{
    $XML = [xml]$_.toXml()
    $PsObject =  New-Object psobject
    $XML.Event.EventData.Data | %{
        $PsObject | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_."#text"
    }
    $ArrayList.add($PsObject) | out-null
}

$ArrayList | Select AccessMask

We select only AccessMask on the arraylist and we are good.

On a End Note I have written a function for this.

function Parse-WindowsEvents(){
    param(
        [Parameter(Position=1, ValueFromPipeline)]
        [object[]]$Events
    )
    process{
        $ArrayList = New-Object System.Collections.ArrayList
        $Events  | %{
            $EventObj = $_
            $EventObjFullName = $_.GetType().FullName
            if($EventObjFullName -like "System.Diagnostics.EventLogEntry"){   
                $EventObj = Get-WinEvent -LogName security -FilterXPath "*[System[EventRecordID=$($_.get_Index())]]"
            }elseif($EventObjFullName -like "System.Diagnostics.Eventing.Reader.EventLogRecord"){

            }else{
                throw "Not An Event System.Diagnostics.Eventing.Reader.EventLogRecord or System.Diagnostics.EventLogEntry"
            }
            $PsObject =  New-Object psobject
            $EventObj.psobject.properties | %{
                $PsObject | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
            }
            $XML = [xml]$EventObj.toXml()
            $PsObject2 = New-Object psobject
            $XML.Event.EventData.Data | %{
                $PsObject2 | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_."#text"
            }
            $PsObject | Add-Member -MemberType NoteProperty -Name ParsedMessage -Value $PsObject2
            $ArrayList.add($PsObject) | out-null
        }
        return $ArrayList
    }
}

Example Usages

Get-EventLog -LogName Security | select -first 3 | Parse-WindowsEvents | select id, recordid -ExpandProperty parsedmessage | fl

or

get-winevent -logName security | parse-winevents

The function will add a new property to the object called ParsedMessage

ArcSet
  • 6,518
  • 1
  • 20
  • 34
  • That's amazing ArcSet, what a great explanation, this is going into my Evernote notes. It works a treat. Have a great day. – David Armstrong Jan 29 '19 at 10:26
  • @DavidArmstrong I added a function for reusability at the bottom – ArcSet Jan 29 '19 at 14:13
  • Thanks ArcSet, it looks good, but I just can't get by the errors, this is what I put into the line to call the function: get-winevent -ComputerName $ComputerName -logname security | -FilterXPath "*[System[EventID=4663]] " -MaxEvents 5 Obviously Im wrong. heres what I have: Get-WinEvent -ComputerName $ComputerName -logname security -FilterXPath "*[System[EventID=4663]] " -MaxEvents 5 | where {($_.Message -match '\b0x0\b' -or $_Message -Match '\b0x1\b' -or $_.Message -match '\b0x4\b' -or $_.Message -match '\b0x20\b' -or $_.Message -match '\b0x40\b' -or $_.Message -match '\b0x10000\b')} – David Armstrong Jan 30 '19 at 11:41
  • @DavidArmstrong `Get-WinEvent -ComputerName $ComputerName -logname security -FilterXPath "*[System[EventID=4663]] " -MaxEvents 5 | Parse-WindowsEvents | ?{ @("0x10000","0x40","0x20","0x4","0x1","0x0") -contains $_.ParsedMessage.AccessMask}` Use the function in my post, Paste the function above this line – ArcSet Jan 30 '19 at 14:03
  • Apologies for the delay ArcSet, this works well, just took me a bit to filter out the fields I needed, can't thank you enough. This is brilliant. My filtering: $AccessMask = $PsObject | Select-String -Pattern "Access Mask.*?;" -AllMatches | foreach {$_.matches.value} $AccessMask = $AccessMask -replace "(\t){2}|;","" $AccountName = $PsObject | Select-String -Pattern "Account Name.*?\n" -AllMatches | foreach {$_.matches.value} $AccountName = $AccountName -replace "(\t){2}","" I used this filter on 4 fileds I needed to so I can see who last accessed a file. Amazing ArcSet – David Armstrong Feb 04 '19 at 13:52
0
Get-winEvent -Logname Security | where {($_.Id -eq '4663') -and ($_.Message -match '0x0' -or $_Message -Match '0x1' -or $_.Message -match '0x4' -or $_.Message -match '0x20' -or $_.Message -match '0x40' -or $_.Message -match '0x10000')}

Is this what you are looking for?

Leon Evans
  • 146
  • 1
  • 6
  • Thanks Leon for taking the time to share your expertise, this is great, in the end I went with ArcSet's code as it was easier for me to add the additional information I needed. Have a great day. – David Armstrong Jan 29 '19 at 10:29
  • Just wanted to give you a vote up Leon as I used your filtering along with ArcSet's code to retrieve and filter the data. – David Armstrong Jan 29 '19 at 14:15