Skip to content

Commit 925f9ff

Browse files
authored
Merge branch 'KelvinTegelaar:master' into master
2 parents 1160fbc + e4a431e commit 925f9ff

192 files changed

Lines changed: 3846 additions & 799 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CIPPHttpTrigger/function.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
"name": "starter",
2727
"type": "durableClient",
2828
"direction": "in"
29+
},
30+
{
31+
"type": "queue",
32+
"direction": "out",
33+
"name": "QueueItem",
34+
"queueName": "cippqueue"
2935
}
3036
]
3137
}

CIPPQueueTrigger/function.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"scriptFile": "../Modules/CippEntrypoints/CippEntrypoints.psm1",
3+
"entryPoint": "Receive-CippQueueTrigger",
4+
"bindings": [
5+
{
6+
"name": "QueueItem",
7+
"type": "queueTrigger",
8+
"direction": "in",
9+
"queueName": "cippqueue"
10+
},
11+
{
12+
"name": "starter",
13+
"type": "durableClient",
14+
"direction": "in"
15+
}
16+
]
17+
}

CIPPTimers.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
"Id": "9b0c8e50-f798-49db-9a8b-dbcc0fcadeea",
7676
"Command": "Start-StandardsOrchestrator",
7777
"Description": "Orchestrator to process standards",
78-
"Cron": "0 0 */4 * * *",
78+
"Cron": "0 0 */12 * * *",
7979
"Priority": 4,
8080
"RunOnProcessor": true,
8181
"PreferredProcessor": "standards"

Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function Add-CIPPWin32LobAppContent {
138138
if ($CommitStateReq.uploadState -like '*fail*') {
139139
$errorMsg = "Commit failed. Upload state: $($CommitStateReq.uploadState)"
140140
if ($Headers) {
141-
Write-LogMessage -Headers $Headers -API $APIName -message $errorMsg -Sev 'Warning' -tenant $TenantFilter
141+
Write-LogMessage -Headers $Headers -API $APIName -message $errorMsg -sev 'Warn' -tenant $TenantFilter
142142
}
143143
throw $errorMsg
144144
}

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertGroupMembershipChange.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function Get-CIPPAlertGroupMembershipChange {
1919
$AuditLogs = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?`$filter=activityDateTime ge $OneHourAgo and (activityDisplayName eq 'Add member to group' or activityDisplayName eq 'Remove member from group')" -tenantid $TenantFilter
2020

2121
$AlertData = foreach ($Log in $AuditLogs) {
22-
$Member = ($Log.targetResources | Where-Object { $_.type -in @('User', 'ServicePrincipal') })[0]
22+
$Member = ($Log.targetResources | Where-Object { $_.type -in @('User', 'ServicePrincipal', 'Group') })[0]
2323
$GroupProp = ($Member.modifiedProperties | Where-Object { $_.displayName -eq 'Group.DisplayName' })
2424
$GroupDisplayName = (($GroupProp.newValue ?? $GroupProp.oldValue) -replace '"', '')
2525
if (!$GroupDisplayName -or !($MonitoredGroups | Where-Object { $GroupDisplayName -like $_ })) { continue }

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,63 @@ function Get-CIPPAlertMFAAdmins {
1818
}
1919
}
2020
if (!$DuoActive) {
21-
$Users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq true and isMfaRegistered eq false and userType eq 'member'&`$select=id,userDisplayName,userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) -AsApp $true |
22-
Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' }
21+
$MFAReport = try { Get-CIPPMFAStateReport -TenantFilter $TenantFilter } catch { $null }
22+
$IncludeDisabled = [System.Convert]::ToBoolean($InputValue)
2323

24-
# Filter out JIT admins if any users were found
25-
if ($Users) {
24+
# Check 1: Admins with no MFA registered — prefer cache, fall back to live Graph
25+
$Users = if ($MFAReport) {
26+
$MFAReport | Where-Object { $_.IsAdmin -eq $true -and $_.MFARegistration -eq $false -and ($IncludeDisabled -or $_.AccountEnabled -eq $true) }
27+
} else {
28+
New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq true and isMfaRegistered eq false and userType eq 'member'&`$select=id,userDisplayName,userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) -AsApp $true |
29+
Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } |
30+
Select-Object @{n = 'ID'; e = { $_.id } }, @{n = 'UPN'; e = { $_.userPrincipalName } }, @{n = 'DisplayName'; e = { $_.userDisplayName } }
31+
}
32+
33+
# Check 2: Admins with MFA registered but no enforcement.
34+
# I hate how this ended up looking, but I couldn't think of a better way to do it ¯\_(ツ)_/¯
35+
$UnenforcedAdmins = $MFAReport | Where-Object {
36+
$_.IsAdmin -eq $true -and
37+
$_.MFARegistration -eq $true -and
38+
($IncludeDisabled -or $_.AccountEnabled -eq $true) -and
39+
$_.PerUser -notin @('Enforced', 'Enabled') -and
40+
$null -ne $_.CoveredBySD -and
41+
$_.CoveredBySD -ne $true -and
42+
$_.CoveredByCA -notlike 'Enforced*'
43+
}
44+
45+
# Filter out JIT admins
46+
if ($Users -or $UnenforcedAdmins) {
2647
$Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } | Select-Object -First 1
2748
$JITAdmins = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/users?`$select=id,$($Schema.id)&`$filter=$($Schema.id)/jitAdminEnabled eq true" -tenantid $TenantFilter -ComplexFilter
2849
$JITAdminIds = $JITAdmins.id
29-
$Users = $Users | Where-Object { $_.id -notin $JITAdminIds }
50+
$Users = $Users | Where-Object { $_.ID -notin $JITAdminIds }
51+
$UnenforcedAdmins = $UnenforcedAdmins | Where-Object { $_.ID -notin $JITAdminIds }
52+
}
53+
54+
$AlertData = [System.Collections.Generic.List[PSCustomObject]]::new()
55+
56+
foreach ($user in $Users) {
57+
$AlertData.Add([PSCustomObject]@{
58+
Message = "Admin user $($user.DisplayName) ($($user.UPN)) does not have MFA registered."
59+
UserPrincipalName = $user.UPN
60+
DisplayName = $user.DisplayName
61+
Id = $user.ID
62+
Tenant = $TenantFilter
63+
})
3064
}
3165

32-
if ($Users.UserPrincipalName) {
33-
$AlertData = foreach ($user in $Users) {
34-
[PSCustomObject]@{
35-
Message = "Admin user $($user.userDisplayName) ($($user.userPrincipalName)) does not have MFA registered."
36-
UserPrincipalName = $user.userPrincipalName
37-
DisplayName = $user.userDisplayName
38-
Id = $user.id
39-
LastUpdated = $user.lastUpdatedDateTime
66+
foreach ($user in $UnenforcedAdmins) {
67+
$AlertData.Add([PSCustomObject]@{
68+
Message = "Admin user $($user.DisplayName) ($($user.UPN)) has MFA registered but no enforcement method (Per-User MFA, Security Defaults, or Conditional Access) is active."
69+
UserPrincipalName = $user.UPN
70+
DisplayName = $user.DisplayName
71+
Id = $user.ID
4072
Tenant = $TenantFilter
41-
}
42-
}
73+
})
74+
}
4375

76+
if ($AlertData.Count -gt 0) {
4477
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData
45-
4678
}
4779
} else {
4880
Write-LogMessage -message 'Potentially using Duo for MFA, could not check MFA status for Admins with 100% accuracy' -API 'MFA Alerts - Informational' -tenant $TenantFilter -sev Info

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMXRecordChanged.ps1

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ function Get-CIPPAlertMXRecordChanged {
1616
$CacheTable = Get-CippTable -tablename 'CacheMxRecords'
1717
$PreviousResults = Get-CIPPAzDataTableEntity @CacheTable -Filter "PartitionKey eq '$TenantFilter'"
1818

19+
if (!$DomainData) {
20+
return
21+
}
22+
1923
$ChangedDomains = foreach ($Domain in $DomainData) {
2024
try {
2125
$PreviousDomain = $PreviousResults | Where-Object { $_.Domain -eq $Domain.Domain }
@@ -60,8 +64,6 @@ function Get-CIPPAlertMXRecordChanged {
6064
if ($ChangedDomains) {
6165
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $ChangedDomains
6266
}
63-
return $true
64-
6567
} catch {
6668
Write-LogMessage -message "Failed to check MX record changes: $($_.Exception.Message)" -API 'MX Record Alert' -tenant $TenantFilter -sev Error
6769
}

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewMFADevice.ps1

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,30 @@ function Get-CIPPAlertNewMFADevice {
2020
$User = $Log.targetResources[0].userPrincipalName
2121
if (-not $User) { $User = $Log.initiatedBy.user.userPrincipalName }
2222

23+
$IPAddress = $Log.initiatedBy.user.ipAddress
24+
$LocationData = $null
25+
if (-not [string]::IsNullOrEmpty($IPAddress) -and $IPAddress -notmatch '[X]+') {
26+
try {
27+
$LocationData = Get-CIPPGeoIPLocation -IP $IPAddress
28+
} catch {
29+
Write-Information "Could not enrich MFA audit IP ${$IPAddress}: $($_.Exception.Message)"
30+
}
31+
}
32+
2333
[PSCustomObject]@{
24-
Message = "New MFA method registered: $User"
25-
User = $User
26-
DisplayName = $Log.targetResources[0].displayName
27-
Activity = $Log.activityDisplayName
28-
ActivityTime = $Log.activityDateTime
29-
Tenant = $TenantFilter
34+
Message = "New MFA method registered: $User"
35+
User = $User
36+
DisplayName = $Log.targetResources[0].displayName
37+
Activity = $Log.activityDisplayName
38+
ActivityTime = $Log.activityDateTime
39+
Tenant = $TenantFilter
40+
IpAddress = $IPAddress
41+
CountryOrRegion = if ($LocationData) { $LocationData.countryCode } else { $null }
42+
City = if ($LocationData) { $LocationData.city } else { $null }
43+
Proxy = if ($LocationData) { $LocationData.proxy } else { $null }
44+
Hosting = if ($LocationData) { $LocationData.hosting } else { $null }
45+
ASN = if ($LocationData) { $LocationData.asname } else { $null }
46+
GeoLocationInfo = if ($LocationData) { ($LocationData | ConvertTo-Json -Depth 10 -Compress) } else { $null }
3047
}
3148
}
3249
}

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#Add rerun protection: This Monitor can only run once every hour.
1515
$Rerun = Test-CIPPRerun -TenantFilter $TenantFilter -Type 'ExchangeMonitor' -API 'Get-CIPPAlertQuarantineReleaseRequests'
1616
if ($Rerun) {
17-
return $true
17+
return
1818
}
1919
$HasLicense = Test-CIPPStandardLicense -StandardName 'QuarantineReleaseRequests' -TenantFilter $TenantFilter -RequiredCapabilities @(
2020
'EXCHANGE_S_STANDARD',
@@ -25,7 +25,7 @@
2525
)
2626

2727
if (-not $HasLicense) {
28-
return $true
28+
return
2929
}
3030

3131
try {

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSmtpAuthSuccess.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function Get-CIPPAlertSmtpAuthSuccess {
1313

1414
try {
1515
# Graph API endpoint for sign-ins
16-
$uri = "https://graph.microsoft.com/v1.0/auditLogs/signIns?`$filter=clientAppUsed eq 'Authenticated SMTP' and status/errorCode eq 0"
16+
$uri = "https://graph.microsoft.com/v1.0/auditLogs/signIns?`$filter=(clientAppUsed eq 'Authenticated SMTP' or clientAppUsed eq 'SMTP') and status/errorCode eq 0"
1717

1818
# Call Graph API for the given tenant
1919
$SignIns = New-GraphGetRequest -uri $uri -tenantid $TenantFilter

0 commit comments

Comments
 (0)