Skip to content

Commit dbeacdf

Browse files
Merge pull request #1543 from kris6673/CustomBannedPasswordList
Feat: Add new Custom Banned Password standard
2 parents 603ec59 + af47716 commit dbeacdf

File tree

1 file changed

+238
-0
lines changed

1 file changed

+238
-0
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
function Invoke-CIPPStandardCustomBannedPasswordList {
2+
<#
3+
.FUNCTIONALITY
4+
Internal
5+
.COMPONENT
6+
(APIName) CustomBannedPasswordList
7+
.SYNOPSIS
8+
(Label) Update Entra ID Custom Banned Password List
9+
.DESCRIPTION
10+
(Helptext) Updates the Entra ID custom banned password list with organization-specific terms. Requires Entra ID P1 or P2 licenses. Enter words separated by commas or new lines. Each word must be 4-16 characters long. Maximum 1,000 words allowed.
11+
(DocsDescription) Updates the Entra ID custom banned password list with organization-specific terms that should be blocked from user passwords. This supplements the global banned password list maintained by Microsoft. The custom list is limited to 1,000 key base terms of 4-16 characters each. Entra ID will block variations and combinations of these terms in user passwords.
12+
.NOTES
13+
CAT
14+
Global Standards
15+
TAG
16+
"CIS M365 5.0 (5.2.3.2)"
17+
ADDEDCOMPONENT
18+
{"type":"textArea","name":"standards.CustomBannedPasswordList.BannedWords","label":"Banned Words List","placeholder":"Enter banned words separated by commas or new lines (4-16 characters each, max 1000 words)","required":true,"rows":10}
19+
IMPACT
20+
Medium Impact
21+
ADDEDDATE
22+
2025-06-28
23+
POWERSHELLEQUIVALENT
24+
Get-MgBetaDirectorySetting, New-MgBetaDirectorySetting, Update-MgBetaDirectorySetting
25+
RECOMMENDEDBY
26+
"CIS", "CIPP"
27+
UPDATECOMMENTBLOCK
28+
Run the Tools\Update-StandardsComments.ps1 script to update this comment block
29+
.LINK
30+
https://docs.cipp.app/user-documentation/tenant/standards/list-standards
31+
#>
32+
33+
param($Tenant, $Settings)
34+
35+
$PasswordRuleTemplateId = '5cf42378-d67d-4f36-ba46-e8b86229381d'
36+
37+
# Parse and validate banned words from input
38+
$BannedWordsInput = $Settings.BannedWords
39+
if ([string]::IsNullOrWhiteSpace($BannedWordsInput)) {
40+
Write-LogMessage -API 'Standards' -tenant $tenant -message 'CustomBannedPasswordList: No banned words provided' -sev Error
41+
return
42+
}
43+
44+
# Split input by commas, newlines, or semicolons and clean up
45+
$BannedWordsList = $BannedWordsInput -split '[,;\r\n]+' | ForEach-Object { ($_.Trim()) } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique
46+
47+
# Validate word count
48+
if ($BannedWordsList.Count -gt 1000) {
49+
Write-LogMessage -API 'Standards' -tenant $tenant -message "CustomBannedPasswordList: Too many banned words provided ($($BannedWordsList.Count)). Maximum allowed is 1000." -sev Error
50+
return
51+
}
52+
53+
# Validate word length (4-16 characters), remove duplicates and invalid words
54+
$ValidBannedWordsList = [System.Collections.Generic.List[string]]::new()
55+
$InvalidWords = [System.Collections.Generic.List[string]]::new()
56+
57+
foreach ($Word in $BannedWordsList) {
58+
if ($Word.Length -ge 4 -and $Word.Length -le 16) {
59+
$ValidBannedWordsList.Add($Word)
60+
} else {
61+
$InvalidWords.Add($Word)
62+
}
63+
}
64+
$BannedWordsList = $ValidBannedWordsList | Select-Object -Unique
65+
66+
# Alert if invalid words are found
67+
if ($InvalidWords.Count -gt 0) {
68+
Write-LogMessage -API 'Standards' -tenant $tenant -message "CustomBannedPasswordList: Invalid words found in input (must be 4-16 characters). Please remove the following words: $($InvalidWords -join ', ')" -sev Warning
69+
}
70+
71+
# Get existing directory settings for password rules
72+
try {
73+
$ExistingSettings = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/settings' -tenantid $Tenant | Where-Object { $_.templateId -eq $PasswordRuleTemplateId }
74+
} catch {
75+
$ErrorMessage = Get-CippException -Exception $_
76+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to get existing Custom Banned Password List: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
77+
return
78+
}
79+
80+
if ($Settings.remediate -eq $true) {
81+
Write-Host 'Time to remediate Custom Banned Password List'
82+
83+
if ($null -eq $ExistingSettings) {
84+
Write-Host 'No existing Custom Banned Password List found, creating new one'
85+
# Create new directory setting with default values if it doesn't exist
86+
try {
87+
$Body = @{
88+
templateId = $PasswordRuleTemplateId
89+
values = @(
90+
@{
91+
name = 'EnableBannedPasswordCheck'
92+
value = 'True'
93+
}
94+
@{
95+
name = 'BannedPasswordList'
96+
value = $BannedWordsList -join ([char]9)
97+
}
98+
@{
99+
name = 'LockoutDurationInSeconds'
100+
value = '60'
101+
}
102+
@{
103+
name = 'LockoutThreshold'
104+
value = '10'
105+
}
106+
@{
107+
name = 'EnableBannedPasswordCheckOnPremises'
108+
value = 'False'
109+
}
110+
@{
111+
name = 'BannedPasswordCheckOnPremisesMode'
112+
value = 'Audit'
113+
}
114+
)
115+
}
116+
$JsonBody = ConvertTo-Json -Depth 10 -InputObject $Body -Compress
117+
118+
$ExistingSettings = New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/settings' -Type POST -Body $JsonBody
119+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Custom Banned Password List created with $($BannedWordsList.Count) words." -sev Info
120+
} catch {
121+
$ErrorMessage = Get-CippException -Exception $_
122+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Custom Banned Password List: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
123+
}
124+
} else {
125+
Write-Host 'Existing Custom Banned Password List found, updating it'
126+
# Update existing directory setting
127+
try {
128+
# Get the current passwords and check if all the new words are already in the list
129+
$CurrentBannedWords = $ExistingSettings.values | Where-Object { $_.name -eq 'BannedPasswordList' }
130+
$CurrentBannedWords = $CurrentBannedWords.value -split ([char]9)
131+
132+
# Check if the new words are already in the list
133+
$NewBannedWords = $BannedWordsList | Where-Object { $CurrentBannedWords -notcontains $_ }
134+
if ($NewBannedWords.Count -eq 0 -and ($ExistingSettings.values | Where-Object { $_.name -eq 'EnableBannedPasswordCheck' }).value -eq 'True') {
135+
Write-Host 'No new words to add'
136+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Custom Banned Password List is already configured with $($CurrentBannedWords.Count) words." -sev Info
137+
} else {
138+
Write-Host "$($NewBannedWords.Count) new words to add"
139+
$AllBannedWords = [System.Collections.Generic.List[string]]::new()
140+
$NewBannedWords | ForEach-Object { $AllBannedWords.Add($_) }
141+
$CurrentBannedWords | ForEach-Object { $AllBannedWords.Add($_) }
142+
$AllBannedWords = $AllBannedWords | Select-Object -Unique -First 1000 | Where-Object { $_ -ne $null }
143+
144+
$Body = @{
145+
values = @(
146+
@{
147+
name = 'EnableBannedPasswordCheck'
148+
value = 'True'
149+
}
150+
@{
151+
name = 'BannedPasswordList'
152+
value = $AllBannedWords -join ([char]9)
153+
}
154+
@{
155+
name = 'LockoutDurationInSeconds'
156+
value = ($ExistingSettings.values | Where-Object { $_.name -eq 'LockoutDurationInSeconds' }).value
157+
}
158+
@{
159+
name = 'LockoutThreshold'
160+
value = ($ExistingSettings.values | Where-Object { $_.name -eq 'LockoutThreshold' }).value
161+
}
162+
@{
163+
name = 'EnableBannedPasswordCheckOnPremises'
164+
value = ($ExistingSettings.values | Where-Object { $_.name -eq 'EnableBannedPasswordCheckOnPremises' }).value
165+
}
166+
@{
167+
name = 'BannedPasswordCheckOnPremisesMode'
168+
value = ($ExistingSettings.values | Where-Object { $_.name -eq 'BannedPasswordCheckOnPremisesMode' }).value
169+
}
170+
)
171+
}
172+
173+
$JsonBody = ConvertTo-Json -Depth 10 -InputObject $Body -Compress
174+
$null = New-GraphPostRequest -tenantid $Tenant -Uri "https://graph.microsoft.com/beta/settings/$($ExistingSettings.id)" -Type PATCH -Body $JsonBody
175+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Custom Banned Password List updated with $($NewBannedWords.Count) new words." -sev Info
176+
}
177+
178+
} catch {
179+
$ErrorMessage = Get-CippException -Exception $_
180+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Custom Banned Password List: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
181+
}
182+
}
183+
}
184+
185+
if ($Settings.alert -eq $true) {
186+
if ($null -eq $ExistingSettings) {
187+
Write-StandardsAlert -message 'Custom Banned Password List is not configured' -object @{Status = 'Not Configured'; WordCount = 0 } -tenant $tenant -standardName 'CustomBannedPasswordList' -standardId $Settings.standardId
188+
Write-LogMessage -API 'Standards' -tenant $tenant -message 'Custom Banned Password List is not configured' -sev Info
189+
} else {
190+
$BannedPasswordCheckEnabled = $ExistingSettings.values | Where-Object { $_.name -eq 'EnableBannedPasswordCheck' }
191+
$CurrentBannedWords = $ExistingSettings.values | Where-Object { $_.name -eq 'BannedPasswordList' }
192+
$CurrentBannedWords = if ($CurrentBannedWords.value) { ($CurrentBannedWords.value -split ([char]9)) } else { @() }
193+
194+
# Find missing words from input
195+
$MissingInputWords = $BannedWordsList | Where-Object { $CurrentBannedWords -notcontains $_ }
196+
197+
if ($MissingInputWords.Count -gt 0) {
198+
Write-StandardsAlert -message "Custom Banned Password List is missing $($MissingInputWords.Count) input words: $($MissingInputWords -join ', ')" -object @{Status = 'Configured but Missing Input Words'; MissingWords = $MissingInputWords; Enabled = $BannedPasswordCheckEnabled.value } -tenant $tenant -standardName 'CustomBannedPasswordList' -standardId $Settings.standardId
199+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Custom Banned Password List is missing $($MissingInputWords.Count) input words: $($MissingInputWords -join ', ')" -sev Info
200+
} else {
201+
Write-LogMessage -API 'Standards' -tenant $tenant -message "Custom Banned Password List contains all input words ($($BannedWordsList.Count))." -sev Info
202+
}
203+
}
204+
}
205+
206+
if ($Settings.report -eq $true) {
207+
if ($null -eq $ExistingSettings) {
208+
$BannedPasswordState = @{
209+
Status = 'Not Configured'
210+
Enabled = $false
211+
WordCount = 0
212+
Compliant = $false
213+
MissingInputWords = $BannedWordsList
214+
}
215+
} else {
216+
$BannedPasswordCheckEnabled = $ExistingSettings.values | Where-Object { $_.name -eq 'EnableBannedPasswordCheck' }
217+
$CurrentBannedWords = $ExistingSettings.values | Where-Object { $_.name -eq 'BannedPasswordList' }
218+
$CurrentBannedWords = if ($CurrentBannedWords.value) { ($CurrentBannedWords.value -split ([char]9)) } else { @() }
219+
$CurrentWordCount = $CurrentBannedWords.Count
220+
221+
# Find missing words from input
222+
$MissingInputWords = $BannedWordsList | Where-Object { $CurrentBannedWords -notcontains $_ }
223+
224+
$BannedPasswordState = @{
225+
Status = 'Configured'
226+
Enabled = $BannedPasswordCheckEnabled.value -eq 'True'
227+
WordCount = $CurrentWordCount
228+
Compliant = ($BannedPasswordCheckEnabled.value -eq 'True' -and $MissingInputWords.Count -eq 0)
229+
MissingInputWords = $MissingInputWords
230+
}
231+
}
232+
233+
Add-CIPPBPAField -FieldName 'CustomBannedPasswordList' -FieldValue $BannedPasswordState -StoreAs json -Tenant $tenant
234+
Set-CIPPStandardsCompareField -FieldName 'standards.CustomBannedPasswordList' -FieldValue $BannedPasswordState.Compliant -Tenant $tenant
235+
}
236+
237+
238+
}

0 commit comments

Comments
 (0)