<?xml version="1.0"?>
<rss version="2.0"><channel><title><![CDATA[Microsoft 365 & Intune Latest Topics]]></title><link>https://wtmsp.com/forum/8-microsoft-365-intune/</link><description><![CDATA[Microsoft 365 & Intune Latest Topics]]></description><language>en</language><item><title>Getting Windows Hello working with on-prem file shares using Cloud Kerberos Trust</title><link>https://wtmsp.com/topic/9-getting-windows-hello-working-with-on-prem-file-shares-using-cloud-kerberos-trust/</link><description><![CDATA[<p>Windows Hello for Business (WHfB) lets people sign in with a PIN or biometric tied to the device's TPM instead of a password. In a hybrid environment, the hard part has always been getting on-premises resources like file shares, printers and Kerberos apps to accept that Hello sign-in. Get it wrong and the user signs in with a PIN, then gets a password prompt the moment they open a share. The older key trust and certificate trust models needed either a PKI with certificates on your domain controllers, or a wait while public keys synced back to AD. Cloud Kerberos Trust removes both. Entra ID issues a partial Kerberos ticket that your DCs trust. It's now Microsoft's recommended model for hybrid deployments, and it's what we deploy.</p>
<div class="ipsRichTextBox" data-i-background-color="blue"><div class="ipsRichTextBox__title"><p><strong>Check these before you start</strong></p></div>
<ul>
<li>Hybrid joined or Entra joined devices on Windows 10 21H2 or later (fully patched) or Windows 11.</li>
<li>Domain controllers running Windows Server 2016 or later, fully patched, at every site where users will authenticate.</li>
<li>Entra Connect syncing your users.</li>
<li>Intune (or Group Policy) to deploy the WHfB settings.</li>
<li>A Domain Admin account in the on-premises domain and a Global Administrator (or Hybrid Identity Administrator) account in Entra ID.</li>
<li>Users who can complete MFA, since WHfB provisioning requires it.</li>
</ul>
</div>
<h2>Why we went with cloud trust</h2>
<p>There's no PKI involved. You don't have DC certificates to issue and renew for Hello, and you don't have to worry about CRL availability.</p>
<p>There's also no key sync delay. With key trust, a new user's public key had to sync to AD before on-premises SSO worked, so the instructions for new staff were basically "set up Hello, then wait up to an hour." With cloud trust it works right after provisioning.</p>
<p>And if you plan to use FIDO2 security keys for hybrid sign-in, the same Entra Kerberos object supports that too.</p>

<h2>Create the Entra Kerberos server object</h2>
<p>This creates a read-only domain controller-style computer object (<code>AzureADKerberos</code>) in your domain and publishes its key to Entra ID, so your DCs can trust the tickets Entra issues. Run it from an elevated PowerShell session on a domain-joined machine that can reach a writable DC.</p>
<pre class="ipsCode" data-language="powershell"># TLS 1.2 for the PowerShell Gallery on older systems
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Install-Module -Name AzureADHybridAuthenticationManagement -AllowClobber

$domain = $env:USERDNSDOMAIN            # e.g. CONTOSO.LOCAL
$upn    = "admin@contoso.com"            # Entra Global Admin or Hybrid Identity Admin
$domainCred = Get-Credential             # Domain Admin in the on-prem domain

Set-AzureADKerberosServer -Domain $domain -UserPrincipalName $upn -DomainCredential $domainCred

# Confirm it exists and the key versions match
Get-AzureADKerberosServer -Domain $domain -UserPrincipalName $upn -DomainCredential $domainCred</pre>
<p>If your admin account requires MFA, the module supports an interactive sign-in instead of passing the UPN. Check the module's help for the current parameters. In AD you should now see an <code>AzureADKerberos</code> computer object in the Domain Controllers OU and a <code>krbtgt_AzureAD</code> user. Don't delete or move either one. Repeat this for each domain in the forest where users sign in.</p>

