Instantly share code, notes, and snippets.
Last active
January 4, 2024 16:55
-
Star
(3)
3
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save joerodgers/f90286636829ac0c7d0e65a5624714a6 to your computer and use it in GitHub Desktop.
Example how to search the unified audit log for SharePoint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -modules "ExchangeOnlineManagement" | |
[System.Net.Http.HttpClient]::DefaultProxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials | |
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 | |
function Invoke-SharePointUnifiedAuditLogSearch | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[Parameter(Mandatory=$true)] | |
[DateTime] | |
$StartTime, | |
[Parameter(Mandatory=$true)] | |
[DateTime] | |
$EndTime, | |
[Parameter(Mandatory=$false)] | |
[int] | |
$Interval = 30, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'FileAccessed', 'FileCheckedIn', 'FileCheckedOut', 'FileCopied', 'FileDeleted', 'FileDeletedFirstStageRecycleBin', 'FileDeletedSecondStageRecycleBin', 'RecordDelete', 'DocumentSensitivityMismatchDetected','FileMalwareDetected', 'FileCheckOutDiscarded', 'FileDownloaded', 'FileModified', 'FileMoved', 'FilePreviewed', 'SearchQueryPerformed', 'FileRecycled', 'FolderRecycled', 'FileVersionsAllRecycled', 'FileVersionsAllRecycled', 'FileRenamed', 'FileRestored', 'FileUploaded', 'PageViewed', 'PageViewedExtended', 'ClientViewSignaled')] | |
[string[]] | |
$FileActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'FolderCopied', 'FolderCreated', 'FolderDeleted', 'FolderDeletedFirstStageRecycleBin', 'FolderDeletedSecondStageRecycleBin', 'FolderModified', 'FolderMoved', 'FolderRenamed', 'FolderRestored')] | |
[string[]] | |
$FolderActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'ListCreated', 'ListColumnCreated', 'ListContentTypeCreated', 'ListItemCreated', 'SiteColumnCreated', 'SiteContentTypeCreated', 'ListDeleted', 'ListColumnDeleted', 'ListContentTypeDeleted', 'ListItemDeleted', 'SiteColumnDeleted', 'SiteContentTypeDeleted', 'ListItemRecycled', 'ListRestored', 'ListItemRestored', 'ListUpdated', 'ListColumnUpdated', 'ListContentTypeUpdated', 'ListItemUpdated', 'SiteColumnUpdated', 'SiteContentTypeUpdated', 'ListItemViewed' )] | |
[string[]] | |
$ListActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'PermissionLevelAdded', 'AccessRequestAccepted', 'SharingInvitationAccepted', 'SharingInvitationBlocked', 'AccessRequestCreated', 'CompanyLinkCreated', 'AnonymousLinkCreated', 'SecureLinkCreated', 'SharingInvitationCreated', 'SecureLinkDeleted', 'AccessRequestDenied', 'CompanyLinkRemoved', 'AnonymousLinkRemoved', 'SharingSet', 'AccessRequestUpdated', 'AnonymousLinkUpdated', 'SharingInvitationUpdated', 'AnonymousLinkUsed', 'SharingRevoked', 'CompanyLinkUsed', 'SecureLinkUsed', 'AddedToSecureLink', 'RemovedFromSecureLink', 'SharingInvitationRevoked' )] | |
[string[]] | |
$SharingAndAccessRequestActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'ManagedSyncClientAllowed', 'UnmanagedSyncClientBlocked', 'FileSyncDownloadedFull', 'FileSyncDownloadedPartial', 'FileSyncUploadedFull', 'FileSyncUploadedPartial')] | |
[string[]] | |
$SynchronizationActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'SiteCollectionAdminAdded', 'AddedToGroup', 'PermissionLevelsInheritanceBroken', 'SharingInheritanceBroken', 'GroupAdded', 'GroupRemoved', 'WebRequestAccessModified', 'WebMembersCanShareModified', 'PermissionLevelModified', 'PermissionLevelRemoved', 'SiteCollectionAdminRemoved', 'RemovedFromGroup', 'SiteAdminChangeRequest', 'SharingInheritanceReset', 'GroupUpdated')] | |
[string[]] | |
$SitePermissionActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'AllowedDataLocationAdded', 'ExemptUserAgentSet', 'GeoAdminAdded', 'AllowGroupCreationSet', 'SiteGeoMoveCancelled', 'SharingPolicyChanged', 'DeviceAccessPolicyChanged', 'CustomizeExemptUsers', 'NetworkAccessPolicyChanged', 'SiteGeoMoveCompleted', 'SendToConnectionAdded', 'SiteCollectionCreated', 'HubSiteOrphanHubDeleted', 'SendToConnectionRemoved', 'SiteDeleted', 'PreviewModeEnabledSet', 'LegacyWorkflowEnabledSet', 'OfficeOnDemandSet', 'PeopleResultsScopeSet', 'NewsFeedEnabledSet', 'HubSiteJoined', 'SiteCollectionQuotaModified', 'HubSiteRegistered', 'AllowedDataLocationDeleted', 'GeoAdminDeleted', 'SiteRenamed', 'SiteGeoMoveScheduled', 'HostSiteSet', 'GeoQuotaAllocated', 'HubSiteUnjoined', 'HubSiteUnregistered')] | |
[string[]] | |
$SiteAdministrationActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'SensitivityLabelApplied', 'SensitivityLabelRemoved', 'FileSensitivityLabelApplied', 'FileSensitivityLabelChanged', 'SensitivityLabelUpdated', 'SensitivityLabelChanged', 'FileSensitivityLabelRemoved')] | |
[string[]] | |
$SensitivityLabelActivities, | |
[Parameter(Mandatory=$false)] | |
[string[]] | |
$ObjectUrl, | |
[Parameter(Mandatory=$false)] | |
[string] | |
$Path = "$PSScriptRoot\UnifiedAuditLogSearchResults_$(Get-Date -Format FileDateTime).csv" | |
) | |
begin | |
{ | |
$totalRows = 0 | |
$intervalStart = $StartTime | |
$operations = @() | |
$objectIds = @() | |
if( $PSBoundParameters.ContainsKey( 'FileActivities' ) ) | |
{ | |
if( $FileActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.FileActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $FileActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'FolderActivities' ) ) | |
{ | |
if( $FolderActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.FolderActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $FolderActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'ListActivities' ) ) | |
{ | |
if( $ListActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.ListActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $ListActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SharingAndAccessRequestActivities' ) ) | |
{ | |
if( $SharingAndAccessRequestActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SharingAndAccessRequestActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SharingAndAccessRequestActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SynchronizationActivities' ) ) | |
{ | |
if( $SynchronizationActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SynchronizationActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SynchronizationActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SitePermissionActivities' ) ) | |
{ | |
if( $SitePermissionActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SitePermissionActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SitePermissionActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SiteAdministrationActivities' ) ) | |
{ | |
if( $SiteAdministrationActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SiteAdministrationActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SiteAdministrationActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SensitivityLabelActivities' ) ) | |
{ | |
if( $SensitivityLabelActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SensitivityLabelActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SensitivityLabelActivities | |
} | |
} | |
$operations = $operations | Where-Object -FilterScript { $_ -ne "*" } | |
if( $PSBoundParameters.ContainsKey( 'ObjectUrl' ) ) | |
{ | |
$objectIds += $ObjectUrl | |
} | |
} | |
process | |
{ | |
if( $operations.Count -eq 0 -and $objectIds.Count -eq 0 ) | |
{ | |
Write-Error "You must specify a one or more activities and/or an object URL" | |
return | |
} | |
while($true) | |
{ | |
$intervalRowCount = 0 | |
# get the next interval enddate or the supplied end date, whatever is lower (sooner) | |
$intervalEnd = [DateTime]::new( [Math]::Min($intervalStart.AddMinutes($Interval).Ticks, $EndTime.Ticks)) | |
if( $intervalStart -eq $intervalEnd ) | |
{ | |
break | |
} | |
Write-Verbose "$(Get-Date) - Executing search for time interval: $($intervalStart) - $($intervalEnd)" | |
$parameters = @{} | |
$parameters.SessionCommand = "ReturnLargeSet" | |
$parameters.ResultSize = 5000 | |
$parameters.Formatted = $true | |
$parameters.SessionId = (New-Guid).Guid | |
$parameters.StartDate = $intervalStart | |
$parameters.EndDate = $intervalEnd | |
if( $operations.Count -gt 0 ) | |
{ | |
$parameters.Operations = @($operations) | |
} | |
if( $objectIds.Count -gt 0 ) | |
{ | |
$parameters.ObjectIds = @($objectIds) | |
} | |
Write-Debug "$(Get-Date) - Parameters: $($parameters | Format-Table -AutoSize | Out-String)" | |
# executed paged search in chunks of 5k rows, up to 50k rows per search | |
do | |
{ | |
$page = Search-UnifiedAuditLog @parameters -ErrorAction Stop | |
if( $page.Count -gt 0 ) | |
{ | |
$intervalTotalRowCount = $page[0].ResultCount | |
$intervalRowCount = $page[-1].ResultIndex | |
$totalRows += $page.Count | |
Write-Verbose "$(Get-Date) - Writing $($intervalRowCount) of $($intervalTotalRowCount) results to $Path" | |
# tbd on expanding the AuditData json | |
# $rows = $page | Select-Object RecordType, CreationDate, UserIds, Operations, ResultIndex, ResultCount, @{ Name="AuditOperation"; Expression={ ($_.AuditData | ConvertFrom-Json).Operation }} | |
# export page results to csv | |
$page | Export-Csv -Path $Path -Append -NoTypeInformation | |
if ($intervalRowCount -eq $intervalTotalRowCount) | |
{ | |
break | |
} | |
} | |
} | |
while( $page.Count -gt 0 ) | |
$intervalStart = $intervalEnd | |
} | |
if( Test-Path -Path $Path -PathType Leaf ) | |
{ | |
Write-Host "$totalRows rows written to: $Path" | |
} | |
} | |
end | |
{ | |
} | |
} | |
if( (Get-PSSession | Where-Object { $_.ConfigurationName -like "Microsoft.Exchange" -and $_.Name -like "ExchangeOnlineInternalSession*" }).Count -eq 0 ) | |
{ | |
Connect-ExchangeOnline -ShowBanner:$false | |
} | |
Invoke-SharePointUnifiedAuditLogSearch ` | |
-StartTime "04/13/2022 19:00:00 PM" ` | |
-EndTime "04/13/2022 19:30:00 PM" ` | |
-SiteAdministrationActivities * ` | |
-Verbose | |
<# EXAMPLE USAGE | |
Invoke-SharePointUnifiedAuditLogSearch ` | |
-StartTime "04/13/2022 19:00:00 PM" ` | |
-EndTime "04/13/2022 19:30:00 PM" ` | |
-SiteAdministrationActivities * ` | |
-Verbose | |
Invoke-SharePointUnifiedAuditLogSearch ` | |
-StartTime "04/13/2022 19:00:00 PM" ` | |
-EndTime "04/13/2022 19:30:00 PM" ` | |
-Path "C:\_temp\AuditLogSearchResult.csv" ` | |
-Verbose | |
Invoke-SharePointUnifiedAuditLogSearch ` | |
-StartTime "03/01/2022 01:00:00" ` | |
-EndTime "04/01/2022 20:00:00" ` | |
-Interval 60 ` | |
-ObjectUrl "https://contoso.sharepoint.com/sites/teamsite" ` | |
-SitePermissionActivities * ` | |
-ListActivities * ` | |
-FileActivities * ` | |
-FolderActivities * ` | |
-Verbose | |
#> | |
#requires -modules "ExchangeOnlineManagement" | |
function Invoke-SharePointUnifiedAuditLogSearch | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[Parameter(Mandatory=$true)] | |
[DateTime] | |
$StartTime, | |
[Parameter(Mandatory=$true)] | |
[DateTime] | |
$EndTime, | |
[Parameter(Mandatory=$false)] | |
[int] | |
$Interval = 30, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'FileAccessed', 'FileCheckedIn', 'FileCheckedOut', 'FileCopied', 'FileDeleted', 'FileDeletedFirstStageRecycleBin', 'FileDeletedSecondStageRecycleBin', 'RecordDelete', 'DocumentSensitivityMismatchDetected','FileMalwareDetected', 'FileCheckOutDiscarded', 'FileDownloaded', 'FileModified', 'FileMoved', 'FilePreviewed', 'SearchQueryPerformed', 'FileRecycled', 'FolderRecycled', 'FileVersionsAllRecycled', 'FileVersionsAllRecycled', 'FileRenamed', 'FileRestored', 'FileUploaded', 'PageViewed', 'PageViewedExtended', 'ClientViewSignaled')] | |
[string[]] | |
$FileActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'FolderCopied', 'FolderCreated', 'FolderDeleted', 'FolderDeletedFirstStageRecycleBin', 'FolderDeletedSecondStageRecycleBin', 'FolderModified', 'FolderMoved', 'FolderRenamed', 'FolderRestored')] | |
[string[]] | |
$FolderActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'ListCreated', 'ListColumnCreated', 'ListContentTypeCreated', 'ListItemCreated', 'SiteColumnCreated', 'SiteContentTypeCreated', 'ListDeleted', 'ListColumnDeleted', 'ListContentTypeDeleted', 'ListItemDeleted', 'SiteColumnDeleted', 'SiteContentTypeDeleted', 'ListItemRecycled', 'ListRestored', 'ListItemRestored', 'ListUpdated', 'ListColumnUpdated', 'ListContentTypeUpdated', 'ListItemUpdated', 'SiteColumnUpdated', 'SiteContentTypeUpdated', 'ListItemViewed' )] | |
[string[]] | |
$ListActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'PermissionLevelAdded', 'AccessRequestAccepted', 'SharingInvitationAccepted', 'SharingInvitationBlocked', 'AccessRequestCreated', 'CompanyLinkCreated', 'AnonymousLinkCreated', 'SecureLinkCreated', 'SharingInvitationCreated', 'SecureLinkDeleted', 'AccessRequestDenied', 'CompanyLinkRemoved', 'AnonymousLinkRemoved', 'SharingSet', 'AccessRequestUpdated', 'AnonymousLinkUpdated', 'SharingInvitationUpdated', 'AnonymousLinkUsed', 'SharingRevoked', 'CompanyLinkUsed', 'SecureLinkUsed', 'AddedToSecureLink', 'RemovedFromSecureLink', 'SharingInvitationRevoked' )] | |
[string[]] | |
$SharingAndAccessRequestActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'ManagedSyncClientAllowed', 'UnmanagedSyncClientBlocked', 'FileSyncDownloadedFull', 'FileSyncDownloadedPartial', 'FileSyncUploadedFull', 'FileSyncUploadedPartial')] | |
[string[]] | |
$SynchronizationActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'SiteCollectionAdminAdded', 'AddedToGroup', 'PermissionLevelsInheritanceBroken', 'SharingInheritanceBroken', 'GroupAdded', 'GroupRemoved', 'WebRequestAccessModified', 'WebMembersCanShareModified', 'PermissionLevelModified', 'PermissionLevelRemoved', 'SiteCollectionAdminRemoved', 'RemovedFromGroup', 'SiteAdminChangeRequest', 'SharingInheritanceReset', 'GroupUpdated')] | |
[string[]] | |
$SitePermissionActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'AllowedDataLocationAdded', 'ExemptUserAgentSet', 'GeoAdminAdded', 'AllowGroupCreationSet', 'SiteGeoMoveCancelled', 'SharingPolicyChanged', 'DeviceAccessPolicyChanged', 'CustomizeExemptUsers', 'NetworkAccessPolicyChanged', 'SiteGeoMoveCompleted', 'SendToConnectionAdded', 'SiteCollectionCreated', 'HubSiteOrphanHubDeleted', 'SendToConnectionRemoved', 'SiteDeleted', 'PreviewModeEnabledSet', 'LegacyWorkflowEnabledSet', 'OfficeOnDemandSet', 'PeopleResultsScopeSet', 'NewsFeedEnabledSet', 'HubSiteJoined', 'SiteCollectionQuotaModified', 'HubSiteRegistered', 'AllowedDataLocationDeleted', 'GeoAdminDeleted', 'SiteRenamed', 'SiteGeoMoveScheduled', 'HostSiteSet', 'GeoQuotaAllocated', 'HubSiteUnjoined', 'HubSiteUnregistered')] | |
[string[]] | |
$SiteAdministrationActivities, | |
[Parameter(Mandatory=$false)] | |
[ValidateSet('*', 'SensitivityLabelApplied', 'SensitivityLabelRemoved', 'FileSensitivityLabelApplied', 'FileSensitivityLabelChanged', 'SensitivityLabelUpdated', 'SensitivityLabelChanged', 'FileSensitivityLabelRemoved')] | |
[string[]] | |
$SensitivityLabelActivities, | |
[Parameter(Mandatory=$false)] | |
[string[]] | |
$ObjectUrl, | |
[Parameter(Mandatory=$false)] | |
[string] | |
$Path = "$PSScriptRoot\UnifiedAuditLogSearchResults_$(Get-Date -Format FileDateTime).csv" | |
) | |
begin | |
{ | |
$totalRows = 0 | |
$intervalStart = $StartTime | |
$operations = @() | |
$objectIds = @() | |
if( $PSBoundParameters.ContainsKey( 'FileActivities' ) ) | |
{ | |
if( $FileActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.FileActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $FileActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'FolderActivities' ) ) | |
{ | |
if( $FolderActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.FolderActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $FolderActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'ListActivities' ) ) | |
{ | |
if( $ListActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.ListActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $ListActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SharingAndAccessRequestActivities' ) ) | |
{ | |
if( $SharingAndAccessRequestActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SharingAndAccessRequestActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SharingAndAccessRequestActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SynchronizationActivities' ) ) | |
{ | |
if( $SynchronizationActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SynchronizationActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SynchronizationActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SitePermissionActivities' ) ) | |
{ | |
if( $SitePermissionActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SitePermissionActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SitePermissionActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SiteAdministrationActivities' ) ) | |
{ | |
if( $SiteAdministrationActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SiteAdministrationActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SiteAdministrationActivities | |
} | |
} | |
if( $PSBoundParameters.ContainsKey( 'SensitivityLabelActivities' ) ) | |
{ | |
if( $SensitivityLabelActivities -contains "*" ) | |
{ | |
$operations += $PSCmdlet.MyInvocation.MyCommand.Parameters.SensitivityLabelActivities.Attributes.ValidValues | |
} | |
else | |
{ | |
$operations += $SensitivityLabelActivities | |
} | |
} | |
$operations = $operations | Where-Object -FilterScript { $_ -ne "*" } | |
if( $PSBoundParameters.ContainsKey( 'ObjectUrl' ) ) | |
{ | |
$objectIds += $ObjectUrl | |
} | |
} | |
process | |
{ | |
if( $operations.Count -eq 0 -and $objectIds.Count -eq 0 ) | |
{ | |
Write-Error "You must specify a one or more activities and/or an object URL" | |
return | |
} | |
while($true) | |
{ | |
$intervalRowCount = 0 | |
# get the next interval enddate or the supplied end date, whatever is lower (sooner) | |
$intervalEnd = [DateTime]::new( [Math]::Min($intervalStart.AddMinutes($Interval).Ticks, $EndTime.Ticks)) | |
if( $intervalStart -eq $intervalEnd ) | |
{ | |
break | |
} | |
Write-Verbose "$(Get-Date) - Executing search for time interval: $($intervalStart) - $($intervalEnd)" | |
$parameters = @{} | |
$parameters.SessionCommand = "ReturnLargeSet" | |
$parameters.ResultSize = 5000 | |
$parameters.Formatted = $true | |
$parameters.SessionId = (New-Guid).Guid | |
$parameters.StartDate = $intervalStart | |
$parameters.EndDate = $intervalEnd | |
if( $operations.Count -gt 0 ) | |
{ | |
$parameters.Operations = @($operations) | |
} | |
if( $objectIds.Count -gt 0 ) | |
{ | |
$parameters.ObjectIds = @($objectIds) | |
} | |
Write-Debug "$(Get-Date) - Parameters: $($parameters | Format-Table -AutoSize | Out-String)" | |
# executed paged search in chunks of 5k rows, up to 50k rows per search | |
do | |
{ | |
$page = Search-UnifiedAuditLog @parameters -ErrorAction Stop | |
if( $page.Count -gt 0 ) | |
{ | |
$intervalTotalRowCount = $page[0].ResultCount | |
$intervalRowCount = $page[-1].ResultIndex | |
$totalRows += $page.Count | |
Write-Verbose "$(Get-Date) - Writing $($intervalRowCount) of $($intervalTotalRowCount) results to $Path" | |
# tbd on expanding the AuditData json | |
# $rows = $page | Select-Object RecordType, CreationDate, UserIds, Operations, ResultIndex, ResultCount, @{ Name="AuditOperation"; Expression={ ($_.AuditData | ConvertFrom-Json).Operation }} | |
# export page results to csv | |
$page | Export-Csv -Path $Path -Append -NoTypeInformation | |
if ($intervalRowCount -eq $intervalTotalRowCount) | |
{ | |
break | |
} | |
} | |
} | |
while( $page.Count -gt 0 ) | |
$intervalStart = $intervalEnd | |
} | |
if( Test-Path -Path $Path -PathType Leaf ) | |
{ | |
Write-Host "$totalRows rows written to: $Path" | |
} | |
} | |
end | |
{ | |
} | |
} | |
<# | |
Reference: https://learn.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#set-up-app-only-authentication | |
Using app-only context requires the app prinicpal to have the follow API Permissions: | |
- Office 365 Exchange Online > Application > Exchange.ManageAsApp | |
Using app-only context requires the app prinicpal to have the follow Azure AD Role: | |
- Compliance Administrator | |
$null = Connect-IPPSSession ` | |
-AppId "4eb83e40-8d4a-4fc4-ba7e-594620e2777e" ` | |
-CertificateThumbprint $env:O365_THUMBPRINT ` | |
-Organization "$env:O365_TENANT.onmicrosoft.com" ` | |
-ErrorAction Stop | |
#> | |
if( (Get-PSSession | Where-Object { $_.ConfigurationName -like "Microsoft.Exchange" -and $_.Name -like "ExchangeOnlineInternalSession*" }).Count -eq 0 ) | |
{ | |
Connect-ExchangeOnline -ShowBanner:$false | |
} | |
$start = [DateTime]::Today.AddDays(-2) | |
$end = [DateTime]::Today.AddDays(1) | |
Invoke-SharePointUnifiedAuditLogSearch ` | |
-StartTime $start ` | |
-EndTime $end ` | |
-ObjectUrl "https://$env:O365_TENANT.sharepoint.com/sites/teamsite1" ` | |
-Verbose | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment