Monday, January 25, 2016

Parsing SPAuditEntry.EventData

SPAuditEntry contains information about an audited event that is connected to a site collection, site, folder, list, or list item. It provides detailed information about event in EventData property. EventData return XML which is not readable for business users. It contains GUID's.  You can see the detail information about event type and value @ https://msdn.microsoft.com/EN-US/library/office/microsoft.sharepoint.spauditentry.eventdata.aspx

I was working on custom report where EventData needs to be updated with readable data. Following is the method I created to parse the event data.


private string ParseEventData(SPWeb web, SPAuditEntry auditEntry, out string eventName)
{
    XmlDocument xmlEventData = new XmlDocument();
    xmlEventData.LoadXml(string.Format("<EventData>{0}</EventData>", auditEntry.EventData));

    string eventData = "";
    eventName = "";
    try
    {
        int userId;
        int groupId;
        string groupName;
        SPUser user;
        SPGroup group;
        string url;
        string permissionName;
        SPBasePermissions permissions;

        switch (auditEntry.Event)
        {
            case SPAuditEventType.SecGroupCreate:
                groupName = xmlEventData.DocumentElement.SelectSingleNode("/EventData/title").InnerText;
                userId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/user").InnerText);
                user = web.AllUsers.GetByID(userId);

                eventData = string.Format("Group created with name {0} by {1}", groupName, user.Name);
                eventName = "Creation of a user group for a SharePoint site collection";
                break;
            case SPAuditEventType.SecGroupDelete:
                groupId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/groupid").InnerText);
                eventData = string.Format("Group deleted with ID {0}", groupId);
                eventName = "Deletion of a group that is associated with a SharePoint site collection.";
                break;
            case SPAuditEventType.SecGroupMemberAdd:
                if (eventData.Contains("<siteadmin"))
                {
                    groupName = "Site Collection Administrator";
                    userId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/user").InnerText);
                }
                else
                {
                    groupId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/groupid").InnerText);
                    group = web.Groups.GetByID(groupId);
                    groupName = group.Name;
                    userId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/userid").InnerText);
                }

                user = web.AllUsers.GetByID(userId);
                eventData = string.Format("Added {0} to the group {1}", user.Name, groupName);
                eventName = "Addition of a new member to a group that is associated with a SharePoint site collection";
                break;
            case SPAuditEventType.SecGroupMemberDel:

                if (eventData.Contains("<siteadmin"))
                {
                    groupName = "Site Collection Administrator";
                }
                else
                {
                    groupId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/groupid").InnerText);
                    group = web.Groups.GetByID(groupId);
                    groupName = group.Name;
                }
                userId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/user").InnerText);
                user = web.AllUsers.GetByID(userId);
                eventData = string.Format("Removed {0} from group {1}", user.Name, groupName);
                eventName = "Deletion of a member from a group that is associated with a SharePoint site collection";
                break;
            case SPAuditEventType.SecRoleBindBreakInherit:
                url = xmlEventData.DocumentElement.SelectSingleNode("/EventData/url").InnerText;
                eventData = string.Format("Inheritance is break for : {0}", url);
                eventName = "Turning off inheritance of role (that is, permission level) definitions from the parent of the object.";
                break;
            case SPAuditEventType.SecRoleBindInherit:
                url = xmlEventData.DocumentElement.SelectSingleNode("/EventData/url").InnerText;
                eventData = string.Format("Set Inheritance permission level for subsite : {0}", url);
                eventName = "Turning on inheritance of security settings from the parent of the object.";
                break;
            case SPAuditEventType.SecRoleBindUpdate:
                int principalId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/principalid").InnerText);

                var eventRoleName = "";
                try
                {
                    int roleId = Convert.ToInt32(xmlEventData.DocumentElement.SelectSingleNode("/EventData/roleid").InnerText);
                    if (roleId != -1)
                    {
                        SPRoleDefinition eventRole = web.RoleDefinitions.GetById(roleId);
                        eventRoleName = eventRole.Name;
                    }
                }
                catch { }
                string operation = xmlEventData.DocumentElement.SelectSingleNode("/EventData/operation").InnerText.Replace("ensure", "");

                try
                {
                    SPUser eventUser = web.SiteUsers.GetByID(principalId);
                    eventData = operation.Trim() + " " + eventRoleName + " permissions for " + (eventUser.Name.Length > 0 ? eventUser.Name : eventUser.LoginName);
                }
                catch
                {
                    SPGroup eventGroup = web.Groups.GetByID(principalId);
                    eventData = string.Format("{0} {1} permissions for {2}", operation.Trim(), eventRoleName, (eventGroup.Name.Length > 0 ? eventGroup.Name : eventGroup.LoginName));

                }
                eventName = "Changing the permissions of a user or group for the object";
                break;
            case SPAuditEventType.SecRoleDefCreate:
                permissionName = xmlEventData.DocumentElement.SelectSingleNode("/EventData/name").InnerText;
                permissions = (SPBasePermissions)Enum.Parse(typeof(SPBasePermissions), xmlEventData.DocumentElement.SelectSingleNode("/EventData/perm").InnerText);
                eventData = string.Format("{0} permission level created with permissions : {1}", permissionName, permissions);
                eventName = "Creation of a new role (that is, permission level) definition associated with the object";
                break;
            case SPAuditEventType.SecRoleDefModify:
                permissionName = xmlEventData.DocumentElement.SelectSingleNode("/EventData/name").InnerText;
                permissions = (SPBasePermissions)Enum.Parse(typeof(SPBasePermissions), xmlEventData.DocumentElement.SelectSingleNode("/EventData/perm").InnerText);
                eventData = string.Format("{0} permission level updated with permissions : {1}", permissionName, permissions);
                eventName = "Changing a role (that is, permission level) definition associated with an object";
                break;
            case SPAuditEventType.SecRoleDefDelete:
                int permLevel = int.Parse(xmlEventData.DocumentElement.SelectSingleNode("/EventData/id").InnerText);
                eventData = string.Format("Permission Level Delete with ID {0}", permLevel);
                eventName = "Changing a role (that is, permission level) definition associated with an object";
                break;
            default:
                eventName = "";
                break;
        }

    }
    catch
    {
        eventData = auditEntry.EventData;
        eventName = auditEntry.Event.ToString();
    }
    return eventData;
}


Above parsing method works with most of the scenarios. Feel free to add other scenarios in the comment section. I hope this will be useful for someone.