Skip to content

Commit 23910f6

Browse files
authored
Merge pull request #61 from KelvinTegelaar/master
[pull] master from KelvinTegelaar:master
2 parents cb5c3d8 + a352c4c commit 23910f6

29 files changed

+547
-298
lines changed

Diff for: CIPPTimers.json

+8
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,13 @@
142142
"Priority": 15,
143143
"RunOnProcessor": true,
144144
"IsSystem": true
145+
},
146+
{
147+
"Command": "Start-TableCleanup",
148+
"Description": "Timer to cleanup tables",
149+
"Cron": "0 0 23 * * *",
150+
"Priority": 20,
151+
"RunOnProcessor": true,
152+
"IsSystem": true
145153
}
146154
]

Diff for: Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function Add-CIPPScheduledTask {
2121
$Parameters = [System.Collections.Hashtable]@{}
2222
foreach ($Key in $task.Parameters.PSObject.Properties.Name) {
2323
$Param = $task.Parameters.$Key
24-
if ($Param -is [System.Collections.IDictionary]) {
24+
if ($Param -is [System.Collections.IDictionary] -or $Param.Key) {
2525
$ht = @{}
2626
foreach ($p in $Param.GetEnumerator()) {
2727
$ht[$p.Key] = $p.Value

Diff for: Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearchResults.ps1

+13-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,21 @@ function Get-CippAuditLogSearchResults {
1414
[string]$TenantFilter,
1515
[Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)]
1616
[Alias('id')]
17-
[string]$QueryId
17+
[string]$QueryId,
18+
[switch]$CountOnly
1819
)
1920

2021
process {
21-
New-GraphGetRequest -uri ('https://graph.microsoft.com/beta/security/auditLog/queries/{0}/records?$top=999' -f $QueryId) -AsApp $true -tenantid $TenantFilter -ErrorAction Stop
22+
$GraphRequest = @{
23+
Uri = ('https://graph.microsoft.com/beta/security/auditLog/queries/{0}/records?$top=999&$count=true' -f $QueryId)
24+
Method = 'GET'
25+
AsApp = $true
26+
tenantid = $TenantFilter
27+
}
28+
if ($CountOnly.IsPresent) {
29+
$GraphRequest.CountOnly = $true
30+
}
31+
32+
New-GraphGetRequest @GraphRequest -ErrorAction Stop
2233
}
2334
}

Diff for: Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ function Push-DomainAnalyserTenant {
2727
'*.excl.cloud'
2828
'*.codetwo.online'
2929
'*.call2teams.com'
30-
'*signature365.net'
30+
'*.signature365.net'
31+
'*.myteamsconnect.io'
32+
'*.teams.dstny.com'
3133
)
3234
$Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $Tenant.customerId | Where-Object { $_.isVerified -eq $true } | ForEach-Object {
3335
$Domain = $_

Diff for: Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1

+7-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ function Push-AuditLogTenant {
3232
# Get webhook rules
3333
$ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable
3434
$LogSearchesTable = Get-CippTable -TableName 'AuditLogSearches'
35-
35+
Write-Information ("Audit: Memory usage before processing $([System.GC]::GetTotalMemory($false))")
36+
$SearchCount = 0
3637
$Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') }
3738
if ($Configuration) {
3839
try {
@@ -88,12 +89,17 @@ function Push-AuditLogTenant {
8889
}
8990
}
9091
}
92+
$SearchCount++
93+
Write-Information "Audit: Memory usage after processing $SearchCount searches: $([System.GC]::GetTotalMemory($false))"
9194
}
9295
} catch {
9396
Write-Information ( 'Audit Log search: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message)
9497
}
9598
}
9699
} catch {
97100
Write-Information ( 'Push-AuditLogTenant: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message)
101+
} finally {
102+
Write-Information "Audit Logs: Completed processing $($TenantFilter)"
103+
Write-Information "Audit Logs: Memory usage after processing $([System.GC]::GetTotalMemory($false))"
98104
}
99105
}

Diff for: Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Function Invoke-ExecRestoreBackup {
1313
$APIName = $TriggerMetadata.FunctionName
1414
Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug'
1515
try {
16-
foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag)) {
16+
foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag, Timestamp)) {
1717
Write-Host ($line)
1818
$Table = Get-CippTable -tablename $line.table
1919
$ht2 = @{}

Diff for: Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1

+13-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,19 @@ Function Invoke-ExecDeviceAction {
2020
if ($Request.Query.Action -eq 'setDeviceName') {
2121
$ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress
2222
}
23-
$ActionResult = New-CIPPDeviceAction -Action $Request.Query.Action -ActionBody $ActionBody -DeviceFilter $Request.Query.GUID -TenantFilter $Request.Query.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' -APINAME $APINAME
23+
else {
24+
$ActionBody = $Request.Body | ConvertTo-Json -Compress
25+
}
26+
27+
$cmdparams = @{
28+
Action = $Request.Query.Action
29+
ActionBody = $ActionBody
30+
DeviceFilter = $Request.Query.GUID
31+
TenantFilter = $Request.Query.TenantFilter
32+
ExecutingUser = $request.headers.'x-ms-client-principal'
33+
APINAME = $APINAME
34+
}
35+
$ActionResult = New-CIPPDeviceAction @cmdparams
2436
$body = [pscustomobject]@{'Results' = "$ActionResult" }
2537

2638
} catch {

Diff for: Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1

-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ Function Invoke-AddGroup {
6868
}
6969
$GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params
7070
}
71-
$GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params
7271
# At some point add logic to use AddOwner/AddMember for New-DistributionGroup, but idk how we're going to brr that - rvdwegen
7372
}
7473
"Successfully created group $($groupobj.displayname) for $($tenant)"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using namespace System.Net
2+
3+
function Invoke-ListPerUserMFA {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Identity.User.Read
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $TriggerMetadata.FunctionName
14+
$User = $request.headers.'x-ms-client-principal'
15+
Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug'
16+
17+
# Write to the Azure Functions log stream.
18+
Write-Host 'PowerShell HTTP trigger function processed a request.'
19+
20+
# Parse query parameters
21+
$Tenant = $Request.query.tenantFilter
22+
try {
23+
$AllUsers = [System.Convert]::ToBoolean($Request.query.allUsers)
24+
} catch {
25+
$AllUsers = $false
26+
}
27+
$UserId = $Request.query.userId
28+
29+
# Get the MFA state for the user/all users
30+
try {
31+
if ($AllUsers -eq $true) {
32+
$Results = Get-CIPPPerUserMFA -TenantFilter $Tenant -AllUsers $true
33+
} else {
34+
$Results = Get-CIPPPerUserMFA -TenantFilter $Tenant -userId $UserId
35+
}
36+
$StatusCode = [HttpStatusCode]::OK
37+
} catch {
38+
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
39+
$Results = "Failed to get MFA State for $UserId : $ErrorMessage"
40+
$StatusCode = [HttpStatusCode]::Forbidden
41+
}
42+
43+
# Associate values to output bindings by calling 'Push-OutputBinding'.
44+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
45+
StatusCode = $StatusCode
46+
Body = @($Results)
47+
})
48+
49+
50+
}

Diff for: Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1

+3-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ function Invoke-PublicWebhooks {
6565
}
6666
Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity
6767
} else {
68-
return 'Not replying to this webhook or processing it'
68+
$Body = 'This webhook is not authorized.'
69+
$StatusCode = [HttpStatusCode]::Forbidden
6970
}
7071
$Body = 'Webhook Recieved'
7172
$StatusCode = [HttpStatusCode]::OK
@@ -80,4 +81,4 @@ function Invoke-PublicWebhooks {
8081
StatusCode = $StatusCode
8182
Body = $Body
8283
})
83-
}
84+
}

Diff for: Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1

+17-9
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,28 @@ function Start-AuditLogOrchestrator {
77
param()
88
try {
99
$AuditLogSearchesTable = Get-CIPPTable -TableName 'AuditLogSearches'
10-
$AuditLogSearches = Get-CIPPAzDataTableEntity @AuditLogSearchesTable -Filter "CippStatus eq 'Pending'"
10+
$15MinutesAgo = (Get-Date).AddMinutes(-15).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
11+
$1DayAgo = (Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
12+
$AuditLogSearches = Get-CIPPAzDataTableEntity @AuditLogSearchesTable -Filter "(CippStatus eq 'Pending' or (CippStatus eq 'Processing' and Timestamp le datetime'$15MinutesAgo')) and Timestamp ge datetime'$1DayAgo'" -Property PartitionKey, RowKey, Tenant, CippStatus, Timestamp
13+
14+
$WebhookRulesTable = Get-CIPPTable -TableName 'WebhookRules'
15+
$WebhookRules = Get-CIPPAzDataTableEntity @WebhookRulesTable
1116

1217
if (($AuditLogSearches | Measure-Object).Count -eq 0) {
1318
Write-Information 'No audit log searches available'
19+
} elseif (($WebhookRules | Measure-Object).Count -eq 0) {
20+
Write-Information 'No webhook rules defined'
1421
} else {
15-
$Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($AuditLogSearches).Count
16-
$Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } }
17-
18-
$InputObject = [PSCustomObject]@{
19-
OrchestratorName = 'AuditLogs'
20-
Batch = @($Batch)
21-
SkipLog = $true
22-
}
22+
Write-Information "Audit Logs: Processing $($AuditLogSearches.Count) searches"
2323
if ($PSCmdlet.ShouldProcess('Start-AuditLogOrchestrator', 'Starting Audit Log Polling')) {
24+
$Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($AuditLogSearches).Count
25+
$Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } }
26+
27+
$InputObject = [PSCustomObject]@{
28+
OrchestratorName = 'AuditLogs'
29+
Batch = @($Batch)
30+
SkipLog = $true
31+
}
2432
Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress)
2533
}
2634
}

Diff for: Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UserTasksOrchestrator.ps1

+8-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function Start-UserTasksOrchestrator {
1616
$currentUnixTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds
1717
if ($currentUnixTime -ge $task.ScheduledTime) {
1818
try {
19-
$null = Update-AzDataTableEntity @Table -Entity @{
19+
$null = Update-AzDataTableEntity -Force @Table -Entity @{
2020
PartitionKey = $task.PartitionKey
2121
RowKey = $task.RowKey
2222
ExecutedTime = "$currentUnixTime"
@@ -36,7 +36,9 @@ function Start-UserTasksOrchestrator {
3636
if ($task.Tenant -eq 'AllTenants') {
3737
$AllTenantCommands = foreach ($Tenant in $TenantList) {
3838
$NewParams = $task.Parameters.Clone()
39-
$NewParams.TenantFilter = $Tenant.defaultDomainName
39+
if ((Get-Command $task.Command).Parameters.TenantFilter) {
40+
$NewParams.TenantFilter = $Tenant.defaultDomainName
41+
}
4042
[pscustomobject]@{
4143
Command = $task.Command
4244
Parameters = $NewParams
@@ -46,13 +48,15 @@ function Start-UserTasksOrchestrator {
4648
}
4749
$Batch.AddRange($AllTenantCommands)
4850
} else {
49-
$ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant
51+
if ((Get-Command $task.Command).Parameters.TenantFilter) {
52+
$ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant
53+
}
5054
$Batch.Add($ScheduledCommand)
5155
}
5256
} catch {
5357
$errorMessage = $_.Exception.Message
5458

55-
$null = Update-AzDataTableEntity @Table -Entity @{
59+
$null = Update-AzDataTableEntity -Force @Table -Entity @{
5660
PartitionKey = $task.PartitionKey
5761
RowKey = $task.RowKey
5862
Results = "$errorMessage"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
function Start-TableCleanup {
2+
<#
3+
.SYNOPSIS
4+
Start the Table Cleanup Timer
5+
#>
6+
[CmdletBinding(SupportsShouldProcess = $true)]
7+
param()
8+
9+
$CleanupRules = @(
10+
@{
11+
DataTableProps = @{
12+
Context = (Get-CIPPTable -tablename 'webhookTable').Context
13+
Property = @('PartitionKey', 'RowKey', 'ETag', 'Resource')
14+
}
15+
Where = "`$_.Resource -match '^Audit'"
16+
}
17+
@{
18+
DataTableProps = @{
19+
Context = (Get-CIPPTable -tablename 'AuditLogSearches').Context
20+
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
21+
First = 10000
22+
Property = @('PartitionKey', 'RowKey', 'ETag')
23+
}
24+
}
25+
@{
26+
DataTableProps = @{
27+
Context = (Get-CIPPTable -tablename 'CippFunctionStats').Context
28+
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
29+
First = 10000
30+
Property = @('PartitionKey', 'RowKey', 'ETag')
31+
}
32+
}
33+
@{
34+
DataTableProps = @{
35+
Context = (Get-CIPPTable -tablename 'CippQueue').Context
36+
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
37+
First = 10000
38+
Property = @('PartitionKey', 'RowKey', 'ETag')
39+
}
40+
}
41+
@{
42+
DataTableProps = @{
43+
Context = (Get-CIPPTable -tablename 'CippQueueTasks').Context
44+
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
45+
First = 10000
46+
Property = @('PartitionKey', 'RowKey', 'ETag')
47+
}
48+
}
49+
)
50+
51+
if ($PSCmdlet.ShouldProcess('Start-TableCleanup', 'Starting Table Cleanup')) {
52+
Write-Information 'Starting table cleanup'
53+
foreach ($Rule in $CleanupRules) {
54+
if ($Rule.Where) {
55+
$Where = [scriptblock]::Create($Rule.Where)
56+
} else {
57+
$Where = { $true }
58+
}
59+
$DataTableProps = $Rule.DataTableProps
60+
61+
$CleanupCompleted = $false
62+
do {
63+
$Entities = Get-AzDataTableEntity @DataTableProps | Where-Object $Where
64+
if ($Entities) {
65+
Write-Information "Removing $($Entities.Count) entities from $($Rule.DataTableProps.Context.TableName)"
66+
try {
67+
Remove-AzDataTableEntity -Context $DataTableProps.Context -Entity $Entities -Force
68+
if ($DataTableProps.First -and $Entities.Count -lt $DataTableProps.First) {
69+
$CleanupCompleted = $true
70+
}
71+
} catch {
72+
Write-LogMessage -API 'TableCleanup' -message "Failed to remove entities from $($DataTableProps.Context.TableName)" -sev Error -LogData (Get-CippException -Exception $_)
73+
$CleanupCompleted = $true
74+
}
75+
} else {
76+
$CleanupCompleted = $true
77+
}
78+
} while (!$CleanupCompleted)
79+
}
80+
Write-Information 'Table cleanup complete'
81+
}
82+
}

Diff for: Modules/CIPPCore/Public/Get-CIPPMFAState.ps1

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ function Get-CIPPMFAState {
9292
}
9393
}
9494

95-
$PerUser = if ($PerUserMFAState -eq $null) { $null } else { ($PerUserMFAState | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).PerUserMFAState }
95+
$PerUser = if ($null -eq $PerUserMFAState) { $null } else { ($PerUserMFAState | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).PerUserMFAState }
9696

97-
$MFARegUser = if (($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName).isMFARegistered -eq $null) { $false } else { ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName) }
97+
$MFARegUser = if ($null -eq ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName).isMFARegistered) { $false } else { ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName) }
9898

9999
[PSCustomObject]@{
100100
Tenant = $TenantFilter

0 commit comments

Comments
 (0)