<h2>The WHfB policy in Intune</h2>
<p>Create a Settings catalog profile for Windows and search for Windows Hello for Business. At a minimum, set <strong>Use Windows Hello For Business</strong> to Enabled (with your PIN complexity and biometric preferences) and <strong>Use Cloud Trust For On Prem Auth</strong> to Enabled.</p>
<p>Under the hood, the cloud trust setting is this CSP.</p>
<pre class="ipsCode" data-language="plaintext">./Device/Vendor/MSFT/PassportForWork/&lt;TenantID&gt;/Policies/UseCloudTrustForOnPremAuth = true</pre>
<p>Assign it to a pilot device group. If you already have a tenant-wide WHfB configuration under Windows enrollment settings, make sure the two don't conflict. The settings catalog profile is the one we rely on. Without Intune, the equivalent Group Policy setting is "Use cloud Kerberos trust for on-premises authentication" under the Windows Hello for Business administrative templates.</p>

<h2>Try it with one user</h2>
<p>Sync policy on the pilot device and have the user sign out and back in. After MFA, they should be prompted to set up Windows Hello. Then lock the machine and sign in with the PIN.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>Confirming on-prem SSO works</strong></p></div>
<p>Run these as the user, while signed in with Hello.</p>
<pre class="ipsCode" data-language="powershell">dsregcmd /status
klist cloud_debug
klist</pre>
<ul>
<li>In <code>dsregcmd /status</code>, under SSO State, you want <code>CloudTgt : YES</code> and <code>OnPremTgt : YES</code>. Under the NGC prerequisite check, <code>NgcSet : YES</code> confirms the user has provisioned Hello.</li>
<li><code>klist cloud_debug</code> should report that the cloud primary (hybrid logon) TGT is available and that cloud Kerberos is enabled by policy.</li>
<li><code>klist</code> should show a <code>krbtgt</code> ticket for your on-premises realm, plus service tickets once you browse a file share.</li>
<li>The test I care about most is opening <code>\\fileserver\share</code> while signed in with the PIN. No password prompt means on-premises SSO works.</li>
</ul>
</div>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>What tripped us up</strong></p></div>
<ul>
<li>Privileged accounts don't work, and that's by design. The Entra Kerberos object behaves like an RODC, so accounts that can't have their credentials cached on an RODC, such as members of Domain Admins and other groups in the "Denied RODC Password Replication Group," won't get on-premises tickets from cloud trust. They'll sign in to Windows fine and then fail to reach on-premises resources. Admins should be using a separate daily account anyway.</li>
<li>If any DC a client might talk to is missing the required updates, sign-ins fail intermittently depending on which DC answers. That's a miserable one to chase, so patch them all before the pilot.</li>
<li>Devices previously set up for key trust or certificate trust may keep using it. Clean up old GPOs and policies, and have users reprovision if needed.</li>
<li>Kerberos fails if the client and DC clocks drift more than about five minutes apart. Check time sync on remote and VPN devices.</li>
<li>Getting the on-premises ticket still needs line of sight to a DC when the resource is accessed. Hello sign-in to Windows works off-network, but file shares still need the VPN.</li>
</ul>
</div>
<p>One last thing that's easy to forget once everything works. Rotate the Entra Kerberos server key periodically with <code>Set-AzureADKerberosServer -RotateServerKey</code> (using the same domain and credential parameters), and put it on your maintenance calendar so it doesn't depend on somebody remembering.</p>]]></description><guid isPermaLink="false">9</guid><pubDate>Sun, 18 Oct 2026 20:19:40 +0000</pubDate></item><item><title>Intune Remediations for config drift, and the one that never fixed anything</title><link>https://wtmsp.com/topic/8-intune-remediations-for-config-drift-and-the-one-that-never-fixed-anything/</link><description><![CDATA[<p>Every environment has little problems that keep coming back, like a service that keeps getting disabled or a registry setting an app keeps resetting. Each time, somebody calls the help desk and a tech fixes it by hand. Intune Remediations (previously Proactive Remediations) are how we stop doing that. You give Intune a pair of PowerShell scripts that run on a schedule, one to detect the problem and one to fix it. Below is how we write them, how we schedule and check them, and the Graph gotcha that left one of ours detecting problems for weeks without fixing a single one.</p>
<div class="ipsRichTextBox" data-i-background-color="blue"><div class="ipsRichTextBox__title"><p><strong>Licensing and setup</strong></p></div>
<ul>
<li>Licensing that includes Remediations, which means Windows Enterprise E3/E5 or Education A3/A5 (often through Microsoft 365 E3/E5 or A3/A5), or Windows VDA per user.</li>
<li>Devices that are Entra joined or hybrid joined and managed by Intune. The Intune Management Extension is what runs the scripts.</li>
<li>A test device group.</li>
</ul>
</div>
<h2>How the two scripts work together</h2>
<p>The detection script runs first. <code>exit 0</code> means everything's fine and there's nothing to do. <code>exit 1</code> means it found an issue, and Intune runs the remediation script.</p>
<p>The remediation script does the fix. After it runs, the detection script runs again so Intune can report whether the fix held.</p>
<p>Whatever the scripts write to STDOUT shows up as the detection and remediation output in the portal, and the last line is what you see in reports. Make that line useful to whoever reads the report later, because "ok" doesn't tell them much.</p>

