Matching the ScopeId from SPAuditEntry.EventData to SPListItem
To match the ScopeId in the EventData property of the SPAuditEntry to a SPListItem you need to use the hidden column 'ScopeId' and not the Id property of SPListItem.
Here is what I mean
The following XML is returned in the EventData proprty for a SPAuditEventType of SecRoleBindUpdate. To match the Scope returned in the XML to SPSite, SPWeb and SPList object you would use the Id property of this object, but not for the SPListItem.
<roleid>1073741826</roleid>
<principalid>11</principalid>
<scope>72EEC412-B14B-4EFB-AB95-EA821A3A4C63</scope>
You need to use the 'ScopeId' column of the SPListItem
So why can't I just use the SPAuditQuery.RestrictToListItem method to return the audit entries for that SPListItem.
It doesn't work, that's why and this has been confirmed by MS Support.
Here is a workaround that will link the ScopeId to the SPListItem that triggered the audit entry
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string siteUrl = "http://url";
string listName = "TheList";
string scopeIdFromItem = string.Empty;
string scopeIdFromChange = string.Empty;
try
{
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[listName];
SPRegionalSettings regionalSettings = web.RegionalSettings;
SPTimeZone timeZone = regionalSettings.TimeZone;
SPAuditQuery query = new SPAuditQuery(site);
SPAuditEntryCollection auditEntries = site.Audit.GetEntries(query);
foreach (SPAuditEntry auditEntry in auditEntries)
{
if (IsSecurityEvent(auditEntry))
{
try
{
if (auditEntry.Event.ToString().ToUpper() == "SECROLEBINDUPDATE")
{
// Should really do a proper XML query here, but for demo just do some string stuff
scopeIdFromChange = auditEntry.EventData.ToString().Substring((auditEntry.EventData.ToString().Length - 44), 36);
foreach (SPListItem item in list.Items)
{
// Square brackets round the scope id need to be removed
scopeIdFromItem = item["ScopeId"].ToString().Substring(1, 36);
if (scopeIdFromChange == scopeIdFromItem)
{
Console.Write("Event Data : "); Console.WriteLine(auditEntry.EventData.ToString());
Console.Write("Occurred : "); Console.WriteLine(timeZone.UTCToLocalTime(auditEntry.Occurred));
if (list.BaseType == SPBaseType.DocumentLibrary)
{
Console.WriteLine("Security changed on file: " + item.File.ToString());
}
if (list.BaseType == SPBaseType.GenericList)
{
Console.WriteLine("Security changed on item: " + item.Name.ToString());
}
}
else
{
Console.WriteLine("No item found in list " + siteUrl + "/" + listName + " for " + auditEntry.EventData.ToString());
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static bool IsSecurityEvent(SPAuditEntry entryToTest)
{
SPAuditEventType[] SECURITY_EVENTS = new SPAuditEventType[]
{
SPAuditEventType.SecGroupCreate,
SPAuditEventType.SecGroupDelete,
SPAuditEventType.SecGroupMemberAdd,
SPAuditEventType.SecGroupMemberDel,
SPAuditEventType.SecRoleBindBreakInherit,
SPAuditEventType.SecRoleBindInherit,
SPAuditEventType.SecRoleBindUpdate,
SPAuditEventType.SecRoleDefBreakInherit,
SPAuditEventType.SecRoleDefCreate,
SPAuditEventType.SecRoleDefDelete,
SPAuditEventType.SecRoleDefModify
};
foreach (SPAuditEventType eventType in SECURITY_EVENTS)
{
if (eventType == entryToTest.Event) return true;
}
return false;
}
}
}