Skip to content

Commit 2bbc55d

Browse files
authored
Merge pull request #970 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents f12d99d + c5a8a20 commit 2bbc55d

4 files changed

Lines changed: 175 additions & 5 deletions

File tree

Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertNewRiskyUsers.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function Get-CIPPAlertNewRiskyUsers {
2222
$RiskyUsersDelta = (Get-CIPPAzDataTableEntity @Deltatable -Filter $Filter).delta | ConvertFrom-Json -ErrorAction SilentlyContinue
2323

2424
# Get current risky users with more detailed information
25-
$NewDelta = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/riskyUsers' -tenantid $TenantFilter) | Select-Object userPrincipalName, riskLevel, riskState, riskDetail, riskLastUpdatedDateTime, isProcessing, history
25+
$NewDelta = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/riskyUsers?`$top=500' -tenantid $TenantFilter) | Select-Object userPrincipalName, riskLevel, riskState, riskDetail, riskLastUpdatedDateTime, isProcessing, history
2626

2727
$NewDeltatoSave = $NewDelta | ConvertTo-Json -Depth 10 -Compress -ErrorAction SilentlyContinue | Out-String
2828
$DeltaEntity = @{

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardsRun.ps1

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

1414

1515
$TenantFilter = $Request.Query.tenantFilter ?? 'allTenants'
16-
$TemplateId = $Request.Query.templateId ?? '*'
16+
$TemplateId = $Request.Query.templateId ?? $Request.Query.TemplateId ?? '*'
1717
$Table = Get-CippTable -tablename 'templates'
1818
$Filter = "PartitionKey eq 'StandardsTemplateV2'"
1919
$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | ForEach-Object {

Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefenderCompliancePolicy.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ function Invoke-CIPPStandardDefenderCompliancePolicy {
2929
{"type":"switch","name":"standards.DefenderCompliancePolicy.allowPartnerToCollectIosPersonalCertificateMetadata","label":"Collect personal certificate metadata from iOS","defaultValue":false}
3030
{"type":"switch","name":"standards.DefenderCompliancePolicy.ConnectMac","label":"Connect macOS devices to MDE","defaultValue":false}
3131
{"type":"switch","name":"standards.DefenderCompliancePolicy.macDeviceBlockedOnMissingPartnerData","label":"Block macOS if partner data unavailable","defaultValue":false}
32-
{"type":"switch","name":"standards.DefenderCompliancePolicy.ConnectWindows","label":"Connect Windows 10.0.15063+ to MDE","defaultValue":false}
32+
{"type":"switch","name":"standards.DefenderCompliancePolicy.ConnectWindows","label":"Connect Windows 10.0.15063+ to MDE (Note: enabling this forces 'Block Windows if partner data unavailable' to on)","defaultValue":false}
3333
{"type":"switch","name":"standards.DefenderCompliancePolicy.windowsMobileApplicationManagementEnabled","label":"Connect Windows (MAM)","defaultValue":false}
34-
{"type":"switch","name":"standards.DefenderCompliancePolicy.windowsDeviceBlockedOnMissingPartnerData","label":"Block Windows if partner data unavailable","defaultValue":false}
34+
{"type":"switch","name":"standards.DefenderCompliancePolicy.windowsDeviceBlockedOnMissingPartnerData","label":"Block Windows if partner data unavailable (Note: Microsoft enforces this to on when Connect Windows 10.0.15063+ to MDE is on)","defaultValue":false}
3535
{"type":"switch","name":"standards.DefenderCompliancePolicy.BlockunsupportedOS","label":"Block unsupported OS versions","defaultValue":false}
3636
{"type":"switch","name":"standards.DefenderCompliancePolicy.AllowMEMEnforceCompliance","label":"Allow MEM enforcement of compliance","defaultValue":false}
3737
IMPACT
@@ -62,7 +62,7 @@ function Invoke-CIPPStandardDefenderCompliancePolicy {
6262
allowPartnerToCollectIOSPersonalApplicationMetadata = [bool]$Settings.ConnectIosCompliance
6363
androidDeviceBlockedOnMissingPartnerData = [bool]$Settings.androidDeviceBlockedOnMissingPartnerData
6464
iosDeviceBlockedOnMissingPartnerData = [bool]$Settings.iosDeviceBlockedOnMissingPartnerData
65-
windowsDeviceBlockedOnMissingPartnerData = [bool]$Settings.windowsDeviceBlockedOnMissingPartnerData
65+
windowsDeviceBlockedOnMissingPartnerData = if ([bool]$Settings.ConnectWindows) { $true } else { [bool]$Settings.windowsDeviceBlockedOnMissingPartnerData }
6666
macDeviceBlockedOnMissingPartnerData = [bool]$Settings.macDeviceBlockedOnMissingPartnerData
6767
androidMobileApplicationManagementEnabled = [bool]$Settings.ConnectAndroidCompliance
6868
iosMobileApplicationManagementEnabled = [bool]$Settings.appSync
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
function Invoke-CIPPStandardSmartLockout {
2+
<#
3+
.FUNCTIONALITY
4+
Internal
5+
.COMPONENT
6+
(APIName) SmartLockout
7+
.SYNOPSIS
8+
(Label) Configure Entra ID Smart Lockout
9+
.DESCRIPTION
10+
(Helptext) **Requires Entra ID P1.** Configures the Entra ID Smart Lockout settings including lockout duration, lockout threshold, and on-premises integration mode.
11+
(DocsDescription) Configures the Entra ID Smart Lockout policy which protects against brute-force password attacks. Smart Lockout locks out bad actors who try to guess user passwords or use brute-force methods. It recognizes sign-ins from valid users and treats them differently from attackers. Settings include lockout duration (seconds), lockout threshold (failed attempts before lockout), and on-premises password protection mode (Audit or Enforced).
12+
.NOTES
13+
CAT
14+
Entra (AAD) Standards
15+
TAG
16+
"EIDSCAPR05"
17+
"EIDSCAPR06"
18+
ADDEDCOMPONENT
19+
{"type":"number","name":"standards.SmartLockout.LockoutDurationInSeconds","label":"Lockout Duration (seconds)","default":60,"required":true}
20+
{"type":"number","name":"standards.SmartLockout.LockoutThreshold","label":"Lockout Threshold (failed attempts)","default":10,"required":true}
21+
{"type":"switch","name":"standards.SmartLockout.EnableBannedPasswordCheckOnPremises","label":"Enable On-Premises Password Protection"}
22+
{"type":"radio","name":"standards.SmartLockout.BannedPasswordCheckOnPremisesMode","label":"On-Premises Mode","options":[{"label":"Audit","value":"Audit"},{"label":"Enforced","value":"Enforced"}]}
23+
IMPACT
24+
Medium Impact
25+
ADDEDDATE
26+
2025-05-27
27+
POWERSHELLEQUIVALENT
28+
Get-MgBetaDirectorySetting, New-MgBetaDirectorySetting, Update-MgBetaDirectorySetting
29+
RECOMMENDEDBY
30+
"CIS"
31+
REQUIREDCAPABILITIES
32+
"AAD_PREMIUM"
33+
"AAD_PREMIUM_P2"
34+
UPDATECOMMENTBLOCK
35+
Run the Tools\Update-StandardsComments.ps1 script to update this comment block
36+
.LINK
37+
https://docs.cipp.app/user-documentation/tenant/standards/alignment/templates/available-standards
38+
#>
39+
40+
param($Tenant, $Settings)
41+
42+
$TestResult = Test-CIPPStandardLicense -StandardName 'SmartLockout' -TenantFilter $Tenant -Preset Entra
43+
44+
if ($TestResult -eq $false) {
45+
return $true
46+
}
47+
48+
$PasswordRuleTemplateId = '5cf42378-d67d-4f36-ba46-e8b86229381d'
49+
50+
# Extract desired values from settings
51+
$DesiredLockoutDuration = [string]($Settings.LockoutDurationInSeconds.value ?? $Settings.LockoutDurationInSeconds ?? '60')
52+
$DesiredLockoutThreshold = [string]($Settings.LockoutThreshold.value ?? $Settings.LockoutThreshold ?? '10')
53+
$DesiredEnableOnPrem = [string]($Settings.EnableBannedPasswordCheckOnPremises.value ?? $Settings.EnableBannedPasswordCheckOnPremises ?? 'False')
54+
$DesiredOnPremMode = $Settings.BannedPasswordCheckOnPremisesMode.value ?? $Settings.BannedPasswordCheckOnPremisesMode ?? 'Audit'
55+
56+
# Normalize boolean switch to string
57+
if ($DesiredEnableOnPrem -eq $true -or $DesiredEnableOnPrem -eq 'true' -or $DesiredEnableOnPrem -eq 'True') {
58+
$DesiredEnableOnPrem = 'True'
59+
} else {
60+
$DesiredEnableOnPrem = 'False'
61+
}
62+
63+
# Get existing directory settings for password rules
64+
try {
65+
$ExistingSettings = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/settings' -tenantid $Tenant | Where-Object { $_.templateId -eq $PasswordRuleTemplateId }
66+
} catch {
67+
$ErrorMessage = Get-CippException -Exception $_
68+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to get Smart Lockout settings: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
69+
return
70+
}
71+
72+
# Extract current values
73+
if ($null -ne $ExistingSettings) {
74+
$CurrentLockoutDuration = ($ExistingSettings.values | Where-Object { $_.name -eq 'LockoutDurationInSeconds' }).value
75+
$CurrentLockoutThreshold = ($ExistingSettings.values | Where-Object { $_.name -eq 'LockoutThreshold' }).value
76+
$CurrentEnableOnPrem = ($ExistingSettings.values | Where-Object { $_.name -eq 'EnableBannedPasswordCheckOnPremises' }).value
77+
$CurrentOnPremMode = ($ExistingSettings.values | Where-Object { $_.name -eq 'BannedPasswordCheckOnPremisesMode' }).value
78+
}
79+
80+
$StateIsCorrect = $null -ne $ExistingSettings -and
81+
$CurrentLockoutDuration -eq $DesiredLockoutDuration -and
82+
$CurrentLockoutThreshold -eq $DesiredLockoutThreshold -and
83+
$CurrentEnableOnPrem -eq $DesiredEnableOnPrem -and
84+
$CurrentOnPremMode -eq $DesiredOnPremMode
85+
86+
if ($Settings.remediate -eq $true) {
87+
if ($StateIsCorrect) {
88+
Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Smart Lockout is already configured correctly.' -sev Info
89+
} else {
90+
try {
91+
if ($null -eq $ExistingSettings) {
92+
# Create new directory setting with desired values
93+
$Body = @{
94+
templateId = $PasswordRuleTemplateId
95+
values = @(
96+
@{ name = 'EnableBannedPasswordCheck'; value = 'False' }
97+
@{ name = 'BannedPasswordList'; value = '' }
98+
@{ name = 'LockoutDurationInSeconds'; value = $DesiredLockoutDuration }
99+
@{ name = 'LockoutThreshold'; value = $DesiredLockoutThreshold }
100+
@{ name = 'EnableBannedPasswordCheckOnPremises'; value = $DesiredEnableOnPrem }
101+
@{ name = 'BannedPasswordCheckOnPremisesMode'; value = $DesiredOnPremMode }
102+
)
103+
}
104+
$JsonBody = ConvertTo-Json -Depth 10 -InputObject $Body -Compress
105+
$null = New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/settings' -Type POST -Body $JsonBody
106+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Smart Lockout created: Duration=$DesiredLockoutDuration, Threshold=$DesiredLockoutThreshold, OnPrem=$DesiredEnableOnPrem, Mode=$DesiredOnPremMode" -sev Info
107+
} else {
108+
# Update existing directory setting, preserving banned password list values
109+
$CurrentBannedPasswordCheck = ($ExistingSettings.values | Where-Object { $_.name -eq 'EnableBannedPasswordCheck' }).value
110+
$CurrentBannedPasswordList = ($ExistingSettings.values | Where-Object { $_.name -eq 'BannedPasswordList' }).value
111+
112+
$Body = @{
113+
values = @(
114+
@{ name = 'EnableBannedPasswordCheck'; value = $CurrentBannedPasswordCheck }
115+
@{ name = 'BannedPasswordList'; value = $CurrentBannedPasswordList }
116+
@{ name = 'LockoutDurationInSeconds'; value = $DesiredLockoutDuration }
117+
@{ name = 'LockoutThreshold'; value = $DesiredLockoutThreshold }
118+
@{ name = 'EnableBannedPasswordCheckOnPremises'; value = $DesiredEnableOnPrem }
119+
@{ name = 'BannedPasswordCheckOnPremisesMode'; value = $DesiredOnPremMode }
120+
)
121+
}
122+
$JsonBody = ConvertTo-Json -Depth 10 -InputObject $Body -Compress
123+
$null = New-GraphPostRequest -tenantid $Tenant -Uri "https://graph.microsoft.com/beta/settings/$($ExistingSettings.id)" -Type PATCH -Body $JsonBody
124+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Smart Lockout updated: Duration=$DesiredLockoutDuration, Threshold=$DesiredLockoutThreshold, OnPrem=$DesiredEnableOnPrem, Mode=$DesiredOnPremMode" -sev Info
125+
}
126+
} catch {
127+
$ErrorMessage = Get-CippException -Exception $_
128+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to configure Smart Lockout: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
129+
}
130+
}
131+
}
132+
133+
if ($Settings.alert -eq $true) {
134+
if ($StateIsCorrect) {
135+
Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Smart Lockout is compliant.' -sev Info
136+
} else {
137+
$AlertObject = @{
138+
LockoutDurationInSeconds = $CurrentLockoutDuration ?? 'Not Configured'
139+
LockoutThreshold = $CurrentLockoutThreshold ?? 'Not Configured'
140+
EnableBannedPasswordCheckOnPremises = $CurrentEnableOnPrem ?? 'Not Configured'
141+
BannedPasswordCheckOnPremisesMode = $CurrentOnPremMode ?? 'Not Configured'
142+
DesiredLockoutDurationInSeconds = $DesiredLockoutDuration
143+
DesiredLockoutThreshold = $DesiredLockoutThreshold
144+
DesiredEnableOnPrem = $DesiredEnableOnPrem
145+
DesiredOnPremMode = $DesiredOnPremMode
146+
}
147+
Write-StandardsAlert -message 'Smart Lockout is not configured correctly' -object $AlertObject -tenant $Tenant -standardName 'SmartLockout' -standardId $Settings.standardId
148+
}
149+
}
150+
151+
if ($Settings.report -eq $true) {
152+
$CurrentValue = @{
153+
LockoutDurationInSeconds = $CurrentLockoutDuration ?? 'Not Configured'
154+
LockoutThreshold = $CurrentLockoutThreshold ?? 'Not Configured'
155+
EnableBannedPasswordCheckOnPremises = $CurrentEnableOnPrem ?? 'Not Configured'
156+
BannedPasswordCheckOnPremisesMode = $CurrentOnPremMode ?? 'Not Configured'
157+
}
158+
$ExpectedValue = @{
159+
LockoutDurationInSeconds = $DesiredLockoutDuration
160+
LockoutThreshold = $DesiredLockoutThreshold
161+
EnableBannedPasswordCheckOnPremises = $DesiredEnableOnPrem
162+
BannedPasswordCheckOnPremisesMode = $DesiredOnPremMode
163+
}
164+
165+
Set-CIPPStandardsCompareField -FieldName 'standards.SmartLockout' `
166+
-CurrentValue $CurrentValue -ExpectedValue $ExpectedValue -TenantFilter $Tenant
167+
168+
Add-CIPPBPAField -FieldName 'SmartLockout' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant
169+
}
170+
}

0 commit comments

Comments
 (0)