Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cloud PC SSO Toggle

A small WPF/PowerShell GUI that applies the Windows 365 Single Sign-On setting to a hand-picked subset of Cloud PCs — instead of the entire provisioning policy's assigned population.

Community tool — unsupported. Test in a lab tenant before using it against production Cloud PCs.

Cloud PC SSO Toggle screenshot


The problem it solves

"Enable single sign-on" lives on the Cloud PC Provisioning Policy, not on the individual Cloud PC. In the Intune portal, the "Apply Region/SSO" action lets you push a Region change to a hand-picked list of Cloud PCs, but for SSO it only offers "apply to all Cloud PCs assigned to this policy" — there's no portal equivalent of "just these three."

The underlying Graph API, however, doesn't enforce that restriction:

POST /deviceManagement/virtualEndpoint/provisioningPolicies/applyConfig
{ "cloudPcIds": [ "...", "..." ], "policySettings": "singleSignOn" }

applyConfig accepts an arbitrary list of Cloud PC IDs — it isn't limited to "every CPC on the policy." This tool exposes that capability with a safe, observable, auditable workflow, so you can flip SSO on (or off) for a pilot group, a single affected user, or a staged rollout, without touching anyone else on the same policy.


How it works, end to end

  1. Connect to Microsoft Graph (delegated auth, one scope — see Permissions below).
  2. Discover your Enterprise provisioning policies and the Cloud PCs assigned to each (queried directly by provisioningPolicyId, not via group membership — see Architecture notes). Enterprise only today — see Known limitations for the Frontline/Flex story.
  3. Pick a policy, then check the individual Cloud PCs you want to change. Each Cloud PC is its own row, so a user with multiple Cloud PCs across different policies can be handled one at a time.
  4. Queue the selected Cloud PCs with a target SSO value (On/Off).
  5. Run the queue. For each queued Cloud PC, the tool:
    • Temporarily sets the provisioning policy's enableSingleSignOn to match this job's target (only if it isn't already that value), and confirms the write actually read back before proceeding.
    • Calls applyConfig for that one Cloud PC ID with policySettings: "singleSignOn".
    • Polls the Cloud PC until its status leaves modifyingSingleSignOn.
    • Does one final confirmation poll to verify connectionSetting.enableSingleSignOn actually matches the target.
    • Once every in-flight job touching that policy has reached a terminal state, restores the policy to whatever value it had before this run first touched it.
  6. Track progress in a live queue grid (5-stage pill per job: Queued → Applying → Waiting for Modification → Verifying → Done/Failed), a running log (also written to Logs\*.log next to the script), and an Export CSV button for reporting on larger batches.

An optional Schedule feature lets you set a future start time and/or an auto-pause time (e.g., "start at 2 AM, pause after 4 hours") for after-hours batches — see Scheduling below.


What happens to the Cloud PC itself

Changing the SSO setting isn't a live in-place config change — the VM goes through a shutdown / reconfigure / start-back-up cycle (effectively a cold reboot), whether you're turning SSO On or Off. This matches Microsoft's documented behavior:

"Applying SSO to a large number of Cloud PCs can restart the VMs over a long period of time and won't complete immediately." — Edit a provisioning policy

Lab observations (your mileage may vary — this is not a documented SLA):

  • Every Cloud PC tested shuts down while modifyingSingleSignOn, then starts back up once the change completes — even Cloud PCs only a few days old, not just ones provisioned before April 2023. The April 2023 cutoff in Microsoft's docs describes an unannounced/no-warning reboot risk for older Cloud PCs, not "old Cloud PCs reboot and new ones don't" — assume any Cloud PC will reboot when its SSO setting changes.
  • Newer Cloud PCs (days old) completed reliably in under ~20 minutes.
  • Older Cloud PCs took noticeably longer — potentially a few hours — to clear modifyingSingleSignOn, consistent with Microsoft's "won't complete immediately" guidance for larger/older fleets.
  • Practical implication: warn end users before running this, regardless of Cloud PC age — treat the in-app "Provisioned before Apr 2023" warning icon as a higher-risk flag (longer, less predictable downtime), not as the only condition under which a reboot happens at all.

Understanding the risk (read this before using it)

The core risk in this tool isn't the Graph call itself — it's the fact that the policy and the Cloud PC are momentarily out of sync while this runs. Two things to understand:

1. Why the policy gets temporarily changed at all

applyConfig doesn't accept a per-Cloud-PC value — it just tells the service "go re-read the policy's current enableSingleSignOn and push it to these Cloud PC IDs." So to get Cloud PC A to SSO=On while the policy's "real" steady-state value is Off, the tool must: briefly set the policy to On → call applyConfig for A → wait for A to finish → put the policy back to Off.

During that window, any other Cloud PC on the same policy that isn't part of this run is unaffected — the policy value alone doesn't change existing Cloud PCs; only applyConfig (or a new provisioning) does. The exposure is narrow, but not zero. Conditions that could cause an unintended Cloud PC to pick up the temporary value while the policy is flipped:

  • A new Cloud PC is provisioned under this policy during the window (e.g. a new license assignment triggers provisioning) — it reads the policy's current (temporarily flipped) value at provision time.
  • An existing Cloud PC is reprovisioned or reset (via the portal, Graph, or an automated workflow) during the window — reprovisioning re-reads the policy just like applyConfig does.
  • Another admin or automated process independently calls applyConfig (or the Intune portal's "Apply configuration" action) against this policy during the window — including, notably, applying it to all assigned Cloud PCs rather than a selected few, which would push the temporary value tenant-wide for that policy.

There is currently no automated detection for these cases — the tool does not diff the full set of Cloud PCs on a policy before/after a run. If you suspect one of these occurred, check connectionSetting.enableSingleSignOn on the affected Cloud PCs directly.

2. Why the tool waits for full completion before restoring the policy

Two rounds of overnight experiments (see Logs/history for details) showed that applyConfig's "204 Accepted" response does not mean the value was read at that moment — the backend actually reads the policy's current value sometime during the modifyingSingleSignOn window, which can take several minutes. Restoring the policy early (e.g., right after the POST) risks the backend reading the restored (wrong) value mid-flight and silently applying the opposite of what you intended.

There is no known safe "early restore" timing. The only proven-safe rule is: hold the policy at the target value until the Cloud PC's job reaches a terminal state (Success/Failed), and only then restore it — and only once no other in-flight job still needs that policy at that value. This is exactly what the tool does; it is not configurable, and shouldn't be worked around.

3. What happens if you Stop mid-run

Stop is deliberately "hard" and makes no further Graph calls — a job mid-flight may still be relying on the policy being pinned to its target, and issuing more PATCH calls at that moment would work against the "stop now" intent (and could re-introduce the exact race described above). Instead, Stop shows a dialog listing any policies that may have been left on a temporary value, so you can manually verify/revert them after refreshing the policy list. Pause is safer in this respect — it only blocks new jobs from starting; anything already in flight keeps running to completion (and the policy still gets restored automatically once it does).

4. Failure modes and what they mean

Stage failure What it means
Failed to set policy / failed read-back The policy PATCH didn't take (or didn't read back correctly) — applyConfig was not called, so nothing was pushed to the Cloud PC. Safe to retry.
Timeout in "Waiting for Modification" The Cloud PC never left modifyingSingleSignOn (or never entered it) within the timeout — the request may not have been processed. Check the Cloud PC directly in the portal before retrying.
Confirmed value mismatch in "Verifying" The status cleared but the final value doesn't match target — rare, but treated as a hard failure rather than silently accepted.

Scheduling

The Schedule... button arms an optional start time and/or stop (pause) time, useful for running batches after hours. A few behaviors worth knowing:

  • Manually clicking Start while a schedule is armed supersedes/clears the pending scheduled start (it's redundant at that point) but leaves a pending scheduled stop alone, since that's still meaningful.
  • Stop (manual) cancels the whole schedule outright.
  • Pause, whether triggered manually or by a scheduled stop, only blocks new job promotion — in-flight jobs keep running and the policy is still restored automatically once they finish, even while paused.
  • While a start is still pending, the tool lightly pings Graph every 10 minutes to keep your token from going stale over a long wait, and does a connection check right before the scheduled start actually fires — aborting gracefully (jobs stay queued) if the connection dropped, rather than failing confusingly mid-run.

Permissions required

The tool requests exactly one delegated Graph scope:

  • CloudPC.ReadWrite.All

That's sufficient for every Graph call the tool makes: discovering provisioning policies and their assignments, listing Cloud PCs by policy, reading/patching a policy's enableSingleSignOn, calling applyConfig, and polling Cloud PC status. There is no group-membership or directory read — the "which user is this Cloud PC assigned to" info shown in the UI comes directly from the Cloud PC object's own userPrincipalName field, not from a group lookup.


Architecture notes

  • Single file, no module to install beyond the Microsoft.Graph PowerShell module (interactive install prompt on first run if missing).
  • Job state machine: each queued Cloud PC is a CPCSsoJobState object advancing through a 5-stage pipeline (Queued → Applying → Waiting for Modification → Verifying → Success/Failed), driven by a GUI DispatcherTimer tick — one small step per job per tick, so the UI never blocks on a long-running Graph poll.
  • Policy pin/restore bookkeeping ($script:SsoPolicyOriginalValue) tracks each touched policy's pre-run value and only restores it once no remaining job still needs that policy at its current value — this is what lets multiple jobs on the same policy (even toward different target values, one after another) share it safely without stepping on each other.
  • Logging: every run auto-logs to Logs\CloudPC-SSO-Toggle_<timestamp>.log next to the script (best-effort; falls back to on-screen-only logging if the folder isn't writable). Logs/ and exported *.csv files are .gitignored.

Known limitations

  • Enterprise policies only, by design — the tool intentionally filters out Frontline/Flex provisioning policies (cloudPcType == 'frontline'). The underlying mechanism (enableSingleSignOn on the policy, applyConfig with policySettings: "singleSignOn") is documented as the same API regardless of policy type, so the same approach should work for Frontline/Flex too — but this hasn't been tested, and Frontline's shared/multi-user Cloud PC model (a Cloud PC isn't tied to one userPrincipalName the way Enterprise ones are) means the current one-row-per-user grid wouldn't map cleanly without changes. Treat this as an untested, plausible extension rather than a supported path today.
  • Windows/WPF only (PowerShell 5.1+, Microsoft.Graph module).
  • No Window.Closing guard — closing the window mid-run does not prompt or attempt any cleanup of policies left pinned to a temporary value.
  • The Stop button's "please verify manually" dialog is the extent of its safety net; there's no automated rollback of a policy left on a temporary value after a hard Stop.

About

WPF/PowerShell GUI to apply Windows 365 Cloud PC Single Sign-On to a hand-picked subset of Cloud PCs via Microsoft Graph, instead of the whole provisioning policy.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages