Skip to content

SPSUserSync: v1.2.1 — fix UserProfile batch (empty ResultCollection) + UPA prerequisite & readiness check - #12

Merged
luigilink merged 6 commits into
mainfrom
release/1.2.1
Jun 28, 2026
Merged

SPSUserSync: v1.2.1 — fix UserProfile batch (empty ResultCollection) + UPA prerequisite & readiness check#12
luigilink merged 6 commits into
mainfrom
release/1.2.1

Conversation

@luigilink

@luigilink luigilink commented Jun 28, 2026

Copy link
Copy Markdown
Owner

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.ps1 processed no users at all.
The run reported "N users do not meet Prerequisites", wrote no
SPSyncUserAddedInUSPList file and logged no error — a silent no-op. Root cause:
Add-SPSUserProfile's mandatory -ResultCollection parameter rejected the
empty ArrayList on the first loop iteration
(Cannot bind argument to parameter 'ResultCollection' because it is an empty collection.), and a script-scoped Trap { Continue } swallowed the terminating
error and abandoned the whole batch.

Fixed

  • SPSyncUserProfile.ps1 now processes every eligible user. Added
    [AllowEmptyCollection()] to -ResultCollection (root cause), wrapped the
    per-user call in try/catch so one failing user is logged (console + Event
    Log) and the batch continues, and removed the misleading Trap { Continue }.
    Added tests/SPSyncUserProfile.Tests.ps1 (AST-extracts the function and asserts
    the 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

  • The readiness check (Test-SPSUserSyncReadiness.ps1) now verifies the current
    account 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

Validation

  • Invoke-Pester ./tests -> 51/51 passed (incl. the new regression test)
  • Invoke-ScriptAnalyzer ./src -Recurse -Settings ./PSScriptAnalyzerSettings.psd1 -> clean
  • Real-world on a SharePoint Subscription Edition farm: a 12-user input with 3
    eligible now creates all 3 profiles with WorkEmail (RecordId 6/7 created),
    writes SPSyncUserAddedInUSPList and the HTML report. Verified in Manage User
    Profiles and on the person profile pages.

This Pull Request (PR) fixes the following issues

Task list

  • Added an entry to the change log under the Unreleased section of the
    file CHANGELOG.md. Entry should say what was changed and how that
    affects users (if applicable), and reference the issue being resolved
    (if applicable).
  • Added/updated documentation and descriptions where appropriate?
  • New/changed code adheres to Style Guidelines?

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
Document under [Unreleased] the new UPA-access readiness check and the UPA
Manage Profiles prerequisite, each referencing its issue.

Refs #10, #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
@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown

Pester Test Results

51 tests   51 ✅  1s ⏱️
12 suites   0 💤
 1 files     0 ❌

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
@luigilink luigilink changed the title SPSUserSync: v1.2.1 — document UPA Manage Profiles prerequisite + readiness UPA check SPSUserSync: v1.2.1 — fix UserProfile batch (empty ResultCollection) + UPA prerequisite & readiness check Jun 28, 2026
@luigilink
luigilink merged commit 0c4ca29 into main Jun 28, 2026
3 checks passed
@luigilink
luigilink deleted the release/1.2.1 branch June 28, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant