Public/ActivityLog/Get-RMMActivityLog.ps1
|
<#
Copyright (c) 2025-2026 Robert Faddes SPDX-License-Identifier: MPL-2.0 #> function Get-RMMActivityLog { <# .SYNOPSIS Retrieves activity logs from the Datto RMM API. .DESCRIPTION Retrieves activity logs for one or more sites, with optional filtering by date range, entity type, categories, actions, and users. Supports global (all sites) or site-specific queries. Site IDs are batched for large environments to avoid API limits. You can specify sites by: - Piping DRMMSite objects (from Get-RMMSite) - Passing SiteId(s) directly - Omitting both for global (all sites) scope .PARAMETER Site A DRMMSite object to retrieve activity logs for. Accepts pipeline input from Get-RMMSite. .PARAMETER SiteId The numeric ID of a site to retrieve activity logs for. .PARAMETER Start Start date/time for fetching data. Accepts local or UTC; local times are automatically converted to UTC for the API. Format: yyyy-MM-ddTHH:mm:ssZ. Required. Defaults to 24 hours ago. .PARAMETER End End date/time for fetching data. Accepts local or UTC; local times are automatically converted to UTC for the API. Format: yyyy-MM-ddTHH:mm:ssZ. Required. Defaults to the current time. .PARAMETER Entity Filters activity logs by entity type. Valid values: 'Device', 'User'. .PARAMETER Category Filters activity logs by category (e.g., 'job', 'device'). .PARAMETER Action Filters activity logs by action (e.g., 'deployment', 'note'). .PARAMETER UserId Filters activity logs by user ID (integer). .PARAMETER Order Specifies the order in which records are returned by creation date. Valid values: 'asc', 'desc'. Default is 'desc'. .PARAMETER SearchQuery Filters activity logs using an advanced Lucene-style search expression, identical to the Activity Log UI search bar. Accepts field searches, wildcards, boolean operators, fuzzy matching, and grouped expressions. Passed through verbatim — no client-side parsing or validation is applied. See https://rmm.datto.com/help/en/Content/3NEWUI/Analytics/ActivityLog.htm for supported fields and syntax. .PARAMETER UseExperimentalDetailClasses Enables experimental entity/category-specific detail classes for activity logs. When specified, details are parsed into strongly-typed classes based on entity, category, and action combinations (e.g., DRMMActivityLogDetailsDeviceJob for DEVICE/job activities). When not specified (default), all details use the generic DRMMActivityLogDetailsGeneric class with dynamic properties. .EXAMPLE Get-RMMActivityLog -Start "2024-01-01T00:00:00Z" -End "2024-01-02T00:00:00Z" Retrieves activity logs for all sites for January 1st, 2024. .EXAMPLE $Start = Get-Date '2024-01-01T00:00:00Z' PS > $End = Get-Date '2024-01-02T00:00:00Z' PS > Get-RMMSite -SiteName "Main Office" | Get-RMMActivityLog -Start $Start -End $End Retrieves activity logs for the "Main Office" site. .EXAMPLE Get-RMMActivityLog -SiteId 1234,5678 -Start (Get-Date '2024-01-01') -End (Get-Date '2024-01-02') Retrieves activity logs for sites with IDs 1234 and 5678. .EXAMPLE Get-RMMSite | Get-RMMActivityLog Retrieves activity logs for last 24 hours for all sites. .EXAMPLE Get-RMMActivityLog -Start (Get-Date).AddDays(-7) -End (Get-Date) -SearchQuery 'data.filter_id : "filterId" AND device.hostname : "hostname"' Retrieves activity logs for the past 7 days matching a specific filter ID and hostname using a Lucene-style search expression. .INPUTS DRMMSite. You can pipe site objects from Get-RMMSite (uses the Id property). .OUTPUTS DRMMActivityLog. Returns activity log objects with details about the activity. .NOTES - Requires an active connection to the Datto RMM API (use Connect-DattoRMM first). - The API uses integer IDs (not UIDs) for sites and users in this endpoint. - Results are paginated automatically. - UserId accepts up to 750 values. This safely stays within URL length limits (750 × 7 chars ≈ 5,250 chars, well within the 6KB safe threshold). .LINK https://github.com/TheShadowTek/DattoRMM.Core/blob/main/docs/commands/ActivityLog/Get-RMMActivityLog.md .LINK Connect-DattoRMM .LINK Get-RMMSite .LINK about_DRMMActivityLog #> [CmdletBinding(DefaultParameterSetName = 'Global')] param( [Parameter( ParameterSetName = 'Site', Mandatory = $true, ValueFromPipeline = $true )] [DRMMSite] $Site, [Parameter( ParameterSetName = 'SiteId', Mandatory = $true )] [long] $SiteId, [Parameter( Mandatory = $false )] [datetime] $Start = (Get-Date).AddHours(-24), [Parameter( Mandatory = $false )] [datetime] $End = (Get-Date), [Parameter( Mandatory = $false )] [ValidateSet( 'Device', 'User' )] [string[]] $Entity, [Parameter( Mandatory = $false )] [string[]] $Category, [Parameter( Mandatory = $false )] [string[]] $Action, [Parameter( Mandatory = $false )] [ValidateCount(1, 750)] [long[]] $UserId, [Parameter( Mandatory = $false )] [ValidateSet( 'asc', 'desc' )] [string] $Order = 'desc', [Parameter( Mandatory = $false )] [string] $SearchQuery, [Parameter( Mandatory = $false )] [switch] $UseExperimentalDetailClasses ) begin { Write-Verbose "Getting activity logs with parameter set: $($PSCmdlet.ParameterSetName)" # Build query parameters with required date range $Parameters = @{ from = $Start.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') until = $End.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } # Add optional filter parameters switch ($PSBoundParameters.Keys) { 'Entity' {$Parameters['entities'] = ($Entity | ForEach-Object { $_.ToLower() }) -join ','} 'Category' {$Parameters['categories'] = ($Category | ForEach-Object { $_.ToLower() }) -join ','} 'Action' {$Parameters['actions'] = ($Action | ForEach-Object { $_.ToLower() }) -join ','} 'UserId' {$Parameters['userIds'] = $UserId -join ','} 'Order' {$Parameters['order'] = $Order} 'SearchQuery' {$Parameters['searchQuery'] = $SearchQuery} } } process { # Set siteIds parameter based on scope switch ($PSCmdlet.ParameterSetName) { 'Site' {$Parameters['siteIds'] = $Site.Id} 'SiteId' {$Parameters['siteIds'] = $SiteId} } $InvokeParams = @{ Method = 'GET' Path = 'activity-logs' Parameters = $Parameters Paginate = $true PageElement = 'activities' } Invoke-ApiMethod @InvokeParams | ForEach-Object { [DRMMActivityLog]::FromAPIMethod($_, $UseExperimentalDetailClasses.IsPresent) } } } # SIG # Begin signature block # MIIF+wYJKoZIhvcNAQcCoIIF7DCCBegCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC0LjeBftgUCLst # pE9mIiOpF8qp8q1QDMGeFBqeuIfxg6CCA04wggNKMIICMqADAgECAhB464iXHfI6 # gksEkDDTyrNsMA0GCSqGSIb3DQEBCwUAMD0xFjAUBgNVBAoMDVJvYmVydCBGYWRk # ZXMxIzAhBgNVBAMMGkRhdHRvUk1NLkNvcmUgQ29kZSBTaWduaW5nMB4XDTI2MDMz # MTAwMTMzMFoXDTI4MDMzMTAwMjMzMFowPTEWMBQGA1UECgwNUm9iZXJ0IEZhZGRl # czEjMCEGA1UEAwwaRGF0dG9STU0uQ29yZSBDb2RlIFNpZ25pbmcwggEiMA0GCSqG # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQChn1EpMYQgl1RgWzQj2+wp2mvdfb3UsaBS # nxEVGoQ0gj96tJ2MHAF7zsITdUjwaflKS1vE6wAlOg5EI1V79tJCMxzM0bFpOdR1 # L5F2HE/ovIAKNkHxFUF5qWU8vVeAsOViFQ4yhHpzLen0WLF6vhmc9eH23dLQy5fy # tELZQEc2WbQFa4HMAitP/P9kHAu6CUx5s4woLIOyyR06jkr3l9vk0sxcbCxx7+dF # RrsSLyPYPH+bUAB8+a0hs+6qCeteBuUfLvGzpMhpzKAsY82WZ3Rd9X38i32dYj+y # dYx+nx+UEMDLjDJrZgnVa8as4RojqVLcEns5yb/XTjLxDc58VatdAgMBAAGjRjBE # MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU # H+B0vf97dYXqdUX1YMcWhFsY6fcwDQYJKoZIhvcNAQELBQADggEBAJmD4EEGNmcD # 1JtFoRGxuLJaTHxDwBsjqcRQRE1VPZNGaiwIm8oSQdHVjQg0oIyK7SEb02cs6n6Y # NZbwf7B7WZJ4aKYbcoLug1k1x9SoqwBmfElECeJTKXf6dkRRNmrAodpGCixR4wMH # KXqwqP5F+5j7bdnQPiIVXuMesxc4tktz362ysph1bqKjDQSCBpwi0glEIH7bv5Ms # Ey9Gl3fe+vYC5W06d2LYVebEfm9+7766hsOgpdDVgdtnN+e6uwIJjG/6PTG6TMDP # y+pr5K6LyUVYJYcWWUTZRBqqwBHiLGekPbxrjEVfxUY32Pq4QfLzUH5hhUCAk4HN # XpF9pOzFLMUxggIDMIIB/wIBATBRMD0xFjAUBgNVBAoMDVJvYmVydCBGYWRkZXMx # IzAhBgNVBAMMGkRhdHRvUk1NLkNvcmUgQ29kZSBTaWduaW5nAhB464iXHfI6gksE # kDDTyrNsMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKEC # gAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG # CisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIDmnt54jLBV2PZE2pbRWOEPAunNM # XTJ7tDe/gmVN/E8aMA0GCSqGSIb3DQEBAQUABIIBAIFX029C4jOxceddn1Up1wSh # TYJ2p382HL+rOKOTDR4hViQRe5qU/9VIOzx1/tv9HCSDhULQXflvY35yoH+4PQvk # xXimOK52LjKYcIlNz9qoG9AjnsI0OlgPjy9g6iv6E/6nLkdex5WPoObxVVJwXyjl # JTRHFdsmD6FaYS4RxdfR2qWr40JtccIqZUIuIEaykpfKO6uqRiWu8DdjE90xXhMN # Fi0NH2JMAwkFr4sR0oHEJ5MHfVbkHVqlKrYdl7zAF1LWJbG5dOw9h2Vq8THaYwsv # GAiBY1MS+vWtJhOtpztMoFzdNffPHuoBDdEHtSZThVFFDbbH+cZt4He6HeB6PJM= # SIG # End signature block |