Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev to hotfix #1195

Merged
merged 36 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4272a3c
Exclude more useless domains from the DA
Nov 13, 2024
0e5b281
Merge pull request #1182 from kris6673/DA-domain-exclutions
JohnDuprey Nov 13, 2024
af64f8f
flip null comparisons
kris6673 Nov 13, 2024
ed55e69
Add Invoke-ListPerUserMFA function for retrieving MFA state per user
kris6673 Nov 13, 2024
9784888
Whoops forgot camel casing
kris6673 Nov 13, 2024
0446511
Update Invoke-PublicWebhooks.ps1
JohnDuprey Nov 13, 2024
882f06c
Merge branch 'KelvinTegelaar:dev' into dev
JohnDuprey Nov 13, 2024
62c03a6
Merge pull request #1185 from JohnDuprey/dev
JohnDuprey Nov 14, 2024
90de902
fix: Flip disable alerts
OfficialEsco Nov 14, 2024
2048073
Table cleanup
JohnDuprey Nov 14, 2024
96134a8
Merge pull request #1187 from JohnDuprey/dev
JohnDuprey Nov 14, 2024
a8ef180
fix: fix check for TAP isUsableOnce
OfficialEsco Nov 15, 2024
1c94421
fix: fix device wipe action
OfficialEsco Nov 15, 2024
25ea673
Fix duplicate graph request in group add
gigacodedev Nov 16, 2024
e593668
Added check for MDO licenses for AntiPhish/SafeLinks/SafeAttachment S…
kakaiwa Nov 18, 2024
622fc04
memory usage tracking
JohnDuprey Nov 19, 2024
49df7d0
update 'true' to $true
JohnDuprey Nov 19, 2024
6f1e309
Merge pull request #264 from KelvinTegelaar/dev
JohnDuprey Nov 19, 2024
ae5f187
Merge pull request #1191 from JohnDuprey/dev
JohnDuprey Nov 19, 2024
7e8eac1
check for tenant filter parameter
JohnDuprey Nov 20, 2024
700436f
Audit log tweaks
JohnDuprey Nov 21, 2024
711911b
better handling of no searches/rules
JohnDuprey Nov 21, 2024
f55b032
fix graph request
JohnDuprey Nov 22, 2024
51fee4f
add force to update-azdatatableentity
JohnDuprey Nov 22, 2024
2c6804d
Merge pull request #1190 from cipptesting/dev
KelvinTegelaar Dec 1, 2024
e34fd45
Merge pull request #1189 from gigacodedev/dev
KelvinTegelaar Dec 1, 2024
ea67b4c
Merge pull request #1188 from Ren-Roros-Digital/deviceaction
KelvinTegelaar Dec 1, 2024
b3ef641
Merge pull request #1186 from Ren-Roros-Digital/flipalerts
KelvinTegelaar Dec 1, 2024
6822e4b
Merge pull request #1184 from kris6673/per-user-mfa-entrypoint
KelvinTegelaar Dec 1, 2024
ff1a071
Update profile.ps1
JohnDuprey Dec 3, 2024
2bde73a
Exclude timestamp, etag from backups
JohnDuprey Dec 3, 2024
819c270
Merge pull request #265 from KelvinTegelaar/dev
JohnDuprey Dec 3, 2024
47fa612
Merge pull request #1193 from JohnDuprey/dev
JohnDuprey Dec 3, 2024
248c570
standard template fix
JohnDuprey Dec 3, 2024
a52e874
Merge pull request #1194 from JohnDuprey/dev
JohnDuprey Dec 3, 2024
440d435
Update version_latest.txt
JohnDuprey Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CIPPTimers.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,13 @@
"Priority": 15,
"RunOnProcessor": true,
"IsSystem": true
},
{
"Command": "Start-TableCleanup",
"Description": "Timer to cleanup tables",
"Cron": "0 0 23 * * *",
"Priority": 20,
"RunOnProcessor": true,
"IsSystem": true
}
]
2 changes: 1 addition & 1 deletion Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function Add-CIPPScheduledTask {
$Parameters = [System.Collections.Hashtable]@{}
foreach ($Key in $task.Parameters.PSObject.Properties.Name) {
$Param = $task.Parameters.$Key
if ($Param -is [System.Collections.IDictionary]) {
if ($Param -is [System.Collections.IDictionary] -or $Param.Key) {
$ht = @{}
foreach ($p in $Param.GetEnumerator()) {
$ht[$p.Key] = $p.Value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@ function Get-CippAuditLogSearchResults {
[string]$TenantFilter,
[Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)]
[Alias('id')]
[string]$QueryId
[string]$QueryId,
[switch]$CountOnly
)

process {
New-GraphGetRequest -uri ('https://graph.microsoft.com/beta/security/auditLog/queries/{0}/records?$top=999' -f $QueryId) -AsApp $true -tenantid $TenantFilter -ErrorAction Stop
$GraphRequest = @{
Uri = ('https://graph.microsoft.com/beta/security/auditLog/queries/{0}/records?$top=999&$count=true' -f $QueryId)
Method = 'GET'
AsApp = $true
tenantid = $TenantFilter
}
if ($CountOnly.IsPresent) {
$GraphRequest.CountOnly = $true
}

New-GraphGetRequest @GraphRequest -ErrorAction Stop
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ function Push-DomainAnalyserTenant {
'*.excl.cloud'
'*.codetwo.online'
'*.call2teams.com'
'*signature365.net'
'*.signature365.net'
'*.myteamsconnect.io'
'*.teams.dstny.com'
)
$Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $Tenant.customerId | Where-Object { $_.isVerified -eq $true } | ForEach-Object {
$Domain = $_
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ function Push-AuditLogTenant {
# Get webhook rules
$ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable
$LogSearchesTable = Get-CippTable -TableName 'AuditLogSearches'

Write-Information ("Audit: Memory usage before processing $([System.GC]::GetTotalMemory($false))")
$SearchCount = 0
$Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') }
if ($Configuration) {
try {
Expand Down Expand Up @@ -88,12 +89,17 @@ function Push-AuditLogTenant {
}
}
}
$SearchCount++
Write-Information "Audit: Memory usage after processing $SearchCount searches: $([System.GC]::GetTotalMemory($false))"
}
} catch {
Write-Information ( 'Audit Log search: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message)
}
}
} catch {
Write-Information ( 'Push-AuditLogTenant: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message)
} finally {
Write-Information "Audit Logs: Completed processing $($TenantFilter)"
Write-Information "Audit Logs: Memory usage after processing $([System.GC]::GetTotalMemory($false))"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Function Invoke-ExecRestoreBackup {
$APIName = $TriggerMetadata.FunctionName
Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug'
try {
foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag)) {
foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag, Timestamp)) {
Write-Host ($line)
$Table = Get-CippTable -tablename $line.table
$ht2 = @{}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,19 @@ Function Invoke-ExecDeviceAction {
if ($Request.Query.Action -eq 'setDeviceName') {
$ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress
}
$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
else {
$ActionBody = $Request.Body | ConvertTo-Json -Compress
}

$cmdparams = @{
Action = $Request.Query.Action
ActionBody = $ActionBody
DeviceFilter = $Request.Query.GUID
TenantFilter = $Request.Query.TenantFilter
ExecutingUser = $request.headers.'x-ms-client-principal'
APINAME = $APINAME
}
$ActionResult = New-CIPPDeviceAction @cmdparams
$body = [pscustomobject]@{'Results' = "$ActionResult" }

} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ Function Invoke-AddGroup {
}
$GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params
}
$GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params
# At some point add logic to use AddOwner/AddMember for New-DistributionGroup, but idk how we're going to brr that - rvdwegen
}
"Successfully created group $($groupobj.displayname) for $($tenant)"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using namespace System.Net

function Invoke-ListPerUserMFA {
<#
.FUNCTIONALITY
Entrypoint
.ROLE
Identity.User.Read
#>
[CmdletBinding()]
param($Request, $TriggerMetadata)

$APIName = $TriggerMetadata.FunctionName
$User = $request.headers.'x-ms-client-principal'
Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug'

# Write to the Azure Functions log stream.
Write-Host 'PowerShell HTTP trigger function processed a request.'

# Parse query parameters
$Tenant = $Request.query.tenantFilter
try {
$AllUsers = [System.Convert]::ToBoolean($Request.query.allUsers)
} catch {
$AllUsers = $false
}
$UserId = $Request.query.userId

# Get the MFA state for the user/all users
try {
if ($AllUsers -eq $true) {
$Results = Get-CIPPPerUserMFA -TenantFilter $Tenant -AllUsers $true
} else {
$Results = Get-CIPPPerUserMFA -TenantFilter $Tenant -userId $UserId
}
$StatusCode = [HttpStatusCode]::OK
} catch {
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
$Results = "Failed to get MFA State for $UserId : $ErrorMessage"
$StatusCode = [HttpStatusCode]::Forbidden
}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $StatusCode
Body = @($Results)
})


}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ function Invoke-PublicWebhooks {
}
Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity
} else {
return 'Not replying to this webhook or processing it'
$Body = 'This webhook is not authorized.'
$StatusCode = [HttpStatusCode]::Forbidden
}
$Body = 'Webhook Recieved'
$StatusCode = [HttpStatusCode]::OK
Expand All @@ -80,4 +81,4 @@ function Invoke-PublicWebhooks {
StatusCode = $StatusCode
Body = $Body
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,28 @@ function Start-AuditLogOrchestrator {
param()
try {
$AuditLogSearchesTable = Get-CIPPTable -TableName 'AuditLogSearches'
$AuditLogSearches = Get-CIPPAzDataTableEntity @AuditLogSearchesTable -Filter "CippStatus eq 'Pending'"
$15MinutesAgo = (Get-Date).AddMinutes(-15).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
$1DayAgo = (Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
$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

$WebhookRulesTable = Get-CIPPTable -TableName 'WebhookRules'
$WebhookRules = Get-CIPPAzDataTableEntity @WebhookRulesTable

if (($AuditLogSearches | Measure-Object).Count -eq 0) {
Write-Information 'No audit log searches available'
} elseif (($WebhookRules | Measure-Object).Count -eq 0) {
Write-Information 'No webhook rules defined'
} else {
$Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($AuditLogSearches).Count
$Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } }

$InputObject = [PSCustomObject]@{
OrchestratorName = 'AuditLogs'
Batch = @($Batch)
SkipLog = $true
}
Write-Information "Audit Logs: Processing $($AuditLogSearches.Count) searches"
if ($PSCmdlet.ShouldProcess('Start-AuditLogOrchestrator', 'Starting Audit Log Polling')) {
$Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($AuditLogSearches).Count
$Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } }

$InputObject = [PSCustomObject]@{
OrchestratorName = 'AuditLogs'
Batch = @($Batch)
SkipLog = $true
}
Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function Start-UserTasksOrchestrator {
$currentUnixTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds
if ($currentUnixTime -ge $task.ScheduledTime) {
try {
$null = Update-AzDataTableEntity @Table -Entity @{
$null = Update-AzDataTableEntity -Force @Table -Entity @{
PartitionKey = $task.PartitionKey
RowKey = $task.RowKey
ExecutedTime = "$currentUnixTime"
Expand All @@ -36,7 +36,9 @@ function Start-UserTasksOrchestrator {
if ($task.Tenant -eq 'AllTenants') {
$AllTenantCommands = foreach ($Tenant in $TenantList) {
$NewParams = $task.Parameters.Clone()
$NewParams.TenantFilter = $Tenant.defaultDomainName
if ((Get-Command $task.Command).Parameters.TenantFilter) {
$NewParams.TenantFilter = $Tenant.defaultDomainName
}
[pscustomobject]@{
Command = $task.Command
Parameters = $NewParams
Expand All @@ -46,13 +48,15 @@ function Start-UserTasksOrchestrator {
}
$Batch.AddRange($AllTenantCommands)
} else {
$ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant
if ((Get-Command $task.Command).Parameters.TenantFilter) {
$ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant
}
$Batch.Add($ScheduledCommand)
}
} catch {
$errorMessage = $_.Exception.Message

$null = Update-AzDataTableEntity @Table -Entity @{
$null = Update-AzDataTableEntity -Force @Table -Entity @{
PartitionKey = $task.PartitionKey
RowKey = $task.RowKey
Results = "$errorMessage"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
function Start-TableCleanup {
<#
.SYNOPSIS
Start the Table Cleanup Timer
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param()

$CleanupRules = @(
@{
DataTableProps = @{
Context = (Get-CIPPTable -tablename 'webhookTable').Context
Property = @('PartitionKey', 'RowKey', 'ETag', 'Resource')
}
Where = "`$_.Resource -match '^Audit'"
}
@{
DataTableProps = @{
Context = (Get-CIPPTable -tablename 'AuditLogSearches').Context
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
First = 10000
Property = @('PartitionKey', 'RowKey', 'ETag')
}
}
@{
DataTableProps = @{
Context = (Get-CIPPTable -tablename 'CippFunctionStats').Context
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
First = 10000
Property = @('PartitionKey', 'RowKey', 'ETag')
}
}
@{
DataTableProps = @{
Context = (Get-CIPPTable -tablename 'CippQueue').Context
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
First = 10000
Property = @('PartitionKey', 'RowKey', 'ETag')
}
}
@{
DataTableProps = @{
Context = (Get-CIPPTable -tablename 'CippQueueTasks').Context
Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'"
First = 10000
Property = @('PartitionKey', 'RowKey', 'ETag')
}
}
)

if ($PSCmdlet.ShouldProcess('Start-TableCleanup', 'Starting Table Cleanup')) {
Write-Information 'Starting table cleanup'
foreach ($Rule in $CleanupRules) {
if ($Rule.Where) {
$Where = [scriptblock]::Create($Rule.Where)
} else {
$Where = { $true }
}
$DataTableProps = $Rule.DataTableProps

$CleanupCompleted = $false
do {
$Entities = Get-AzDataTableEntity @DataTableProps | Where-Object $Where
if ($Entities) {
Write-Information "Removing $($Entities.Count) entities from $($Rule.DataTableProps.Context.TableName)"
try {
Remove-AzDataTableEntity -Context $DataTableProps.Context -Entity $Entities -Force
if ($DataTableProps.First -and $Entities.Count -lt $DataTableProps.First) {
$CleanupCompleted = $true
}
} catch {
Write-LogMessage -API 'TableCleanup' -message "Failed to remove entities from $($DataTableProps.Context.TableName)" -sev Error -LogData (Get-CippException -Exception $_)
$CleanupCompleted = $true
}
} else {
$CleanupCompleted = $true
}
} while (!$CleanupCompleted)
}
Write-Information 'Table cleanup complete'
}
}
4 changes: 2 additions & 2 deletions Modules/CIPPCore/Public/Get-CIPPMFAState.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ function Get-CIPPMFAState {
}
}

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

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

[PSCustomObject]@{
Tenant = $TenantFilter
Expand Down
Loading