@@ -8,6 +8,7 @@ function New-CIPPCAPolicy {
88 $Overwrite ,
99 $ReplacePattern = ' none' ,
1010 $DisableSD = $false ,
11+ $CreateGroups = $false ,
1112 $APIName = ' Create CA Policy' ,
1213 $Headers
1314 )
@@ -39,7 +40,7 @@ function New-CIPPCAPolicy {
3940 }
4041 # Helper function to replace group display names with GUIDs
4142 function Replace-GroupNameWithId {
42- param ($groupNames )
43+ param ($TenantFilter , $ groupNames, $CreateGroups )
4344
4445 $GroupIds = [System.Collections.Generic.List [string ]]::new()
4546 $groupNames | ForEach-Object {
@@ -54,6 +55,20 @@ function New-CIPPCAPolicy {
5455 $null = Write-LogMessage - Headers $User - API ' Create CA Policy' - message " Replaced group name $_ with ID $gid " - Sev ' Debug'
5556 $GroupIds.Add ($gid ) # add the ID to the list
5657 }
58+ } elseif ($CreateGroups ) {
59+ Write-Warning " Creating group $_ as it does not exist in the tenant"
60+ $username = $_ -replace ' [^a-zA-Z0-9]' , ' '
61+ if ($username.Length -gt 64 ) {
62+ $username = $username.Substring (0 , 64 )
63+ }
64+ $GroupObject = @ {
65+ groupType = ' generic'
66+ displayName = $_
67+ username = $username
68+ securityEnabled = $true
69+ }
70+ $NewGroup = New-CIPPGroup - GroupObject $GroupObject - TenantFilter $TenantFilter - APIName ' New-CIPPCAPolicy'
71+ $GroupIds.Add ($NewGroup.GroupId )
5772 } else {
5873 Write-Warning " Group $_ not found in the tenant"
5974 }
@@ -187,8 +202,22 @@ function New-CIPPCAPolicy {
187202 ' displayName' {
188203 try {
189204 Write-Information ' Replacement pattern for inclusions and exclusions is displayName.'
190- $users = New-GraphGETRequest - uri ' https://graph.microsoft.com/beta/users?$select=id,displayName' - tenantid $TenantFilter - asApp $true
191- $groups = New-GraphGETRequest - uri ' https://graph.microsoft.com/beta/groups?$select=id,displayName' - tenantid $TenantFilter - asApp $true
205+ $Requests = @ (
206+ @ {
207+ url = ' users?$select=id,displayName&$top=999'
208+ method = ' GET'
209+ id = ' users'
210+ }
211+ @ {
212+ url = ' groups?$select=id,displayName&$top=999'
213+ method = ' GET'
214+ id = ' groups'
215+ }
216+ )
217+ $BulkResults = New-GraphBulkRequest - Requests $Requests - tenantid $TenantFilter - asapp $true
218+
219+ $users = ($BulkResults | Where-Object { $_.id -eq ' users' }).body.value
220+ $groups = ($BulkResults | Where-Object { $_.id -eq ' groups' }).body.value
192221
193222 foreach ($userType in ' includeUsers' , ' excludeUsers' ) {
194223 if ($JSONobj.conditions.users.PSObject.Properties.Name -contains $userType -and $JSONobj.conditions.users .$userType -notin ' All' , ' None' , ' GuestOrExternalUsers' ) {
@@ -199,7 +228,7 @@ function New-CIPPCAPolicy {
199228 # Check the included and excluded groups
200229 foreach ($groupType in ' includeGroups' , ' excludeGroups' ) {
201230 if ($JSONobj.conditions.users.PSObject.Properties.Name -contains $groupType ) {
202- $JSONobj.conditions.users .$groupType = @ (Replace- GroupNameWithId - groupNames $JSONobj.conditions.users .$groupType )
231+ $JSONobj.conditions.users .$groupType = @ (Replace- GroupNameWithId - groupNames $JSONobj.conditions.users .$groupType - CreateGroups $CreateGroups - TenantFilter $TenantFilter )
203232 }
204233 }
205234 } catch {
@@ -246,18 +275,42 @@ function New-CIPPCAPolicy {
246275 Write-Information $RawJSON
247276 try {
248277 Write-Information ' Checking for existing policies'
249- $CheckExististing = New-GraphGETRequest - uri ' https://graph.microsoft.com/beta/identity/conditionalAccess/policies' - tenantid $TenantFilter - asApp $true | Where-Object - Property displayName -EQ $displayname
250- if ($CheckExististing ) {
278+ $CheckExisting = New-GraphGETRequest - uri ' https://graph.microsoft.com/beta/identity/conditionalAccess/policies' - tenantid $TenantFilter - asApp $true | Where-Object - Property displayName -EQ $displayname
279+ if ($CheckExisting ) {
251280 if ($Overwrite -ne $true ) {
252281 throw " Conditional Access Policy with Display Name $ ( $Displayname ) Already exists"
253282 return $false
254283 } else {
255284 if ($State -eq ' donotchange' ) {
256- $JSONobj.state = $CheckExististing .state
285+ $JSONobj.state = $CheckExisting .state
257286 $RawJSON = ConvertTo-Json - InputObject $JSONobj - Depth 10 - Compress
258287 }
259- Write-Information " overwriting $ ( $CheckExististing.id ) "
260- $null = New-GraphPOSTRequest - uri " https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$ ( $CheckExististing.id ) " - tenantid $tenantfilter - type PATCH - body $RawJSON - asApp $true
288+ # Preserve any exclusion groups named "Vacation Exclusion - <PolicyDisplayName>" from existing policy
289+ try {
290+ $ExistingVacationGroup = New-GraphGETRequest - uri " https://graph.microsoft.com/beta/groups?`$ filter=startsWith(displayName,'Vacation Exclusion')&`$ select=id,displayName&`$ top=999&`$ count=true" - ComplexFilter - tenantid $TenantFilter - asApp $true |
291+ Where-Object { $CheckExisting.conditions.users.excludeGroups -contains $_.id }
292+ if ($ExistingVacationGroup ) {
293+ if (-not ($JSONobj.conditions.users.PSObject.Properties.Name -contains ' excludeGroups' )) {
294+ $JSONobj.conditions.users | Add-Member - NotePropertyName ' excludeGroups' - NotePropertyValue @ () - Force
295+ }
296+ if ($JSONobj.conditions.users.excludeGroups -notcontains $ExistingVacationGroup.id ) {
297+ Write-Information " Preserving vacation exclusion group $ ( $ExistingVacationGroup.displayName ) "
298+ $NewExclusions = [system.collections.generic.list [string ]]::new()
299+ # Convert each item to string explicitly to avoid type conversion issues
300+ foreach ($group in $JSONobj.conditions.users.excludeGroups ) {
301+ $NewExclusions.Add ([string ]$group )
302+ }
303+ $NewExclusions.Add ($ExistingVacationGroup.id )
304+ $JSONobj.conditions.users.excludeGroups = $NewExclusions
305+ }
306+ # Re-render RawJSON after modification
307+ $RawJSON = ConvertTo-Json - InputObject $JSONobj - Depth 10 - Compress
308+ }
309+ } catch {
310+ Write-Information " Failed to preserve vacation exclusion group: $ ( $_.Exception.Message ) "
311+ }
312+ Write-Information " overwriting $ ( $CheckExisting.id ) "
313+ $null = New-GraphPOSTRequest - uri " https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$ ( $CheckExisting.id ) " - tenantid $tenantfilter - type PATCH - body $RawJSON - asApp $true
261314 Write-LogMessage - Headers $User - API ' Create CA Policy' - tenant $ ($Tenant ) - message " Updated Conditional Access Policy $ ( $JSONobj.Displayname ) to the template standard." - Sev ' Info'
262315 return " Updated policy $displayname for $tenantfilter "
263316 }
0 commit comments