Skip to content

Commit 5165123

Browse files
authored
Merge pull request #468 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents ac4f5fd + e292d25 commit 5165123

File tree

6 files changed

+421
-41
lines changed

6 files changed

+421
-41
lines changed

Config/standards.json

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3428,6 +3428,163 @@
34283428
"addedDate": "2025-04-01",
34293429
"powershellEquivalent": "Graph API",
34303430
"recommendedBy": []
3431+
},
3432+
{
3433+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration",
3434+
"cat": "Intune Standards",
3435+
"tag": [],
3436+
"helpText": "Sets the Windows Hello for Business configuration during device enrollment.",
3437+
"executiveText": "Enables or disables Windows Hello for Business during device enrollment, enhancing security through biometric or PIN-based authentication methods. This ensures that devices meet corporate security standards while providing a user-friendly sign-in experience.",
3438+
"addedComponent": [
3439+
{
3440+
"type": "autoComplete",
3441+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.state",
3442+
"label": "Configure Windows Hello for Business",
3443+
"multiple": false,
3444+
"options": [
3445+
{
3446+
"label": "Not configured",
3447+
"value": "notConfigured"
3448+
},
3449+
{
3450+
"label": "Enabled",
3451+
"value": "enabled"
3452+
},
3453+
{
3454+
"label": "Disabled",
3455+
"value": "disabled"
3456+
}
3457+
]
3458+
},
3459+
{
3460+
"type": "switch",
3461+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.securityDeviceRequired",
3462+
"label": "Use a Trusted Platform Module (TPM)",
3463+
"default": true
3464+
},
3465+
{
3466+
"type": "number",
3467+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinMinimumLength",
3468+
"label": "Minimum PIN length (4-127)",
3469+
"default": 4
3470+
},
3471+
{
3472+
"type": "number",
3473+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinMaximumLength",
3474+
"label": "Maximum PIN length (4-127)",
3475+
"default": 127
3476+
},
3477+
{
3478+
"type": "autoComplete",
3479+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinLowercaseCharactersUsage",
3480+
"label": "Lowercase letters in PIN",
3481+
"multiple": false,
3482+
"options": [
3483+
{
3484+
"label": "Not allowed",
3485+
"value": "disallowed"
3486+
},
3487+
{
3488+
"label": "Allowed",
3489+
"value": "allowed"
3490+
},
3491+
{
3492+
"label": "Required",
3493+
"value": "required"
3494+
}
3495+
]
3496+
},
3497+
{
3498+
"type": "autoComplete",
3499+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinUppercaseCharactersUsage",
3500+
"label": "Uppercase letters in PIN",
3501+
"multiple": false,
3502+
"options": [
3503+
{
3504+
"label": "Not allowed",
3505+
"value": "disallowed"
3506+
},
3507+
{
3508+
"label": "Allowed",
3509+
"value": "allowed"
3510+
},
3511+
{
3512+
"label": "Required",
3513+
"value": "required"
3514+
}
3515+
]
3516+
},
3517+
{
3518+
"type": "autoComplete",
3519+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinSpecialCharactersUsage",
3520+
"label": "Special characters in PIN",
3521+
"multiple": false,
3522+
"options": [
3523+
{
3524+
"label": "Not allowed",
3525+
"value": "disallowed"
3526+
},
3527+
{
3528+
"label": "Allowed",
3529+
"value": "allowed"
3530+
},
3531+
{
3532+
"label": "Required",
3533+
"value": "required"
3534+
}
3535+
]
3536+
},
3537+
{
3538+
"type": "number",
3539+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinExpirationInDays",
3540+
"label": "PIN expiration (days) - 0 to disable",
3541+
"default": 0
3542+
},
3543+
{
3544+
"type": "number",
3545+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.pinPreviousBlockCount",
3546+
"label": "PIN history - 0 to disable",
3547+
"default": 0
3548+
},
3549+
{
3550+
"type": "switch",
3551+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.unlockWithBiometricsEnabled",
3552+
"label": "Allow biometric authentication",
3553+
"default": true
3554+
},
3555+
{
3556+
"type": "autoComplete",
3557+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.enhancedBiometricsState",
3558+
"label": "Use enhanced anti-spoofing when available",
3559+
"multiple": false,
3560+
"options": [
3561+
{
3562+
"label": "Not configured",
3563+
"value": "notConfigured"
3564+
},
3565+
{
3566+
"label": "Enabled",
3567+
"value": "enabled"
3568+
},
3569+
{
3570+
"label": "Disabled",
3571+
"value": "disabled"
3572+
}
3573+
]
3574+
},
3575+
{
3576+
"type": "switch",
3577+
"name": "standards.EnrollmentWindowsHelloForBusinessConfiguration.remotePassportEnabled",
3578+
"label": "Allow phone sign-in",
3579+
"default": true
3580+
}
3581+
],
3582+
"label": "Windows Hello for Business enrollment configuration",
3583+
"impact": "Low Impact",
3584+
"impactColour": "info",
3585+
"addedDate": "2025-09-25",
3586+
"powershellEquivalent": "Graph API",
3587+
"recommendedBy": []
34313588
},
34323589
{
34333590
"name": "standards.intuneDeviceReg",

Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ function Get-CIPPHttpFunctions {
1111
if ($Help.Functionality -notmatch 'Entrypoint') { continue }
1212
if ($Help.Role -eq 'Public') { continue }
1313
[PSCustomObject]@{
14-
Function = $Function.Name
15-
Role = $Help.Role
14+
Function = $Function.Name
15+
Role = $Help.Role
16+
Description = $Help.Description
1617
}
1718
}
1819

1920
if ($ByRole.IsPresent -or $ByRoleGroup.IsPresent) {
20-
$Results = $Results | Group-Object -Property Role | Select-Object -Property @{l = 'Permission'; e = { $_.Name -eq '' ? 'None' : $_.Name } }, Count, @{l = 'Functions'; e = { $_.Group.Function -replace 'Invoke-' } } | Sort-Object -Property Permission
21-
21+
$Results = $Results | Group-Object -Property Role | Select-Object -Property @{l = 'Permission'; e = { $_.Name -eq '' ? 'None' : $_.Name } }, Count, @{l = 'Functions'; e = { $_.Group | Select-Object @{l='Name'; e={$_.Function -replace 'Invoke-'}}, Description } } | Sort-Object -Property Permission
2222
if ($ByRoleGroup.IsPresent) {
2323
$RoleGroup = @{}
2424
foreach ($Permission in $Results) {

Modules/CIPPCore/Public/Get-CIPPIntunePolicy.ps1

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,77 @@ function Get-CIPPIntunePolicy {
1313
switch ($TemplateType) {
1414
'AppProtection' {
1515
$PlatformType = 'deviceAppManagement'
16-
$TemplateTypeURL = 'androidManagedAppProtections'
16+
$AndroidTemplateTypeURL = 'androidManagedAppProtections'
17+
$iOSTemplateTypeURL = 'iosManagedAppProtections'
18+
19+
# Define bulk request for both platforms - used by all scenarios
20+
$BulkRequests = @(
21+
@{
22+
id = 'AndroidPolicies'
23+
url = "$PlatformType/$AndroidTemplateTypeURL"
24+
method = 'GET'
25+
},
26+
@{
27+
id = 'iOSPolicies'
28+
url = "$PlatformType/$iOSTemplateTypeURL"
29+
method = 'GET'
30+
}
31+
)
32+
$BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $tenantFilter
33+
34+
$androidPolicies = ($BulkResults | Where-Object { $_.id -eq 'AndroidPolicies' }).body.value
35+
$iOSPolicies = ($BulkResults | Where-Object { $_.id -eq 'iOSPolicies' }).body.value
1736

1837
if ($DisplayName) {
19-
$policies = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter
20-
$policy = $policies | Where-Object -Property displayName -EQ $DisplayName
21-
if ($policy) {
22-
$policyDetails = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$($policy.id)')" -tenantid $tenantFilter
23-
$policyJson = ConvertTo-Json -InputObject $policyDetails -Depth 100 -Compress
24-
$policy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
38+
$androidPolicy = $androidPolicies | Where-Object -Property displayName -EQ $DisplayName
39+
$iOSPolicy = $iOSPolicies | Where-Object -Property displayName -EQ $DisplayName
40+
41+
# Return the matching policy (Android or iOS) - using full data from bulk request
42+
if ($androidPolicy) {
43+
$policyJson = ConvertTo-Json -InputObject $androidPolicy -Depth 100 -Compress
44+
$androidPolicy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
45+
return $androidPolicy
46+
} elseif ($iOSPolicy) {
47+
$policyJson = ConvertTo-Json -InputObject $iOSPolicy -Depth 100 -Compress
48+
$iOSPolicy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
49+
return $iOSPolicy
2550
}
26-
return $policy
51+
return $null
52+
2753
} elseif ($PolicyId) {
28-
$policy = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$PolicyId')" -tenantid $tenantFilter
29-
if ($policy) {
54+
$androidPolicy = $androidPolicies | Where-Object -Property id -EQ $PolicyId
55+
$iOSPolicy = $iOSPolicies | Where-Object -Property id -EQ $PolicyId
56+
57+
# Return the matching policy - using full data from bulk request
58+
if ($androidPolicy) {
59+
$policyJson = ConvertTo-Json -InputObject $androidPolicy -Depth 100 -Compress
60+
$androidPolicy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
61+
return $androidPolicy
62+
} elseif ($iOSPolicy) {
63+
$policyJson = ConvertTo-Json -InputObject $iOSPolicy -Depth 100 -Compress
64+
$iOSPolicy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
65+
return $iOSPolicy
66+
}
67+
return $null
68+
69+
} else {
70+
# Process all Android policies
71+
foreach ($policy in $androidPolicies) {
3072
$policyJson = ConvertTo-Json -InputObject $policy -Depth 100 -Compress
3173
$policy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
3274
}
33-
return $policy
34-
} else {
35-
$policies = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter
36-
foreach ($policy in $policies) {
37-
$policyDetails = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$($policy.id)')" -tenantid $tenantFilter
38-
$policyJson = ConvertTo-Json -InputObject $policyDetails -Depth 100 -Compress
75+
76+
# Process all iOS policies
77+
foreach ($policy in $iOSPolicies) {
78+
$policyJson = ConvertTo-Json -InputObject $policy -Depth 100 -Compress
3979
$policy | Add-Member -MemberType NoteProperty -Name 'cippconfiguration' -Value $policyJson -Force
4080
}
41-
return $policies
81+
82+
# Combine and return all policies
83+
$allPolicies = [System.Collections.Generic.List[object]]::new()
84+
if ($androidPolicies) { $allPolicies.AddRange($androidPolicies) }
85+
if ($iOSPolicies) { $allPolicies.AddRange($iOSPolicies) }
86+
return $allPolicies
4287
}
4388
}
4489
'deviceCompliancePolicies' {

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,62 @@ function Invoke-CIPPStandardBranding {
3838

3939
$TenantId = Get-Tenants | Where-Object -Property defaultDomainName -EQ $Tenant
4040

41-
try {
42-
$CurrentState = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/organization/$($TenantId.customerId)/branding/localizations/0" -tenantID $Tenant -AsApp $true
43-
}
44-
catch {
45-
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
46-
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the Branding state for $Tenant. Error: $ErrorMessage" -Sev Error
47-
return
48-
}
49-
41+
$Localizations = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/organization/$($TenantId.customerId)/branding/localizations" -tenantID $Tenant -AsApp $true
5042
# Get layoutTemplateType value using null-coalescing operator
5143
$layoutTemplateType = $Settings.layoutTemplateType.value ?? $Settings.layoutTemplateType
44+
# If default localization (id "0") exists, use that to get the currentState. Otherwise we have to create it first.
45+
if ($Localizations | Where-Object { $_.id -eq '0' }) {
46+
try {
47+
$CurrentState = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/organization/$($TenantId.customerId)/branding/localizations/0" -tenantID $Tenant -AsApp $true
48+
}
49+
catch {
50+
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
51+
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the Branding state for $Tenant. Error: $ErrorMessage" -Sev Error
52+
return
53+
}
54+
}
55+
else {
56+
try {
57+
$GraphRequest = @{
58+
tenantID = $Tenant
59+
uri = "https://graph.microsoft.com/beta/organization/$($TenantId.customerId)/branding/localizations"
60+
AsApp = $true
61+
Type = 'POST'
62+
ContentType = 'application/json; charset=utf-8'
63+
Body = [pscustomobject]@{
64+
signInPageText = $Settings.signInPageText
65+
usernameHintText = $Settings.usernameHintText
66+
loginPageTextVisibilitySettings = [pscustomobject]@{
67+
hideAccountResetCredentials = $Settings.hideAccountResetCredentials
68+
}
69+
loginPageLayoutConfiguration = [pscustomobject]@{
70+
layoutTemplateType = $layoutTemplateType
71+
isHeaderShown = $Settings.isHeaderShown
72+
isFooterShown = $Settings.isFooterShown
73+
}
74+
} | ConvertTo-Json -Compress
75+
}
76+
$CurrentState = New-GraphPostRequest @GraphRequest
77+
}
78+
catch {
79+
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
80+
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not create the default Branding localization for $Tenant. Error: $ErrorMessage" -Sev Error
81+
return
82+
}
83+
}
5284

5385
$StateIsCorrect = ($CurrentState.signInPageText -eq $Settings.signInPageText) -and
54-
($CurrentState.usernameHintText -eq $Settings.usernameHintText) -and
55-
($CurrentState.loginPageTextVisibilitySettings.hideAccountResetCredentials -eq $Settings.hideAccountResetCredentials) -and
56-
($CurrentState.loginPageLayoutConfiguration.layoutTemplateType -eq $layoutTemplateType) -and
57-
($CurrentState.loginPageLayoutConfiguration.isHeaderShown -eq $Settings.isHeaderShown) -and
58-
($CurrentState.loginPageLayoutConfiguration.isFooterShown -eq $Settings.isFooterShown)
86+
($CurrentState.usernameHintText -eq $Settings.usernameHintText) -and
87+
($CurrentState.loginPageTextVisibilitySettings.hideAccountResetCredentials -eq $Settings.hideAccountResetCredentials) -and
88+
($CurrentState.loginPageLayoutConfiguration.layoutTemplateType -eq $layoutTemplateType) -and
89+
($CurrentState.loginPageLayoutConfiguration.isHeaderShown -eq $Settings.isHeaderShown) -and
90+
($CurrentState.loginPageLayoutConfiguration.isFooterShown -eq $Settings.isFooterShown)
5991

6092
If ($Settings.remediate -eq $true) {
6193
if ($StateIsCorrect -eq $true) {
6294
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Branding is already applied correctly.' -Sev Info
63-
} else {
95+
}
96+
else {
6497
try {
6598
$GraphRequest = @{
6699
tenantID = $Tenant
@@ -83,7 +116,8 @@ function Invoke-CIPPStandardBranding {
83116
}
84117
$null = New-GraphPostRequest @GraphRequest
85118
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully updated branding.' -Sev Info
86-
} catch {
119+
}
120+
catch {
87121
$ErrorMessage = Get-CippException -Exception $_
88122
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update branding. Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage
89123
}
@@ -95,7 +129,8 @@ function Invoke-CIPPStandardBranding {
95129

96130
if ($StateIsCorrect -eq $true) {
97131
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Branding is correctly set.' -Sev Info
98-
} else {
132+
}
133+
else {
99134
Write-StandardsAlert -message 'Branding is incorrectly set.' -object ($CurrentState | Select-Object -Property signInPageText, usernameHintText, loginPageTextVisibilitySettings, loginPageLayoutConfiguration) -tenant $Tenant -standardName 'Branding' -standardId $Settings.standardId
100135
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Branding is incorrectly set.' -Sev Info
101136
}

0 commit comments

Comments
 (0)