<h2>The detection script</h2>
<p>This example makes sure the Windows Time service is set to automatic and running.</p>
<pre class="ipsCode" data-language="powershell"># Detect-W32Time.ps1
try {
    $svc = Get-Service -Name W32Time -ErrorAction Stop
    if ($svc.StartType -ne 'Automatic' -or $svc.Status -ne 'Running') {
        Write-Output "Issue: W32Time StartType=$($svc.StartType) Status=$($svc.Status)"
        exit 1
    }
    Write-Output "OK: W32Time running"
    exit 0
}
catch {
    Write-Output "Issue: $($_.Exception.Message)"
    exit 1
}</pre>

<h2>The remediation script</h2>
<pre class="ipsCode" data-language="powershell"># Remediate-W32Time.ps1
try {
    Set-Service -Name W32Time -StartupType Automatic -ErrorAction Stop
    Start-Service -Name W32Time -ErrorAction Stop
    w32tm /resync /force | Out-Null
    Write-Output "Remediated: W32Time set to Automatic and started"
    exit 0
}
catch {
    Write-Output "Remediation failed: $($_.Exception.Message)"
    exit 1
}</pre>
<p>Keep both scripts idempotent, so running the fix twice does no harm. Save them as UTF-8, and keep them small and dependency-free. There's no guarantee any module you rely on exists on the client.</p>

<h2>Creating the package</h2>
<p>In the Intune admin center, go to Devices, then Scripts and remediations, then Remediations, and create a script package. Upload both scripts and pick the settings.</p>
<ul>
<li>"Run this script using the logged-on credentials" should be No (so it runs as SYSTEM) for machine settings like services. Only use Yes for per-user fixes.</li>
<li>Only turn on "Enforce script signature check" if you sign your scripts.</li>
<li>Set "Run script in 64-bit PowerShell" to Yes for most things, so you see the real registry and <code>System32</code>.</li>
</ul>

<h2>Assigning and scheduling</h2>
<p>Assign it to a pilot group first and choose a schedule of once, hourly or daily (with a time). Daily is a sensible default for drift. Hourly is for things that genuinely need it, since every run is another process on every device. You can also run it on a single device on demand from that device's page with the "Run remediation" action, which is handy for testing.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>Checking that it works</strong></p></div>
<p>Open the remediation and go to the device status view. Add the output columns (pre-remediation detection output, remediation output and post-remediation detection output) so you can see what each script reported. A working package shows devices moving from "With issues" to "Issues fixed." On the device itself, the Intune Management Extension logs under <code>C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\</code> show each run.</p>
<p>Then break it on purpose. Stop the service on a test device, trigger the remediation on demand, and make sure the service comes back.</p>
</div>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>The package that only ever detected</strong></p></div>
<p>We automate a lot of Intune through Microsoft Graph, including creating and assigning remediation packages across tenants. One package showed exactly the right detection results. Devices were listed "with issues," and the output clearly explained the problem. And yet nothing ever got fixed. Weeks later, the same devices were still on the list.</p>
<p>The assignment had been created through Graph with the flag that tells Intune to run the remediation script set to true. When we read it back in the portal, the package was assigned in a detection-only state. In our experience that flag on the assignment can be <strong>silently ignored</strong>. The API call succeeds, no error comes back, and the package runs detection only.</p>
</div>
<p>Here's what we do now.</p>
<ol>
<li>After any create or assign through Graph, <strong>open the package in the portal and read back the assignment</strong>. Make sure the remediation script is enabled to run, not just detection.</li>
<li>If it isn't, fix it in the portal (or re-check your Graph payload against the current API documentation) and read it back again.</li>
<li>Before calling the rollout done, wait until at least one device shows "Issues fixed" in the report. If all you ever see is "With issues," the remediation side isn't running.</li>
</ol>

