Recently, I worked with a client who required the retention of SharePoint Online audit logs for over 20 years. In this article, I documented a solution to this problem.
Microsoft 365 Unified Log can retain the events for up to 10 years. While this is an impressive period, it does not meet our requirement of 20+ year retention.
Deploy Microsoft Sentinel and funnel the logs to Azure Blob Storage. Free Sentinel trial is available for 31 days. To calculate the price, use the Sentinel Price Calculator 📱
This is a high-level list of steps that are involved in the solution:
This is the high-level architecture that shows all important components:
Select the cheapest tier and the lowest redundancy option for cost savings.
Microsoft Sentinel is an Azure-based security information and event management (SIEM) service. Among other things, Microsoft Sentinel can funnel all events from Microsoft 365 and push them to Azure Monitor Log Analytics workspace. Microsoft Sentinel is billed for the volume of data stored in a Log Analytics workspace and analyzed in Microsoft Sentinel.
OfficeActivity
💡It might take 5-20 minutes for the OfficeActivities table to start populating. If you are working on a test tenant, you might want to click on some files in SharePoint to make sure some if your activity is captured.
// Files and Sharing, ALL IN ONEOfficeActivity| where OfficeWorkload in ("OneDrive", "SharePoint")| where Operation in ("FileAccessed", "FileCopied", "FileDeleted", "FileDeletedFirstStageRecycleBin","FileDeletedSecondStageRecycleBin", "FileDownloaded", "FileModified", "FileMoved","FileVersionsAllMinorsRecycled", "FileVersionsAllRecycled", "FileVersionRecycled","FileRenamed", "FileUploaded","SharingSet", "SecureLinkCreated", "SecureLinkUsed", "AddedToSecureLink", "CompanyLinkCreated","AnonymousLinkCreated", "AnonymousLinkUpdated", "SharingInvitationCreated", "SharingInvitationUpdated","CompanyLinkUsed" )| where UserId != "app@sharepoint"| where SourceFileName != "AllItems.aspx"| project TimeGenerated, DestinationFileName, Operation,UserId,ClientIP,Site_Url,SourceFileName,ItemType,TargetUserOrGroupName,TargetUserOrGroupType,OfficeObjectId,UserAgent
This query will filter out specific events from the OfficeActivity table into a dynamic table. Keep reading for more details about this particular query.
Summary Rule wizard result:
It will be expensive to retain all SharePoint activities. This is why I recommend only retaining the activities you absolutely need. Use the official list of Audit activities as a reference. For example, I recommend the following operations:
Friendly name | Operation | Description |
---|---|---|
Accessed file | FileAccessed | User or system account accesses a file. |
Copied file | FileCopied | User copies a document from a site. The copied file can be saved to another folder on the site. |
Deleted file | FileDeleted | User deletes a document from a site. |
Deleted file from recycle bin | FileDeletedFirstStageRecycleBin | User deletes a file from the recycle bin of a site. |
Deleted file from second-stage recycle bin | FileDeletedSecondStageRecycleBin | User deletes a file from the second-stage recycle bin of a site. |
Downloaded file | FileDownloaded | User downloads a document from a site. |
Modified file | FileModified | User or system account modifies the content or the properties of a document located on a site. |
Moved file | FileMoved | User moves a document from its current location on a site to a new location. |
Recycled all minor versions of file | FileVersionsAllMinorsRecycled | User deletes all minor versions from the version history of a file. The deleted versions are moved to the site’s recycle bin. |
Recycled all versions of file | FileVersionsAllRecycled | User deletes all versions from the version history of a file. The deleted versions are moved to the site’s recycle bin. |
Recycled version of file | FileVersionRecycled | User deletes a version from the version history of a file. The deleted version is moved to the site’s recycle bin. |
Renamed file | FileRenamed | User renames a document on a site. |
Uploaded file | FileUploaded | User uploads a document to a folder on a site. |
Sample KQL query that retrieves file-related events only:
OfficeActivity| where OfficeWorkload in ("OneDrive", "SharePoint") and Operation in ("FileAccessed", "FileCopied", "FileDeleted", "FileDeletedFirstStageRecycleBin", "FileDeletedSecondStageRecycleBin", "FileDownloaded", "FileModified", "FileMoved","FileVersionsAllMinorsRecycled", "FileVersionsAllRecycled", "FileVersionRecycled", "FileRenamed", "FileUploaded" )
The following table describes the user sharing and access request activities in SharePoint Online and OneDrive for Business. For more information, see Use sharing auditing in the Office 365 audit log.
💡Users can be either members or guests based on the UserType property of the user object. A member is usually an employee, and a guest is usually a collaborator outside of your organization. When a user accepts a sharing invitation (and isn’t already part of your organization), a guest account is created for them in your organization’s directory. Once the guest user has an account in your directory, resources may be shared directly with them (without requiring an invitation).
Friendly name | Operation | Description |
---|---|---|
User added to secure link | AddedToSecureLink | A user was added to the list of entities who can use this secure sharing link. |
Created a company shareable link | CompanyLinkCreated | User created a company-wide link to a resource. company-wide links can only be used by members in your organization. They can’t be used by guests. |
Created an anonymous link | AnonymousLinkCreated | User created an anonymous link to a resource. Anyone with this link can access the resource without having to be authenticated. |
Created secure link | SecureLinkCreated | A secure sharing link was created to this item. |
Created sharing invitation | SharingInvitationCreated | User shared a resource in SharePoint Online or OneDrive for Business with a user who isn’t in your organization’s directory. |
Shared file, folder, or site | SharingSet | User (member or guest) shared a file, folder, or site in SharePoint or OneDrive for Business with a user in your organization’s directory. The value in the Detail column for this activity identifies the name of the user the resource was shared with and whether this user is a member or a guest. This activity is often accompanied by a second event that describes how the user was granted access to the resource; for example, adding the user to a group that has access to the resource. |
Updated an anonymous link | AnonymousLinkUpdated | User updated an anonymous link to a resource. The updated field is included in the EventData property when you export the search results. |
Updated sharing invitation | SharingInvitationUpdated | An external sharing invitation was updated. |
Used an anonymous link | AnonymousLinkUsed | An anonymous user accessed a resource by using an anonymous link. The user’s identity might be unknown, but you can get other details such as the user’s IP address. |
Used a company shareable link | CompanyLinkUsed | User accessed a resource by using a company-wide link. |
Used secure link | SecureLinkUsed | A user used a secure link. |
User added to secure link | AddedToSecureLink | A user was added to the list of entities who can use a secure sharing link. |
The following table describes how users interact with list items in SharePoint Online.
Friendly name | Operation | Description |
---|---|---|
Deleted list item | ListItemDeleted | A user deleted a SharePoint list item. |
Recycled list item | ListItemRecycled | A user moved a SharePoint list item to the Recycle Bin. |
Restored list item | ListItemRestored | A user restored a SharePoint list item from the Recycle Bin. |
Updated list item | ListItemUpdated | A user updated a SharePoint list item by modifying one or more properties. |
I recommend retaining only the most important columns to save on the data transfer and storage costs. For example:
Considering all of the above, I came up with this KQL query. It filters out all important file-related and sharing-related events:
// Files and Sharing, ALL IN ONEOfficeActivity| where OfficeWorkload in ("OneDrive", "SharePoint")| where Operation in ("FileAccessed", "FileCopied", "FileDeleted", "FileDeletedFirstStageRecycleBin","FileDeletedSecondStageRecycleBin", "FileDownloaded", "FileModified", "FileMoved","FileVersionsAllMinorsRecycled", "FileVersionsAllRecycled", "FileVersionRecycled","FileRenamed", "FileUploaded","SharingSet", "SecureLinkCreated", "SecureLinkUsed", "AddedToSecureLink", "CompanyLinkCreated","AnonymousLinkCreated", "AnonymousLinkUpdated", "SharingInvitationCreated", "SharingInvitationUpdated","CompanyLinkUsed" )| where UserId != "app@sharepoint"| where SourceFileName != "AllItems.aspx"| project TimeGenerated, DestinationFileName, Operation,UserId,ClientIP,Site_Url,SourceFileName,ItemType,TargetUserOrGroupName,TargetUserOrGroupType,OfficeObjectId,UserAgent
💡 Audit records for some SharePoint activities indicate the app@sharepoint account. I prefer filtering these out.
Finally, we want to export the logs from the custom SharePointFileActivitiesPlusSharing_CL table and push them to the Azure Blob Storage.
Navigate to Log Analytics Workspace > Data export > New export rule
Give the export rule a name. For example, SharePointFileActivitiesPlusSharing
SharePointFileActivitiesPlusSharing_CL
The exported logs are stored in the am-sharepointfileactivitiesplussharing-cl
container. In your case, the container name will be different.
The logs are stored in the .JSON files organized in the deep folder structure. For example:
Tam-sharepointfileactivitiesplussharing-cl / WorkspaceResourceId= / subscriptions / 591f62bc-9c19-472e-9039-60a78f976abb / resourcegroups / sentinel-all-in-one / providers / microsoft.operationalinsights / workspaces / sentinel-all-in-one-workspace / y=2025 / m=01 / d=20
Sample JSON log file:
{ "_BinSize": 20, "_BinStartTime": "2025-01-20T15:40:00.0000000Z", "_RuleLastModifiedTime": "2025-01-20T04:49:50.3950041Z", "_RuleName": "SharePointFileActivitiesPlusSharing", "_OriginalTimeGenerated": "2025-01-20T15:45:46.0000000Z", "Operation": "FileModified", "UserId": "denis@contoso.com", "ClientIP": "2607:fea8:879f:9a10:3184:a800:6b7f:35b1", "Site_Url": "https://contoso-my.sharepoint.com/personal/denis_contoso_com/", "SourceFileName": "Howard the Cat.one", "ItemType": "File", "OfficeObjectId": "https://contoso-my.sharepoint.com/personal/denis_contoso_com/Documents/Personal/8_Pets, Nature and - Science/Howard the Cat.one", "UserAgent": "Microsoft Office OneNote/16.0.18324.20092 (Windows/10.0; Desktop x64; en-US; Desktop app; ASUS/System Product Name)", "TimeGenerated": "2025-01-20T16:03:47.9818100Z", "TenantId": "aa230883-692c-4119-b714-29e622f39b1f", "_ItemId": "21d1504c-d748-11ef-b8e1-000d3a841abf", "_Internal_WorkspaceResourceId": "/subscriptions/591f62bc-9c19-472e-9039-60a78f976abb/resourcegroups/sentinel-all-in-one/providers/microsoft.operationalinsights/workspaces/sentinel-all-in-one-workspace", "Type": "SharePointFileActivitiesPlusSharing_CL"}{ "_BinSize": 20, "_BinStartTime": "2025-01-20T15:40:00.0000000Z", "_RuleLastModifiedTime": "2025-01-20T04:49:50.3950041Z", "_RuleName": "SharePointFileActivitiesPlusSharing", "_OriginalTimeGenerated": "2025-01-20T15:49:46.0000000Z", "Operation": "FileAccessed", "UserId": "denis@contoso.com", "ClientIP": "2607:fea8:879f:9a10:3184:a800:6b7f:35b1", "Site_Url": "https://contoso-my.sharepoint.com/personal/denis_contoso_com/", "SourceFileName": "Howard the Cat.one", "ItemType": "File", "OfficeObjectId": "https://contoso-my.sharepoint.com/personal/denis_contoso_com/Documents/Personal/8_Pets, Nature and - Science/Howard the Cat.one", "UserAgent": "Microsoft Office OneNote/16.0.18324.20092 (Windows/10.0; Desktop x64; en-US; Desktop app; ASUS/System Product Name)", "TimeGenerated": "2025-01-20T16:03:47.9818100Z", "TenantId": "aa230883-692c-4119-b714-29e622f39b1f", "_ItemId": "21d15050-d748-11ef-b8e1-000d3a841abf", "_Internal_WorkspaceResourceId": "/subscriptions/591f62bc-9c19-472e-9039-60a78f976abb/resourcegroups/sentinel-all-in-one/providers/microsoft.operationalinsights/workspaces/sentinel-all-in-one-workspace", "Type": "SharePointFileActivitiesPlusSharing_CL"}{ "_BinSize": 20, "_BinStartTime": "2025-01-20T15:40:00.0000000Z", "_RuleLastModifiedTime": "2025-01-20T04:49:50.3950041Z", "_RuleName": "SharePointFileActivitiesPlusSharing", "_OriginalTimeGenerated": "2025-01-20T15:52:20.0000000Z", "Operation": "FileModified", "UserId": "denis@contoso.com", "ClientIP": "2607:fea8:879f:9a10:3184:a800:6b7f:35b1", "Site_Url": "https://contoso-my.sharepoint.com/personal/denis_contoso_com/", "SourceFileName": "Howard the Cat.one", "ItemType": "File", "OfficeObjectId": "https://contoso-my.sharepoint.com/personal/denis_contoso_com/Documents/Personal/8_Pets, Nature and - Science/Howard the Cat.one", "UserAgent": "Microsoft Office OneNote/16.0.18324.20092 (Windows/10.0; Desktop x64; en-US; Desktop app; ASUS/System Product Name)", "TimeGenerated": "2025-01-20T16:03:47.9818100Z", "TenantId": "aa230883-692c-4119-b714-29e622f39b1f", "_ItemId": "21d15051-d748-11ef-b8e1-000d3a841abf", "_Internal_WorkspaceResourceId": "/subscriptions/591f62bc-9c19-472e-9039-60a78f976abb/resourcegroups/sentinel-all-in-one/providers/microsoft.operationalinsights/workspaces/sentinel-all-in-one-workspace", "Type": "SharePointFileActivitiesPlusSharing_CL"}
If you are still reading this, congratulations. You now know how to retain SharePoint Online Logs for an extended period.