@@ -20,8 +20,6 @@ function Start-UserSyncTimer {
2020 $ApiName = ' UserSync'
2121
2222 try {
23- Write-LogMessage - API $ApiName - tenant ' none' - message ' Starting user sync from partner tenant.' - sev Info
24-
2523 # Load the role-to-group mappings
2624 $AccessGroupsTable = Get-CippTable - TableName AccessRoleGroups
2725 $AccessGroups = @ (Get-CIPPAzDataTableEntity @AccessGroupsTable - Filter " PartitionKey eq 'AccessRoleGroups'" )
@@ -69,12 +67,6 @@ function Start-UserSyncTimer {
6967 }
7068 }
7169
72- if ($UserRoleMap.Count -eq 0 -and $RoleGroupIds.Count -gt 0 ) {
73- Write-LogMessage - API $ApiName - tenant ' none' - message ' No users found in any role groups.' - sev Info
74- } elseif ($RoleGroupIds.Count -eq 0 ) {
75- Write-LogMessage - API $ApiName - tenant ' none' - message ' No Entra groups mapped to roles — will clean up any stale auto-provisioned users.' - sev Info
76- }
77-
7870 # Load existing allowedUsers table
7971 $UsersTable = Get-CippTable - tablename ' allowedUsers'
8072 $ExistingUsers = @ (Get-CIPPAzDataTableEntity @UsersTable | Where-Object { -not $_.RowKey.StartsWith (' _' ) })
@@ -91,7 +83,6 @@ function Start-UserSyncTimer {
9183 }
9284
9385 $Now = (Get-Date ).ToUniversalTime().ToString(' o' )
94- $UpsertCount = 0
9586 $RemoveCount = 0
9687 $EntitiesToUpsert = [System.Collections.Generic.List [object ]]::new()
9788 $EntitiesToRemove = [System.Collections.Generic.List [object ]]::new()
@@ -134,7 +125,6 @@ function Start-UserSyncTimer {
134125 }
135126
136127 $EntitiesToUpsert.Add ($Entity )
137- $UpsertCount ++
138128 }
139129
140130 # Reconcile existing users that are NOT in any mapped role group
@@ -205,8 +195,22 @@ function Start-UserSyncTimer {
205195 }
206196 }
207197
208- # Apply upserts first (write canonical rows), then removals (drop duplicates/stale rows)
198+ # Apply upserts first (write canonical rows), then removals (drop duplicates/stale rows).
199+ # Only count an upsert as a change when the role data actually differs from the
200+ # existing canonical row — LastSync alone changing every run isn't a real change.
201+ $ChangedCount = 0
209202 foreach ($Entity in $EntitiesToUpsert ) {
203+ $Canonical = $null
204+ if ($ExistingLookup.ContainsKey ($Entity.RowKey )) {
205+ $Canonical = $ExistingLookup [$Entity.RowKey ] | Where-Object { $_.RowKey -ceq $Entity.RowKey } | Select-Object - First 1
206+ }
207+ if (-not $Canonical -or
208+ $Canonical.Roles -ne $Entity.Roles -or
209+ $Canonical.AutoRoles -ne $Entity.AutoRoles -or
210+ $Canonical.ManualRoles -ne $Entity.ManualRoles -or
211+ $Canonical.Source -ne $Entity.Source ) {
212+ $ChangedCount ++
213+ }
210214 Add-CIPPAzDataTableEntity @UsersTable - Entity $Entity - Force
211215 }
212216 foreach ($Entity in $EntitiesToRemove ) {
@@ -217,7 +221,10 @@ function Start-UserSyncTimer {
217221 # Invalidate CRAFT's in-memory user cache so changes apply
218222 try { [Craft.Services.AuthBridge ]::InvalidateUsers() } catch {}
219223
220- Write-LogMessage - API $ApiName - tenant ' none' - message " User sync completed: $UpsertCount users synced, $RemoveCount duplicate/stale rows removed." - sev Info
224+ # Only log when something actually changed — no noise on steady-state runs.
225+ if ($ChangedCount -gt 0 -or $RemoveCount -gt 0 ) {
226+ Write-LogMessage - API $ApiName - tenant ' none' - message " User sync completed: $ChangedCount users added/updated, $RemoveCount duplicate/stale rows removed." - sev Info
227+ }
221228
222229 } catch {
223230 $ErrorData = Get-CippException - Exception $_
0 commit comments