<h2>Other ways these go sideways</h2>
<ul>
<li>If detection exits 0 when there's a problem, for example because an error got swallowed, the remediation never runs. Always exit 1 in the catch block.</li>
<li>The post-remediation detection runs right away. If your fix only takes effect after a reboot or a service restart, detection reports "failed" even though it worked. Account for that in the logic or the output.</li>
<li>Keep scripts and output short. Long output gets truncated in the report.</li>
<li>Scripts set to run as the logged-on user fail when nobody is logged on, and they can't change machine settings.</li>
</ul>
<p>I've stopped trusting any automated assignment until I've seen "Issues fixed" in the report myself. It costs a day of waiting, which beats finding out weeks later.</p>]]></description><guid isPermaLink="false">8</guid><pubDate>Sun, 18 Oct 2026 20:18:40 +0000</pubDate></item><item><title>Our Win32 app packaging routine for Intune, and why we test as SYSTEM first</title><link>https://wtmsp.com/topic/7-our-win32-app-packaging-routine-for-intune-and-why-we-test-as-system-first/</link><description><![CDATA[<p>Most real software gets into Intune as a Win32 app. That covers EXE installers, MSIs with transforms, and anything that needs a script to do some work before or after setup. Building the package is the easy part. What actually breaks deployments is detection rules, install context and return codes, and usually you find out when someone opens a ticket saying the app they were promised never showed up. This is the process we follow, including the testing step that saves us the most time.</p>
<div class="ipsRichTextBox" data-i-background-color="blue"><div class="ipsRichTextBox__title"><p><strong>Tools to grab first</strong></p></div>
<ul>
<li>The Microsoft Win32 Content Prep Tool (<code>IntuneWinAppUtil.exe</code>) from Microsoft's GitHub.</li>
<li>The installer and its silent install and uninstall switches. Check the vendor's documentation, or run it with <code>/?</code>.</li>
<li>A test VM or spare PC, ideally with a snapshot you can roll back.</li>
<li>Sysinternals PsExec, for testing as SYSTEM.</li>
</ul>
</div>
<h2>Start with a clean source folder</h2>
<p>Put only what the install needs into one folder, like the installer, any transforms or config files, and an optional wrapper script. Everything in that folder ends up in the package, so don't point the tool at your Downloads folder.</p>
<pre class="ipsCode" data-language="plaintext">C:\Packaging\AcmeApp\Source\
    AcmeApp-5.2.msi
    settings.xml
    Install.ps1
C:\Packaging\AcmeApp\Output\</pre>

<h2>Test the silent install as SYSTEM</h2>
<p>This is the step I'd never skip. Intune installs Win32 apps in SYSTEM context by default, and an installer that works fine when you double-click it can behave completely differently as SYSTEM. There's no user profile, no mapped drives and no HKCU. So test it the way Intune will run it.</p>
<pre class="ipsCode" data-language="powershell"># Opens a PowerShell window running as SYSTEM (run from an elevated prompt)
psexec.exe -s -i powershell.exe

# In the SYSTEM window, confirm who you are, then run your exact install line
whoami
msiexec /i "C:\Packaging\AcmeApp\Source\AcmeApp-5.2.msi" /qn /norestart /l*v C:\Windows\Temp\AcmeApp-install.log
$LASTEXITCODE</pre>
<p>Write down the exit code, then test the uninstall line the same way. If either one needs anybody to click anything, it'll hang in Intune until the timeout.</p>

