Since the 24H2 broad rollout resumed in Q2 2026 for enterprise rings, we've triaged this ticket pattern across four separate tenants: Company Portal.exe vanishes from the Start Menu, taskbar pins go dead, and the affected user can no longer self-remediate compliance issues — because the tool that reports compliance is the thing that's missing. If you're running Autopatch or staged feature update rings and you've seen a spike in "Company Portal not found" tickets correlating with 23H2→24H2 upgrades since mid-2026, this is your root cause map and remediation kit.
deviceCompliant and your compliance evaluation UX relies on the user opening Company Portal to trigger re-check-in, a missing CP binary creates a chicken-and-egg lockout: the device is flagged non-compliant, the user has no way to force re-evaluation, and they're blocked from Exchange/SharePoint until an admin intervenes remotely.
The Three-Stage Failure Chain
Company Portal loss on 24H2 isn't one bug — it's three independent failure modes that share a common trigger (the in-place feature update image apply) and get conflated in ticket queues because the symptom is identical. Triage requires branching, not a single fix-all script.
Root Cause 1: Per-User AppX Loss (the most common — 70%+ of tickets)
The overwhelming majority of these tickets trace back to how Company Portal was originally deployed. If it was pushed as a Store app or MSIX assigned to User context rather than a genuinely provisioned all-users package, the 24H2 image-apply process can leave the package binaries on disk but drop the per-user registration record. Get-AppxPackage for that user comes back empty or shows Status: NotAvailable, while Get-AppxProvisionedPackage -Online still shows the provisioned entry — because provisioning and per-user registration are tracked independently in the AppX deployment database, and 24H2's servicing stack changes don't reliably replay the registration step for every existing profile.
Get-AppxPackage -AllUsers -Name Microsoft.CompanyPortal | Select Name, PackageFullName, Status, InstallLocation before touching anything. If InstallLocation is empty, this isn't a registration problem — the package itself is gone and needs a full Intune redeploy, not a re-register.
Root Cause 2: Store for Business Deprecation Debt
Microsoft retired the Store for Business/Education sync connector in 2023, but plenty of tenants never migrated their private line-of-business or Store-sourced app assignments off it — they just stopped touching that blade. If Company Portal (or a wrapper policy referencing it) was ever synced through that connector, the underlying licensing/content source metadata is now stale. Post-24H2, when the device re-evaluates app assignments during the OOBE-adjacent policy refresh, the app source resolution fails silently: no error surfaces in the console, the assignment just sits at Not applicable indefinitely.
Tenant administration > Connectors and tokens > Microsoft Store for Business. If a connector still exists and shows a last-sync date, any app record originally ingested through it should be treated as suspect and manually re-added as a native Store app (new) or Win32/MSIX LOB package.
Root Cause 3: MDM Certificate Re-enrollment / Detection Rule Mismatch
Least common, but nastiest to diagnose because it looks identical from the user's chair. During a feature update, the device's MDM enrollment certificate can be silently renewed as part of the post-upgrade device attestation flow. This forces a full app assignment re-evaluation cycle in IME. If Company Portal was ever packaged as a Win32 app (some tenants do this deliberately to control versioning outside Store cadence) with a detection rule keyed to a specific registry value or MSI product code that changed between CP builds, the re-evaluation reads "not detected," uninstalls the stale record, and the reinstall fails against the same broken detection logic — an infinite fail loop that never surfaces as a hard error in Company Portal app status, just perpetually cycling between Install command line failed and Pending.
Detection & Remediation: The Four Scripts
Ad-hoc fixes don't scale past a handful of tickets. Below is the full kit we run in production: a Proactive Remediation pair for the self-healing device-side fix, a bulk diagnostic for identifying the blast radius tenant-wide, and a Graph SDK v2 script for triggering bulk sync once you've isolated the affected cohort.
Script 1 — Detection (Proactive Remediation, runs as SYSTEM)
Devices > Scripts and remediations > Create. Run as System, not signed-in user — Company Portal registration state must be evaluated per logged-on user profile, but SYSTEM context lets you enumerate -AllUsers without triggering per-user script execution overhead across every session.
# Detect-CompanyPortalRegistration.ps1
# Purpose: Proactive Remediation DETECTION script
# Context: SYSTEM
# Exit 0 = healthy (no remediation needed) | Exit 1 = remediation required
$ErrorActionPreference = 'Stop'
$logPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\CP-Detect.log"
function Write-Log {
param([string]$Message)
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logPath -Value "[$ts] $Message" -ErrorAction SilentlyContinue
}
try {
Write-Log "=== Detection run started ==="
# Step 1: Confirm the package exists at all (provisioned or per-user)
$provisioned = Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -eq 'Microsoft.CompanyPortal' }
$userPkg = Get-AppxPackage -AllUsers -Name 'Microsoft.CompanyPortal' -ErrorAction SilentlyContinue
# Step 1: Confirm the package exists at all (provisioned or per-user)
$provisioned = Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -eq 'Microsoft.CompanyPortal' }
$userPkg = Get-AppxPackage -AllUsers -Name 'Microsoft.CompanyPortal' -ErrorAction SilentlyContinue
# Case A: Missing entirely
if (-not $provisioned -and -not $userPkg) {
Write-Log "FAIL: Company Portal package is not provisioned or registered for any user."
Write-Output "Company Portal is missing entirely from this device."
exit 1
}
# Case B: Provisioned but missing registration for active/logged-on users
$loggedOnUsers = Get-CimInstance -ClassName Win32_LogonSession |
Where-Object { $_.LogonType -eq 2 } |
ForEach-Object {
Get-CimAssociatedInstance -InputObject $_ -ResultClassName Win32_Account -ErrorAction SilentlyContinue
} |
Where-Object { $_.Name -and $_.Name -notmatch '^(SYSTEM|LOCAL SERVICE|NETWORK SERVICE|DefaultAccount|WDAGUtilityAccount)$' } |
Select-Object -ExpandProperty SID -Unique
if ($loggedOnUsers) {
foreach ($sid in $loggedOnUsers) {
$userSpecificPkg = Get-AppxPackage -User $sid -Name 'Microsoft.CompanyPortal' -ErrorAction SilentlyContinue
if (-not $userSpecificPkg -or $userSpecificPkg.Status -ne 'Ok') {
Write-Log "FAIL: Company Portal missing or unregistered for active user session SID: $sid"
Write-Output "Company Portal is provisioned but not registered for active user session."
exit 1
}
}
} elseif (-not $userPkg) {
Write-Log "WARN: No active interactive session, but no user registration exists on device."
Write-Output "Provisioned package exists but no user registrations found."
exit 1
}
Write-Log "PASS: Company Portal is properly provisioned and registered."
Write-Output "Company Portal registration is healthy."
exit 0
}
catch {
Write-Log "ERROR during detection: $($_.Exception.Message)"
Write-Output "Detection script error: $($_.Exception.Message)"
exit 1
}
Script 2 — Remediation (Proactive Remediation, runs as SYSTEM)
AppXManifest.xml from the provisioned package and triggers Add-AppxPackage -Register -AllUsers to restore profile bindings instantly without rebooting. If package files are missing from disk, it falls back to machine-scoped WinGet installation.
# Remediate-CompanyPortalRegistration.ps1
# Purpose: Proactive Remediation REMEDIATION script
# Context: SYSTEM
# Exit 0 = Successfully remediated | Exit 1 = Remediation failed
$ErrorActionPreference = 'Stop'
$logPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\CP-Remediate.log"
function Write-Log {
param([string]$Message)
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logPath -Value "[$ts] $Message" -ErrorAction SilentlyContinue
}
try {
Write-Log "=== Remediation run started ==="
# Step 1: Locate the staged Company Portal manifest on disk
$manifestPath = (Get-AppxProvisionedPackage -Online |
Where-Object { $_.DisplayName -eq 'Microsoft.CompanyPortal' } |
Select-Object -First 1).InstallLocation
if (-not $manifestPath) {
$windowsAppsDir = "$env:ProgramFiles\WindowsApps"
$cpFolder = Get-ChildItem -Path $windowsAppsDir -Filter "Microsoft.CompanyPortal_*" -Directory -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($cpFolder) {
$manifestPath = $cpFolder.FullName
}
}
if ($manifestPath -and (Test-Path "$manifestPath\AppXManifest.xml")) {
$xmlPath = "$manifestPath\AppXManifest.xml"
Write-Log "Found staged manifest at: $xmlPath"
# Re-register for All Users
Write-Log "Executing Add-AppxPackage registration..."
Add-AppxPackage -DisableDevelopmentMode -Register $xmlPath -AllUsers -ErrorAction Stop
Write-Log "AllUsers registration completed."
# Verify registration immediately
$verify = Get-AppxPackage -AllUsers -Name 'Microsoft.CompanyPortal' -ErrorAction SilentlyContinue
if ($verify) {
Write-Log "SUCCESS: Company Portal re-registered successfully."
Write-Output "Company Portal re-registered successfully across all profiles."
exit 0
}
}
# Step 2: Fallback — Trigger Windows Package Manager (winget) silent re-install via MS Store
Write-Log "Staged binary not found or registration failed. Attempting WinGet machine-level install..."
$wingetPath = (Get-ChildItem -Path "$env:ProgramFiles\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe\winget.exe" -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
if ($wingetPath -and (Test-Path $wingetPath)) {
Write-Log "Invoking winget: 9WZDNCRFJ3PZ"
$process = Start-Process -FilePath $wingetPath -ArgumentList "install --id 9WZDNCRFJ3PZ --source msstore --accept-package-agreements --accept-source-agreements --scope machine --silent" -Wait -PassThru -NoNewWindow
if ($process.ExitCode -eq 0) {
Write-Log "SUCCESS: WinGet installed Company Portal successfully."
Write-Output "Company Portal installed via Windows Package Manager."
exit 0
}
}
Write-Log "FAIL: Unable to remediate Company Portal registration."
Write-Output "Remediation failed. Manual intervention or Intune redeploy required."
exit 1
}
catch {
Write-Log "ERROR in remediation: $($_.Exception.Message)"
Write-Output "Remediation error: $($_.Exception.Message)"
exit 1
}
Script 3 — Fleet Diagnostic & Blast Radius Assessment
Run this script via Intune Run Script or Live Response to identify which endpoints are currently at risk or missing Company Portal registrations following 24H2 enablement:
# Test-FleetCompanyPortalHealth.ps1
# Purpose: Diagnostic script to inventory Company Portal health across endpoints
# Context: Evaluates OS build, provisioned package presence, and registered profile counts
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
$buildNumber = [int]$osInfo.BuildNumber
$provisioned = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq 'Microsoft.CompanyPortal' }
$allUserPkg = Get-AppxPackage -AllUsers -Name 'Microsoft.CompanyPortal'
$report = [PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
OSVersion = $osInfo.Caption
OSBuild = $buildNumber
Is24H2OrLater = ($buildNumber -ge 26100)
IsProvisioned = [bool]$provisioned
ProvisionedVersion = $provisioned.Version
RegisteredUsers = ($allUserPkg | Select-Object -ExpandProperty PackageUserInformation -ErrorAction SilentlyContinue).Count
HealthStatus = if ($provisioned -and $allUserPkg) { "Healthy" } elseif ($provisioned) { "Unregistered Profile (At Risk)" } else { "Missing Entirely" }
}
$report | Format-List
Script 4 — Graph API Bulk Fleet Policy Sync
Once your Proactive Remediation or WinGet app policy is assigned in Intune, trigger an expedited sync across all 24H2 endpoints using the Microsoft Graph PowerShell SDK v2:
# Invoke-IntuneFleetSync24H2.ps1
# Purpose: Force immediate policy check-in across Windows 11 24H2 devices via Graph SDK
# Required Scope: DeviceManagementManagedDevices.ReadWrite.All
Connect-MgGraph -Scopes "DeviceManagementManagedDevices.ReadWrite.All" -NoWelcome
Write-Host "Querying Windows 11 24H2 devices (Build 26100+)..." -ForegroundColor Cyan
$devices = Get-MgDeviceManagementManagedDevice -Filter "operatingSystem eq 'Windows' and startsWith(osVersion, '10.0.26100')" -All
Write-Host "Found $($devices.Count) target 24H2 device(s)." -ForegroundColor Green
foreach ($dev in $devices) {
Write-Host "Triggering sync on $($dev.DeviceName) ($($dev.Id))..." -NoNewline
try {
Sync-MgDeviceManagementManagedDevice -ManagedDeviceId $dev.Id -ErrorAction Stop
Write-Host " [TRIGGERED]" -ForegroundColor Green
}
catch {
Write-Host " [FAILED: $($_.Exception.Message)]" -ForegroundColor Red
}
}
2. Deploy Scripts 1 & 2 via Proactive Remediations targeting all Windows 11 devices.
3. Audit your fleet with Script 3 and force policy convergence with Script 4 to clear non-compliant Conditional Access states.