Skip to content

Commit 337c16e

Browse files
authored
Merge pull request #972 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 26e32a9 + 0ebb188 commit 337c16e

1 file changed

Lines changed: 246 additions & 0 deletions

File tree

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
function Invoke-CIPPStandardAutopatchGroup {
2+
<#
3+
.FUNCTIONALITY
4+
Internal
5+
.COMPONENT
6+
(APIName) AutopatchGroup
7+
.SYNOPSIS
8+
(Label) Deploy Windows Autopatch Group
9+
.DESCRIPTION
10+
(Helptext) Deploys a Windows Autopatch group with configurable deployment ring settings for quality updates, feature updates, Edge, and Office.
11+
(DocsDescription) Creates or updates a Windows Autopatch deployment group with Test and Last deployment rings. Configures quality update deferrals, feature update targeting, Edge and Office update channels per ring. Uses the Autopatch API proxy to manage the group configuration.
12+
.NOTES
13+
CAT
14+
Intune Standards
15+
TAG
16+
EXECUTIVETEXT
17+
Configures Windows Autopatch deployment groups to manage update delivery across devices. Autopatch automates Windows quality updates, feature updates, Edge, and Office updates using deployment rings with configurable deferrals and deadlines.
18+
ADDEDCOMPONENT
19+
{"type":"textField","name":"standards.AutopatchGroup.GroupName","label":"Group Name","required":true,"defaultValue":"Autopatch default group"}
20+
{"type":"select","multiple":false,"name":"standards.AutopatchGroup.TargetOSVersion","label":"Target OS Version","required":true,"options":[{"label":"Windows 11, version 24H2","value":"Windows 11, version 24H2"},{"label":"Windows 11, version 25H2","value":"Windows 11, version 25H2"}],"defaultValue":"Windows 11, version 25H2"}
21+
{"type":"switch","name":"standards.AutopatchGroup.EnableDriverUpdate","label":"Enable Driver Updates","defaultValue":true}
22+
{"type":"switch","name":"standards.AutopatchGroup.InstallWin10OnWin11Ineligible","label":"Install latest Windows 10 on Windows 11 ineligible devices","defaultValue":false}
23+
{"type":"number","name":"standards.AutopatchGroup.TestQualityDeferral","label":"Test Ring - Quality Update Deferral (days)","defaultValue":0,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
24+
{"type":"number","name":"standards.AutopatchGroup.TestQualityDeadline","label":"Test Ring - Quality Update Deadline (days)","defaultValue":1,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
25+
{"type":"number","name":"standards.AutopatchGroup.TestQualityGracePeriod","label":"Test Ring - Quality Update Grace Period (days)","defaultValue":1,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":7,"message":"Maximum value is 7"}}}
26+
{"type":"number","name":"standards.AutopatchGroup.TestFeatureDeferral","label":"Test Ring - Feature Update Deferral (days)","defaultValue":0,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":365,"message":"Maximum value is 365"}}}
27+
{"type":"number","name":"standards.AutopatchGroup.TestFeatureDeadline","label":"Test Ring - Feature Update Deadline (days)","defaultValue":5,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
28+
{"type":"select","multiple":false,"name":"standards.AutopatchGroup.TestEdgeChannel","label":"Test Ring - Edge Update Channel","options":[{"label":"Stable","value":"Stable"},{"label":"Beta","value":"Beta"},{"label":"Dev","value":"Dev"}],"defaultValue":"Beta"}
29+
{"type":"select","multiple":false,"name":"standards.AutopatchGroup.TestOfficeChannel","label":"Test Ring - Office Update Channel","options":[{"label":"Current","value":"Current"},{"label":"Monthly Enterprise","value":"MonthlyEnterprise"},{"label":"Semi-Annual Enterprise","value":"SemiAnnual"}],"defaultValue":"MonthlyEnterprise"}
30+
{"type":"number","name":"standards.AutopatchGroup.LastQualityDeferral","label":"Last Ring - Quality Update Deferral (days)","defaultValue":1,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
31+
{"type":"number","name":"standards.AutopatchGroup.LastQualityDeadline","label":"Last Ring - Quality Update Deadline (days)","defaultValue":2,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
32+
{"type":"number","name":"standards.AutopatchGroup.LastQualityGracePeriod","label":"Last Ring - Quality Update Grace Period (days)","defaultValue":2,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":7,"message":"Maximum value is 7"}}}
33+
{"type":"number","name":"standards.AutopatchGroup.LastFeatureDeferral","label":"Last Ring - Feature Update Deferral (days)","defaultValue":0,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":365,"message":"Maximum value is 365"}}}
34+
{"type":"number","name":"standards.AutopatchGroup.LastFeatureDeadline","label":"Last Ring - Feature Update Deadline (days)","defaultValue":5,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
35+
{"type":"select","multiple":false,"name":"standards.AutopatchGroup.LastEdgeChannel","label":"Last Ring - Edge Update Channel","options":[{"label":"Stable","value":"Stable"},{"label":"Beta","value":"Beta"},{"label":"Dev","value":"Dev"}],"defaultValue":"Stable"}
36+
{"type":"select","multiple":false,"name":"standards.AutopatchGroup.LastOfficeChannel","label":"Last Ring - Office Update Channel","options":[{"label":"Current","value":"Current"},{"label":"Monthly Enterprise","value":"MonthlyEnterprise"},{"label":"Semi-Annual Enterprise","value":"SemiAnnual"}],"defaultValue":"MonthlyEnterprise"}
37+
{"type":"number","name":"standards.AutopatchGroup.LastOfficeDeferral","label":"Last Ring - Office Update Deferral (days)","defaultValue":1,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
38+
{"type":"number","name":"standards.AutopatchGroup.LastOfficeDeadline","label":"Last Ring - Office Update Deadline (days)","defaultValue":2,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
39+
{"type":"number","name":"standards.AutopatchGroup.TestDnfDeferral","label":"Test Ring - Driver & Firmware Deferral (days)","defaultValue":0,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
40+
{"type":"number","name":"standards.AutopatchGroup.LastDnfDeferral","label":"Last Ring - Driver & Firmware Deferral (days)","defaultValue":1,"validators":{"min":{"value":0,"message":"Minimum value is 0"},"max":{"value":30,"message":"Maximum value is 30"}}}
41+
IMPACT
42+
Medium Impact
43+
ADDEDDATE
44+
2025-05-27
45+
POWERSHELLEQUIVALENT
46+
Autopatch API - POST /api/autoPatch
47+
RECOMMENDEDBY
48+
MULTIPLE
49+
True
50+
DISABLEDFEATURES
51+
{"report":false,"warn":false,"remediate":false}
52+
UPDATECOMMENTBLOCK
53+
Run the Tools\Update-StandardsComments.ps1 script to update this comment block
54+
.LINK
55+
https://docs.cipp.app/user-documentation/tenant/standards/alignment/templates/available-standards
56+
#>
57+
58+
param(
59+
$Tenant,
60+
$Settings
61+
)
62+
# This autoPatch proxy has been created by Microsoft to facilitate Autopatch group management until native Graph API support is available. It abstracts the underlying Graph API calls and provides a simplified interface for creating and updating Autopatch groups based on the provided settings.
63+
64+
$AutopatchProxyBase = 'https://intuneautopatchbeta-bwhtaqgefgcyaaa8.westeurope-01.azurewebsites.net/api/autoPatch'
65+
66+
# Extract settings with defaults
67+
$GroupName = $Settings.GroupName ?? 'Autopatch default group'
68+
$TargetOSVersion = $Settings.TargetOSVersion.value ?? $Settings.TargetOSVersion ?? 'Windows 11, version 25H2'
69+
$EnableDriverUpdate = if ($null -ne $Settings.EnableDriverUpdate) { [bool]$Settings.EnableDriverUpdate } else { $true }
70+
$InstallWin10OnWin11Ineligible = if ($null -ne $Settings.InstallWin10OnWin11Ineligible) { [bool]$Settings.InstallWin10OnWin11Ineligible } else { $false }
71+
72+
# Test ring settings
73+
$TestQualityDeferral = [int]($Settings.TestQualityDeferral ?? 0)
74+
$TestQualityDeadline = [int]($Settings.TestQualityDeadline ?? 1)
75+
$TestQualityGracePeriod = [int]($Settings.TestQualityGracePeriod ?? 1)
76+
$TestFeatureDeferral = [int]($Settings.TestFeatureDeferral ?? 0)
77+
$TestFeatureDeadline = [int]($Settings.TestFeatureDeadline ?? 5)
78+
$TestEdgeChannel = $Settings.TestEdgeChannel.value ?? $Settings.TestEdgeChannel ?? 'Beta'
79+
$TestOfficeChannel = $Settings.TestOfficeChannel.value ?? $Settings.TestOfficeChannel ?? 'MonthlyEnterprise'
80+
$TestDnfDeferral = [int]($Settings.TestDnfDeferral ?? 0)
81+
82+
# Last ring settings
83+
$LastQualityDeferral = [int]($Settings.LastQualityDeferral ?? 1)
84+
$LastQualityDeadline = [int]($Settings.LastQualityDeadline ?? 2)
85+
$LastQualityGracePeriod = [int]($Settings.LastQualityGracePeriod ?? 2)
86+
$LastFeatureDeferral = [int]($Settings.LastFeatureDeferral ?? 0)
87+
$LastFeatureDeadline = [int]($Settings.LastFeatureDeadline ?? 5)
88+
$LastEdgeChannel = $Settings.LastEdgeChannel.value ?? $Settings.LastEdgeChannel ?? 'Stable'
89+
$LastOfficeChannel = $Settings.LastOfficeChannel.value ?? $Settings.LastOfficeChannel ?? 'MonthlyEnterprise'
90+
$LastDnfDeferral = [int]($Settings.LastDnfDeferral ?? 1)
91+
$LastOfficeDeferral = [int]($Settings.LastOfficeDeferral ?? 1)
92+
$LastOfficeDeadline = [int]($Settings.LastOfficeDeadline ?? 2)
93+
94+
# Get current autopatch groups
95+
try {
96+
$CurrentGroups = New-GraphGetRequest -uri $AutopatchProxyBase -tenantid $Tenant -AsApp $true
97+
} catch {
98+
$ErrorMessage = Get-CippException -Exception $_
99+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not retrieve Autopatch groups: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
100+
return
101+
}
102+
103+
$ExistingGroup = if ($CurrentGroups) {
104+
@($CurrentGroups) | Where-Object { $_.name -eq $GroupName } | Select-Object -First 1
105+
}
106+
107+
# Build the autopatch group body
108+
$Body = @{
109+
name = $GroupName
110+
description = ''
111+
globalUserManagedAadGroups = @()
112+
deploymentGroups = @(
113+
@{
114+
userManagedAadGroups = @()
115+
name = "$GroupName - Test"
116+
deploymentGroupPolicySettings = @{
117+
aadGroupName = "$GroupName - Test"
118+
deviceConfigurationSetting = @{
119+
updateBehavior = 'AutoInstallAndRestart'
120+
notificationSetting = 'DefaultNotifications'
121+
qualityDeploymentSettings = @{
122+
deferral = $TestQualityDeferral
123+
deadline = $TestQualityDeadline
124+
gracePeriod = $TestQualityGracePeriod
125+
}
126+
featureDeploymentSettings = @{
127+
deferral = $TestFeatureDeferral
128+
deadline = $TestFeatureDeadline
129+
}
130+
updateFrequencyUI = $null
131+
installDays = $null
132+
installTime = $null
133+
activeHourEndTime = $null
134+
activeHourStartTime = $null
135+
}
136+
featureUpdateAnchorCloudSetting = @{
137+
targetOSVersion = $TargetOSVersion
138+
installLatestWindows10OnWindows11IneligibleDevice = $InstallWin10OnWin11Ineligible
139+
}
140+
dnfUpdateCloudSetting = @{
141+
approvalType = 'Automatic'
142+
deploymentDeferralInDays = $TestDnfDeferral
143+
}
144+
edgeDCv2Setting = @{
145+
targetChannel = $TestEdgeChannel
146+
}
147+
officeDCv2Setting = @{
148+
targetChannel = $TestOfficeChannel
149+
deferral = 0
150+
deadline = 1
151+
hideUpdateNotifications = $false
152+
enableAutomaticUpdate = $true
153+
hideEnableDisableUpdate = $true
154+
enableOfficeMgmt = $false
155+
updatePath = 'http://officecdn.microsoft.com/pr/55336b82-a18d-4dd6-b5f6-9e5095c314a6'
156+
}
157+
}
158+
}
159+
@{
160+
userManagedAadGroups = @()
161+
name = "$GroupName - Last"
162+
deploymentGroupPolicySettings = @{
163+
aadGroupName = "$GroupName - Last"
164+
deviceConfigurationSetting = @{
165+
updateBehavior = 'AutoInstallAndRestart'
166+
notificationSetting = 'DefaultNotifications'
167+
qualityDeploymentSettings = @{
168+
deferral = $LastQualityDeferral
169+
deadline = $LastQualityDeadline
170+
gracePeriod = $LastQualityGracePeriod
171+
}
172+
featureDeploymentSettings = @{
173+
deferral = $LastFeatureDeferral
174+
deadline = $LastFeatureDeadline
175+
}
176+
updateFrequencyUI = $null
177+
installDays = $null
178+
installTime = $null
179+
activeHourEndTime = $null
180+
activeHourStartTime = $null
181+
}
182+
featureUpdateAnchorCloudSetting = @{
183+
targetOSVersion = $TargetOSVersion
184+
installLatestWindows10OnWindows11IneligibleDevice = $InstallWin10OnWin11Ineligible
185+
}
186+
dnfUpdateCloudSetting = @{
187+
approvalType = 'Automatic'
188+
deploymentDeferralInDays = $LastDnfDeferral
189+
}
190+
edgeDCv2Setting = @{
191+
targetChannel = $LastEdgeChannel
192+
}
193+
officeDCv2Setting = @{
194+
targetChannel = $LastOfficeChannel
195+
deferral = $LastOfficeDeferral
196+
deadline = $LastOfficeDeadline
197+
hideUpdateNotifications = $false
198+
enableAutomaticUpdate = $true
199+
hideEnableDisableUpdate = $true
200+
enableOfficeMgmt = $false
201+
updatePath = 'http://officecdn.microsoft.com/pr/55336b82-a18d-4dd6-b5f6-9e5095c314a6'
202+
}
203+
}
204+
}
205+
)
206+
type = 'User'
207+
enableDriverUpdate = $EnableDriverUpdate
208+
scopeTags = @(0)
209+
enabledContentTypes = 31
210+
} | ConvertTo-Json -Compress -Depth 10
211+
212+
if ($Settings.remediate -eq $true) {
213+
if ($ExistingGroup) {
214+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Autopatch group '$GroupName' already exists, updating." -sev Info
215+
try {
216+
$UpdateUri = "$AutopatchProxyBase/$($ExistingGroup.id)"
217+
New-GraphPOSTRequest -uri $UpdateUri -tenantid $Tenant -body $Body -type PUT
218+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully updated Autopatch group '$GroupName'." -sev Info
219+
} catch {
220+
$ErrorMessage = Get-CippException -Exception $_
221+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Autopatch group '$GroupName': $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
222+
}
223+
} else {
224+
try {
225+
New-GraphPOSTRequest -uri $AutopatchProxyBase -tenantid $Tenant -body $Body -type POST
226+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully created Autopatch group '$GroupName'." -sev Info
227+
} catch {
228+
$ErrorMessage = Get-CippException -Exception $_
229+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Autopatch group '$GroupName': $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
230+
}
231+
}
232+
}
233+
234+
if ($Settings.alert -eq $true) {
235+
if ($ExistingGroup) {
236+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Autopatch group '$GroupName' is configured." -sev Info
237+
} else {
238+
Write-StandardsAlert -message "Autopatch group '$GroupName' is not configured." -object $GroupName `
239+
-tenant $Tenant -standardName 'AutopatchGroup' -standardId $Settings.standardId
240+
}
241+
}
242+
243+
if ($Settings.report -eq $true) {
244+
Add-CIPPBPAField -FieldName 'AutopatchGroup' -FieldValue ([bool]$ExistingGroup) -StoreAs bool -Tenant $Tenant
245+
}
246+
}

0 commit comments

Comments
 (0)