<h2>Build the .intunewin</h2>
<pre class="ipsCode" data-language="powershell">.\IntuneWinAppUtil.exe -c "C:\Packaging\AcmeApp\Source" -s "AcmeApp-5.2.msi" -o "C:\Packaging\AcmeApp\Output" -q</pre>
<p><code>-c</code> is the source folder, <code>-s</code> is the setup file (relative to the source folder), <code>-o</code> is the output folder, and <code>-q</code> is quiet mode. When the setup file is an MSI, the tool reads its metadata and Intune can prefill the product code for detection.</p>

<h2>Creating the app in Intune</h2>
<p>In the Intune admin center, add a Windows app of type "Windows app (Win32)," upload the <code>.intunewin</code>, and fill in the commands and behavior.</p>
<ul>
<li>Install command: <code>msiexec /i "AcmeApp-5.2.msi" /qn /norestart</code>, or for a wrapper, <code>powershell.exe -ExecutionPolicy Bypass -File .\Install.ps1</code>.</li>
<li>Uninstall command: for an MSI, <code>msiexec /x {PRODUCT-CODE-GUID} /qn</code>.</li>
<li>Install behavior: System or User. Use System unless the app installs per user into the profile.</li>
<li>Device restart behavior: usually "Determine behavior based on return codes."</li>
</ul>
<p>The default return codes are 0 (success), 1707 (success), 3010 (soft reboot), 1641 (hard reboot) and 1618 (retry, another install in progress). Add any vendor-specific success codes your installer uses. If you don't, a perfectly good install gets reported as failed, and somebody burns an afternoon chasing it.</p>

<h2>Requirement rules decide who gets it</h2>
<p>Requirements decide whether the app even applies to a device. You can check OS architecture, minimum Windows version, disk space and RAM, and optionally add a file, registry or script check. If a requirement isn't met, the device reports "Not applicable" instead of failing. We use a script or file requirement to limit apps to a subset of devices, for example only machines with a marker file dropped by a department provisioning step.</p>

<h2>Detection rules, where most of the trouble lives</h2>
<p>Detection is how Intune decides whether the app is installed, right after the install runs and on every check after that. You've got four options.</p>
<ul>
<li>The MSI product code is the most reliable for MSIs, and you can check the version too.</li>
<li>A file or folder rule checks that something exists, or compares the version or date on a specific file, for example <code>C:\Program Files\Acme\acme.exe</code> with version greater than or equal to 5.2.</li>
<li>A registry rule checks that a key or value exists or matches, like the app's entry under the Uninstall key. Pay attention to the "associated with a 32-bit app on 64-bit clients" option, which controls whether Intune looks in the WOW6432Node view.</li>
<li>A custom PowerShell script decides for itself. I reach for it when the other options can't express the condition.</li>
</ul>
<pre class="ipsCode" data-language="powershell"># Detection script: detected = exit 0 AND something written to STDOUT
$exe = "C:\Program Files\Acme\acme.exe"
if (Test-Path $exe) {
    $ver = [version](Get-Item $exe).VersionInfo.FileVersion
    if ($ver -ge [version]"5.2.0") {
        Write-Output "AcmeApp $ver detected"
        exit 0
    }
}
exit 1</pre>

