SPSUserSync: v1.2.1 — fix UserProfile batch (empty ResultCollection) + UPA prerequisite & readiness check - #12
Merged
Merged
Conversation
SPSyncUserProfile.ps1 needs to manage profiles on the User Profile Service Application. Without that permission, CreateUserProfile / profile reads fail through the UPA cache with "ProfileDBCacheServiceClient.GetUserData threw exception: Access is denied." and the run looks like a silent no-op. Document, in the prerequisites, that the account running SPSyncUserProfile.ps1 must be either the farm account or an account granted Administrator of the UPA with the Manage Profiles permission (Central Administration -> Manage Service Applications -> UPA -> Administrators). - wiki/Getting-Started.md: add a "User Profile Service" prerequisite row. Fixes #10
The readiness check validated the MySite host was reachable but not that the UPA itself was usable, so the missing Manage Profiles permission only surfaced mid-run on the master farm (Access is denied through the UPA cache). Add a non-destructive UPA probe to the SharePoint section (UPA master only, unless -SkipNetwork): open the MySite SPSite, get the service context, instantiate UserProfileManager and read the profile count. No profile is ever created, updated or deleted, so the script keeps its "never writes to the UPA" guarantee. - PASS with the profile count when the read succeeds. - WARN pointing to the Manage Profiles / farm-account prerequisite when the read is denied (matches on "Access is denied"). - WARN when the MySite host cannot be opened (this server is not the UPA master), consistent with the existing MySite check. - Test-SPSUserSyncReadiness.ps1: reuse the opened MySite SPSite for the probe; updated the comment-based help summary. Validated on macOS: PSScriptAnalyzer clean, parse OK, Pester 49/49. Fixes #11
Bump the module manifest to 1.2.1, date the CHANGELOG [1.2.1] section, and rewrite RELEASE-NOTES.md (the GitHub Release body) for this version. A small follow-up to 1.2.0: documents the User Profile Service "Manage Profiles" prerequisite and adds a non-destructive UPA-access check to the readiness script, so the permission gap is caught before the first run instead of mid-job on the master farm. Refs #10, #11
Pester Test Results51 tests 51 ✅ 1s ⏱️ Results for commit 00ba899. ♻️ This comment has been updated with latest results. |
SPSyncUserProfile.ps1 processed no eligible users at all: the run reported
"N users do not meet Prerequisites", wrote no SPSyncUserAddedInUSPList file,
logged no error and finished in the same second it started.
Root cause: Add-SPSUserProfile declared -ResultCollection as
[Parameter(Mandatory = $true)] [System.Collections.ArrayList]. A mandatory
parameter rejects an EMPTY collection, and $tbSPSUserProfileMgmt is empty on the
first loop iteration, so the first eligible user threw a terminating binding
error:
Cannot bind argument to parameter 'ResultCollection' because it is an
empty collection.
That terminating error was swallowed by a script-scoped `Trap { Continue }`,
which resumed after the whole foreach and abandoned every eligible user with no
trace.
Fix:
- Add [AllowEmptyCollection()] to -ResultCollection (root cause).
- Wrap the per-user Add-SPSUserProfile call in try/catch so one failing user is
logged (console + SPSUserSync Event Log) and the batch continues.
- Remove the misleading script-scoped `Trap { Continue }` that hid the failure.
Added tests/SPSyncUserProfile.Tests.ps1: extracts Add-SPSUserProfile from the
script via the AST and asserts -ResultCollection is mandatory AND carries
AllowEmptyCollection, so the regression cannot silently come back.
Verified on a SharePoint Subscription Edition farm: a 12-user input with 3
eligible now creates all 3 profiles (with WorkEmail), writes
SPSyncUserAddedInUSPList and the HTML report. Local: PSScriptAnalyzer clean,
Pester 51/51.
Fixes #13
Record the SPSyncUserProfile.ps1 empty-ResultCollection fix in the [1.2.1] CHANGELOG section and in RELEASE-NOTES.md (the Release body), as the headline change of this patch release. Refs #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request (PR) description
Ships SPSUserSync v1.2.1, a small follow-up to 1.2.0 — with one important fix
to the User Profile reconciliation script, plus a documentation/readiness
improvement around UPA permissions. Both issues surfaced during real-world
testing on a Subscription Edition farm.
The headline fix (#13):
SPSyncUserProfile.ps1processed no users at all.The run reported "N users do not meet Prerequisites", wrote no
SPSyncUserAddedInUSPListfile and logged no error — a silent no-op. Root cause:Add-SPSUserProfile's mandatory-ResultCollectionparameter rejected theempty
ArrayListon the first loop iteration(
Cannot bind argument to parameter 'ResultCollection' because it is an empty collection.), and a script-scopedTrap { Continue }swallowed the terminatingerror and abandoned the whole batch.
Fixed
SPSyncUserProfile.ps1now processes every eligible user. Added[AllowEmptyCollection()]to-ResultCollection(root cause), wrapped theper-user call in
try/catchso one failing user is logged (console + EventLog) and the batch continues, and removed the misleading
Trap { Continue }.Added
tests/SPSyncUserProfile.Tests.ps1(AST-extracts the function and assertsthe parameter is mandatory and allows an empty collection) so the
regression cannot silently come back. ([Bug]: SPSyncUserProfile processes no users — empty ResultCollection rejected by mandatory param #13)
Added
Test-SPSUserSyncReadiness.ps1) now verifies the currentaccount can read the UPA — a non-destructive profile-count read via
UserProfileManager, on the UPA master only. PASS reports the profile count;WARN points to the Manage Profiles / farm-account prerequisite when the read is
denied. It never creates, updates or deletes a profile. ([Feature]: Readiness check should verify UPA access (Manage Profiles) #11)
Changed
SPSyncUserProfile.ps1must be able to manage profiles on the UPA — either the farm account or an
account granted Administrator of the UPA with the Manage Profiles
permission. ([Bug]: SPSyncUserProfile fails without 'Manage Profiles' on the UPA (Access is denied) #10)
Validation
Invoke-Pester ./tests-> 51/51 passed (incl. the new regression test)Invoke-ScriptAnalyzer ./src -Recurse -Settings ./PSScriptAnalyzerSettings.psd1-> cleaneligible now creates all 3 profiles with WorkEmail (RecordId 6/7 created),
writes
SPSyncUserAddedInUSPListand the HTML report. Verified in Manage UserProfiles and on the person profile pages.
This Pull Request (PR) fixes the following issues
Task list
file CHANGELOG.md. Entry should say what was changed and how that
affects users (if applicable), and reference the issue being resolved
(if applicable).