|
| 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