<h2>Pilot it</h2>
<p>Assign it as Required to a small device group, or as Available to a user group for Company Portal. Sync the test device and watch it.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>How we confirm it landed</strong></p></div>
<ul>
<li>The app's device install status in Intune shows Installed, not "Failed" or "Not detected."</li>
<li>The Intune Management Extension logs on the client tell you what actually ran. They live in <code>C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\</code>, and the ones I open are <code>IntuneManagementExtension.log</code> and <code>AppWorkload.log</code>. CMTrace or any log viewer that follows the file helps.</li>
<li>If you included <code>/l*v</code> in the install line, the installer log has the rest.</li>
</ul>
</div>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>Where packages have gone wrong for us</strong></p></div>
<ul>
<li>Script detection has to write to STDOUT <em>and</em> exit 0. A script that exits 0 but writes nothing counts as not detected. Write the result with <code>Write-Output</code>, and exit non-zero when the app is missing. This one is easy to forget.</li>
<li>"Installed successfully but not detected" means the install worked and the detection rule is wrong. Usually it's the wrong registry view (32-bit vs 64-bit), a version string that doesn't compare the way you expect, or a path that differs on some machines.</li>
<li>Depending on how the command is launched, a wrapper can end up running in 32-bit PowerShell, where <code>System32</code> and the registry are redirected. If your script needs the 64-bit view, launch it explicitly with <code>%windir%\Sysnative\WindowsPowerShell\v1.0\powershell.exe</code> and test both paths.</li>
<li>Interactive installers hang until the install timeout. Test in SYSTEM context and make sure nothing prompts.</li>
<li>When a new version comes out, use supersedence instead of deploying two versions side by side with overlapping detection rules.</li>
</ul>
</div>
<p>When a deployment fails, I open <code>AppWorkload.log</code> before I change anything in the portal. It usually shows exactly what ran and what exit code came back.</p>]]></description><guid isPermaLink="false">7</guid><pubDate>Sun, 18 Oct 2026 20:17:39 +0000</pubDate></item><item><title>Hybrid-joined PCs that wouldn't auto-enroll in Intune, and the CA policy blocking our admins</title><link>https://wtmsp.com/topic/6-hybrid-joined-pcs-that-wouldnt-auto-enroll-in-intune-and-the-ca-policy-blocking-our-admins/</link><description><![CDATA[<p>If your domain-joined PCs are already hybrid-joined to Entra ID, one Group Policy setting will get them into Intune. The PC enrolls itself in the background with the signed-in user's Entra credentials, and nobody has to click anything. That's the theory. In practice we spent a long time on a handful of machines that refused to enroll, and every one of them was used by someone in IT. It turned out to be a Conditional Access policy. Below is the setup we use, how to check it, and how we tracked that problem down.</p>
<div class="ipsRichTextBox" data-i-background-color="blue"><div class="ipsRichTextBox__title"><p><strong>Confirm these before you start</strong></p></div>
<ul>
<li>Entra Connect (or Cloud Sync) configured for hybrid Entra join, with the computer OUs in sync scope.</li>
<li>Users licensed for Intune, directly or through a suite such as Microsoft 365 Business Premium or E3/E5.</li>
<li>The MDM user scope set in Entra ID so those users are allowed to enroll.</li>
<li>Windows 10/11 Pro, Enterprise or Education.</li>
<li>Group Policy administrative templates recent enough to include the MDM enrollment setting.</li>
</ul>
</div>
<h2>Make sure hybrid join actually works</h2>
<p>Auto-enrollment rides on hybrid join. If the device isn't hybrid-joined, nothing else here matters. On a test PC, signed in as a normal domain user, run this.</p>
<pre class="ipsCode" data-language="powershell">dsregcmd /status</pre>
<p>Under <strong>Device State</strong> you want <code>AzureAdJoined : YES</code> and <code>DomainJoined : YES</code>. Under <strong>SSO State</strong> you want <code>AzureAdPrt : YES</code>. If <code>AzureAdJoined</code> says NO, check that the computer object is in a synced OU, that the service connection point (SCP) is configured, and that the device can reach the Microsoft device registration endpoints. Also look the device up in Entra ID. It should show as "Microsoft Entra hybrid joined" with a registered date, not "Pending."</p>

<h2>MDM user scope and licensing</h2>
<p>In the Entra or Intune admin center, find the mobility (MDM and WIP) settings for Microsoft Intune and set the <strong>MDM user scope</strong> to All, or to Some with a group containing the people who sign in to these PCs. Leave the MAM scope alone unless you know you need it. Confirm those users have an Intune license and that your Windows enrollment restrictions allow Windows (MDM) enrollment.</p>

<h2>The GPO itself</h2>
<p>Create a GPO linked to the OU that holds the computers. Start with a test OU. Then set this.</p>
<pre class="ipsCode" data-language="plaintext">Computer Configuration
  &gt; Policies
    &gt; Administrative Templates
      &gt; Windows Components
        &gt; MDM
          &gt; Enable automatic MDM enrollment using default Azure AD credentials
              = Enabled
              Select Credential Type to Use: User Credential</pre>
<p>"User Credential" is the standard choice here. "Device Credential" exists for specific co-management and ConfigMgr scenarios, so don't pick it just because it sounds more convenient.</p>
<p>When the policy applies, Windows creates a scheduled task under <code>\Microsoft\Windows\EnterpriseMgmt</code> that tries to enroll on a recurring schedule. The next time a licensed, in-scope user signs in, the device enrolls.</p>

<h2>Kick it and watch</h2>
<pre class="ipsCode" data-language="powershell">gpupdate /force
# Confirm the policy landed
gpresult /r /scope computer
# Confirm the enrollment task exists
Get-ScheduledTask -TaskPath "\Microsoft\Windows\EnterpriseMgmt\*" | Select-Object TaskName, State</pre>
<p>Sign out and back in as a normal user, give it a few minutes, and then check.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>Signs it enrolled</strong></p></div>
<ul>
<li>In <code>dsregcmd /status</code>, the Tenant Details section should have <code>MdmUrl</code> filled in. Once enrolled, the device shows up in the Intune device list as co-managed or Intune-managed.</li>
<li>In Event Viewer, open Applications and Services Logs &gt; Microsoft &gt; Windows &gt; DeviceManagement-Enterprise-Diagnostics-Provider &gt; Admin. Event ID 75 means auto-enrollment succeeded. Event ID 76 means it failed, and the event includes an error code.</li>
<li>In Settings, Accounts &gt; Access work or school shows the work account with an "Info" button that lists the MDM sync status.</li>
</ul>
<p>If you'd rather pull those events with PowerShell:</p>
<pre class="ipsCode" data-language="powershell">Get-WinEvent -LogName "Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin" -MaxEvents 50 |
  Where-Object { $_.Id -in 75,76 } |
  Format-Table TimeCreated, Id, Message -Wrap</pre>
</div>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>The machines that never enrolled</strong></p></div>
<p>We proved this one the hard way. Most of the fleet enrolled fine, but a set of machines kept logging event 76. Every one was used by an IT staffer signing in with an account that held an admin role. Regular users on identical hardware, in the same OU with the same GPO, enrolled without any trouble.</p>
<p>Background auto-enrollment requests its token <strong>non-interactively</strong>. There's no prompt, so there's no way to answer an MFA challenge. Our tenant had a Conditional Access policy requiring MFA for users in admin roles, so for those accounts CA blocked the token request, and the enrollment task just failed and retried forever.</p>
<p>It took a while to find because the default sign-in logs view in Entra shows <em>interactive</em> sign-ins, and those looked clean. Switch to <strong>non-interactive user sign-ins</strong>, filter on the affected user, and look for failures from the application <strong>Device Management Client</strong>. The Conditional Access tab on that sign-in tells you which policy blocked it.</p>
</div>
<h2>What we did about it</h2>
<p>Here are the options in the order I'd pick them.</p>
<ol>
<li>Stop signing in to workstations with admin accounts. Give IT staff a normal daily account for their PC and keep privileged roles on separate accounts. The device then enrolls under the normal user, and your admin accounts keep their MFA requirement. This is the one I push for.</li>
<li>If you really have to, make a narrow exclusion. Adjust the CA policy so only the enrollment resource shown in the failed sign-in is excluded, and nothing broader. Don't exclude the admins from MFA entirely. Review the change with whoever owns your CA policies and test it with the What If tool.</li>
<li>Enroll the affected devices once with a non-admin user, then change the primary user later if you need to.</li>
</ol>
<p>If you manage several tenants, check each one for a similar admin-MFA policy before you roll this out. I'd assume it's there until you've looked.</p>

<h2>A few smaller ones</h2>
<ul>
<li>Users with a non-routable UPN like <code>@contoso.local</code> can't authenticate to Entra properly. The UPN has to match a verified domain.</li>
<li>A device that's already MDM-enrolled somewhere else (another tenant or a previous MDM) will fail until you clean that up.</li>
<li>A device reimaged with the same name can have a stale Entra object. Delete the stale object and let it re-register.</li>
<li>Sync cycles, the scheduled task interval and policy refresh all add delay. On a big rollout, give it a day before you start chasing ghosts.</li>
</ul>]]></description><guid isPermaLink="false">6</guid><pubDate>Sun, 18 Oct 2026 20:16:39 +0000</pubDate></item></channel></rss>
