Kris Mandemaker

Kris Mandemaker

Senior Workspace Consultant @ Mand-IT

I'm a freelance Senior Workspace Consultant operating as Mand-IT, based in Alkmaar, Netherlands.

My day job centres on the Microsoft ecosystem — Intune, Entra ID, Azure Virtual Desktop, and modern workplace design.

Sherlog is a side project — I spend a lot of time digging through Intune Management Extension logs and wanted the timeline analysis and a CMTrace-style viewer one drag-and-drop away, right in the browser.

Troubleshoot a diagnostics package

Upload the IntuneDiag-*.zip produced by Collect-IntuneDiagnostics.ps1 and get device health checks, an automatic Win32App timeline and a browser for every file in the package.

Drag & drop the IntuneDiag-*.zip here, or choose files · choose a folder.

    .zip Max total upload: 100 MB

    Don't have a package yet?

    Run Collect-IntuneDiagnostics.ps1 in an elevated PowerShell on the device. It collects MDM logs, event logs, registry exports, identity/network info and the IME logs, and writes IntuneDiag-<device>-<timestamp>.zip to C:\Temp. Upload that zip above.

    Download Collect-IntuneDiagnostics.ps1

    View script source
    <#
    .SYNOPSIS
        Collects a complete diagnostics package from an Intune-managed Windows device.
    
    .DESCRIPTION
        Mimics the Intune "Collect diagnostics" action and extends it with:
        - MDM logs via mdmdiagnosticstool.exe (all registered areas)
        - Relevant Event Logs (MDM, Entra/AAD, Device Registration, ESP/Shell-Core)
        - Registry exports (Enrollments, PolicyManager, IME, Autopilot)
        - Identity status (dsregcmd), certificates, network info
        - Intune Management Extension (IME) logs
        - Defender support files, Windows Update logs, system reports
        - Status of relevant services and scheduled tasks
    
        Result: a single zip file in C:\Temp (or a custom path).
    
    .PARAMETER OutputPath
        Folder where the zip file will be created. Default: C:\Temp
    
    .EXAMPLE
        .\Collect-IntuneDiagnostics.ps1
        .\Collect-IntuneDiagnostics.ps1 -OutputPath D:\Diag
    
    .NOTES
        Run as Administrator (elevated PowerShell).
    #>
    
    [CmdletBinding()]
    param(
        [string]$OutputPath = 'C:\Temp'
    )
    
    # ============================================================
    # 0. Preparation
    # ============================================================
    
    # Admin check
    $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
               ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    if (-not $isAdmin) {
        Write-Error 'This script must be run as Administrator. Start an elevated PowerShell session and try again.'
        exit 1
    }
    
    $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
    $work      = Join-Path $OutputPath "IntuneDiag-$env:COMPUTERNAME-$timestamp"
    $zipFile   = "$work.zip"
    
    $folders = @('MDM','EventLogs','Registry','Identity','Network','Apps-IME','System','Defender','WindowsUpdate','Autopilot')
    foreach ($f in $folders) {
        New-Item -ItemType Directory -Path (Join-Path $work $f) -Force | Out-Null
    }
    
    $transcript = Join-Path $work 'CollectionTranscript.log'
    Start-Transcript -Path $transcript -Force | Out-Null
    
    function Write-Step { param([string]$Msg) Write-Host "[$(Get-Date -Format 'HH:mm:ss')] $Msg" -ForegroundColor Cyan }
    function Invoke-Safe {
        param([string]$Name, [scriptblock]$Action)
        Write-Step $Name
        try { & $Action } catch { Write-Warning "  Failed: $($_.Exception.Message)" }
    }
    
    # ============================================================
    # 1. MDM logs (mdmdiagnosticstool, all areas)
    # ============================================================
    Invoke-Safe 'MDM diagnostics (all areas)...' {
        $areaKey = 'HKLM:\SOFTWARE\Microsoft\MdmDiagnostics\Area'
        if (Test-Path $areaKey) {
            $areas = (Get-ChildItem $areaKey).PSChildName -join ';'
            Write-Host "  Areas found: $areas"
            & "$env:windir\system32\mdmdiagnosticstool.exe" -area $areas -zip (Join-Path $work 'MDM\MDMDiag-AllAreas.zip') | Out-Null
        }
        # Always also generate the default report (HTML + XML + registry dump)
        & "$env:windir\system32\mdmdiagnosticstool.exe" -out (Join-Path $work 'MDM\DefaultReport') | Out-Null
    }
    
    # ============================================================
    # 2. Event Logs
    # ============================================================
    $eventLogs = @{
        'DeviceManagement-Admin'      = 'Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin'
        'DeviceManagement-Operational'= 'Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Operational'
        'AAD-Operational'             = 'Microsoft-Windows-AAD/Operational'
        'UserDeviceRegistration'      = 'Microsoft-Windows-User Device Registration/Admin'
        'Shell-Core'                  = 'Microsoft-Windows-Shell-Core/Operational'
        'ModernDeployment-Autopilot'  = 'Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Autopilot'
        'ModernDeployment-Diagnostics'= 'Microsoft-Windows-ModernDeployment-Diagnostics-Provider/ManagementService'
        'Provisioning-Diagnostics'    = 'Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin'
        'CodeIntegrity'               = 'Microsoft-Windows-CodeIntegrity/Operational'
        'TaskScheduler'               = 'Microsoft-Windows-TaskScheduler/Operational'
        'Application'                 = 'Application'
        'System'                      = 'System'
    }
    
    foreach ($entry in $eventLogs.GetEnumerator()) {
        Invoke-Safe "Event log: $($entry.Key)..." {
            $dest = Join-Path $work "EventLogs\$($entry.Key).evtx"
            wevtutil epl $entry.Value $dest /ow:true 2>$null
            if (Test-Path $dest) {
                # Also create a readable text summary of errors/warnings (last 200 events)
                Get-WinEvent -LogName $entry.Value -MaxEvents 200 -ErrorAction SilentlyContinue |
                    Where-Object { $_.Level -in 1,2,3 } |
                    Select-Object TimeCreated, Id, LevelDisplayName, Message |
                    Format-List | Out-File (Join-Path $work "EventLogs\$($entry.Key)-ErrorsWarnings.txt") -Width 250
            }
        }
    }
    
    # ============================================================
    # 3. Registry exports
    # ============================================================
    $regKeys = @{
        'Enrollments'              = 'HKLM\SOFTWARE\Microsoft\Enrollments'
        'PolicyManager-Current'    = 'HKLM\SOFTWARE\Microsoft\PolicyManager\current'
        'PolicyManager-Providers'  = 'HKLM\SOFTWARE\Microsoft\PolicyManager\Providers'
        'IntuneManagementExtension'= 'HKLM\SOFTWARE\Microsoft\IntuneManagementExtension'
        'Win32Apps'                = 'HKLM\SOFTWARE\Microsoft\IntuneManagementExtension\Win32Apps'
        'Autopilot'                = 'HKLM\SOFTWARE\Microsoft\Provisioning\Diagnostics\AutoPilot'
        'Autopilot-EstablishedCorr'= 'HKLM\SOFTWARE\Microsoft\Provisioning\AutopilotSettings'
        'EnrollmentStatusTracking' = 'HKLM\SOFTWARE\Microsoft\Windows\Autopilot\EnrollmentStatusTracking'
        'FirstSync'                = 'HKLM\SOFTWARE\Microsoft\Windows\Autopilot'
        'CloudDomainJoin'          = 'HKLM\SYSTEM\CurrentControlSet\Control\CloudDomainJoin'
        'MDM-Uninstall'            = 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
        'InternetSettings'         = 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings'
    }
    
    foreach ($entry in $regKeys.GetEnumerator()) {
        Invoke-Safe "Registry: $($entry.Key)..." {
            reg export $entry.Value (Join-Path $work "Registry\$($entry.Key).reg") /y 2>$null | Out-Null
        }
    }
    
    # ============================================================
    # 4. Identity & certificates
    # ============================================================
    Invoke-Safe 'dsregcmd /status...' {
        dsregcmd /status | Out-File (Join-Path $work 'Identity\dsregcmd-status.txt')
    }
    
    Invoke-Safe 'Certificates (machine + user)...' {
        certutil -store MY  | Out-File (Join-Path $work 'Identity\certs-machine-MY.txt')
        certutil -store -user MY | Out-File (Join-Path $work 'Identity\certs-user-MY.txt')
    
        # Highlight the machine certificates, including the Intune MDM device cert
        Get-ChildItem Cert:\LocalMachine\My |
            Select-Object Subject, Issuer, NotBefore, NotAfter, Thumbprint, @{n='Expired';e={$_.NotAfter -lt (Get-Date)}} |
            Format-List | Out-File (Join-Path $work 'Identity\certs-machine-overview.txt')
    }
    
    # ============================================================
    # 5. Network
    # ============================================================
    Invoke-Safe 'Network configuration...' {
        ipconfig /all                          | Out-File (Join-Path $work 'Network\ipconfig.txt')
        netsh advfirewall show allprofiles     | Out-File (Join-Path $work 'Network\firewall-profiles.txt')
        netsh advfirewall show global          | Out-File (Join-Path $work 'Network\firewall-global.txt')
        netsh winhttp show proxy               | Out-File (Join-Path $work 'Network\winhttp-proxy.txt')
        netsh wlan show profiles               | Out-File (Join-Path $work 'Network\wlan-profiles.txt')
        route print                            | Out-File (Join-Path $work 'Network\routes.txt')
        Get-DnsClientServerAddress | Format-Table -AutoSize | Out-File (Join-Path $work 'Network\dns-servers.txt')
    }
    
    Invoke-Safe 'Connectivity test to Intune/Entra endpoints...' {
        $endpoints = @(
            'login.microsoftonline.com',
            'enterpriseregistration.windows.net',
            'enrollment.manage.microsoft.com',
            'portal.manage.microsoft.com',
            'fef.msuc03.manage.microsoft.com',
            'graph.microsoft.com'
        )
        $results = foreach ($ep in $endpoints) {
            $t = Test-NetConnection -ComputerName $ep -Port 443 -WarningAction SilentlyContinue
            [pscustomobject]@{
                Endpoint  = $ep
                Reachable = $t.TcpTestSucceeded
                RemoteIP  = $t.RemoteAddress
            }
        }
        $results | Format-Table -AutoSize | Out-File (Join-Path $work 'Network\endpoint-connectivity.txt')
    }
    
    # ============================================================
    # 6. Apps / Intune Management Extension
    # ============================================================
    Invoke-Safe 'Copying IME logs...' {
        $imeLogs = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs"
        if (Test-Path $imeLogs) {
            Copy-Item $imeLogs (Join-Path $work 'Apps-IME\Logs') -Recurse -Force
        }
    }
    
    Invoke-Safe 'IME service status...' {
        Get-Service -Name 'IntuneManagementExtension','Microsoft Intune Management Extension' -ErrorAction SilentlyContinue |
            Select-Object Name, Status, StartType |
            Format-Table -AutoSize | Out-File (Join-Path $work 'Apps-IME\service-status.txt')
    }
    
    Invoke-Safe 'Inventorying installed apps...' {
        $paths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
                 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
        Get-ItemProperty $paths -ErrorAction SilentlyContinue |
            Where-Object DisplayName |
            Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
            Sort-Object DisplayName |
            Format-Table -AutoSize | Out-File (Join-Path $work 'Apps-IME\installed-apps.txt') -Width 250
    }
    
    # ============================================================
    # 7. System
    # ============================================================
    Invoke-Safe 'msinfo32 report (this may take a while)...' {
        Start-Process msinfo32 -ArgumentList "/report `"$(Join-Path $work 'System\msinfo32.log')`"" -Wait
    }
    
    Invoke-Safe 'Drivers, battery, OS info...' {
        pnputil /enum-drivers | Out-File (Join-Path $work 'System\drivers.txt')
        powercfg /batteryreport /output (Join-Path $work 'System\battery-report.html') 2>$null
        Get-ComputerInfo | Out-File (Join-Path $work 'System\computerinfo.txt')
        Get-HotFix | Sort-Object InstalledOn -Descending |
            Format-Table -AutoSize | Out-File (Join-Path $work 'System\hotfixes.txt')
    }
    
    Invoke-Safe 'Relevant scheduled tasks...' {
        Get-ScheduledTask -TaskPath '\Microsoft\Windows\EnterpriseMgmt\*' -ErrorAction SilentlyContinue |
            Select-Object TaskPath, TaskName, State |
            Format-Table -AutoSize | Out-File (Join-Path $work 'System\enterprisemgmt-tasks.txt') -Width 250
    }
    
    # ============================================================
    # 8. Defender
    # ============================================================
    Invoke-Safe 'Defender support files...' {
        $mpcmd = "$env:ProgramFiles\Windows Defender\mpcmdrun.exe"
        if (Test-Path $mpcmd) {
            & $mpcmd -GetFiles | Out-Null
            Copy-Item "$env:ProgramData\Microsoft\Windows Defender\Support\MpSupportFiles.cab" `
                      (Join-Path $work 'Defender') -Force -ErrorAction SilentlyContinue
        }
        Get-MpComputerStatus -ErrorAction SilentlyContinue |
            Out-File (Join-Path $work 'Defender\mp-status.txt')
    }
    
    # ============================================================
    # 9. Windows Update
    # ============================================================
    Invoke-Safe 'Windows Update log (this may take a while)...' {
        Get-WindowsUpdateLog -LogPath (Join-Path $work 'WindowsUpdate\WindowsUpdate.log') -ErrorAction SilentlyContinue | Out-Null
        Copy-Item "$env:ProgramData\USOShared\Logs\System\*.etl" (Join-Path $work 'WindowsUpdate') -Force -ErrorAction SilentlyContinue
    }
    
    # ============================================================
    # 10. Autopilot / ESP extras
    # ============================================================
    Invoke-Safe 'Autopilot/ESP files...' {
        Copy-Item "$env:windir\Logs\Panther\unattendgc\setupact.log" (Join-Path $work 'Autopilot') -Force -ErrorAction SilentlyContinue
        Copy-Item "$env:ProgramData\Microsoft\Provisioning\*.log" (Join-Path $work 'Autopilot') -Force -ErrorAction SilentlyContinue
    }
    
    # ============================================================
    # 11. Generate summary
    # ============================================================
    Invoke-Safe 'Generating summary...' {
        $dsreg = dsregcmd /status
        $aadJoined  = ($dsreg | Select-String 'AzureAdJoined\s*:\s*(\w+)').Matches.Groups[1].Value
        $prt        = ($dsreg | Select-String 'AzureAdPrt\s*:\s*(\w+)').Matches.Groups[1].Value
        $mdmUrl     = ($dsreg | Select-String 'MdmUrl\s*:\s*(.+)').Matches.Groups[1].Value
    
        $imeService = (Get-Service -Name 'IntuneManagementExtension' -ErrorAction SilentlyContinue).Status
    
        $recentErrors = Get-WinEvent -LogName 'Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin' -MaxEvents 500 -ErrorAction SilentlyContinue |
            Where-Object Level -eq 2 |
            Select-Object -First 10 TimeCreated, Id, Message
    
        $summary = @"
    ==========================================================
     INTUNE DIAGNOSTICS SUMMARY
     Device : $env:COMPUTERNAME
     Date   : $(Get-Date)
     User   : $env:USERNAME
    ==========================================================
    
    [Identity]
      AzureAdJoined : $aadJoined
      AzureAdPrt    : $prt
      MDM URL       : $mdmUrl
    
    [Services]
      IntuneManagementExtension : $imeService
    
    [Last 10 MDM errors (DeviceManagement Admin log)]
    $($recentErrors | Format-List | Out-String)
    
    See the subfolders for all details:
      MDM\           - mdmdiagnosticstool output (HTML report, registry dump, evtx)
      EventLogs\     - evtx exports + errors/warnings as text
      Registry\      - Enrollments, PolicyManager, IME, Autopilot
      Identity\      - dsregcmd, certificates
      Network\       - ipconfig, proxy, firewall, endpoint connectivity
      Apps-IME\      - IME logs, app inventory
      System\        - msinfo32, drivers, hotfixes, scheduled tasks
      Defender\      - MpSupportFiles.cab, status
      WindowsUpdate\ - WindowsUpdate.log, USO etl files
      Autopilot\     - setupact.log, provisioning logs
    ==========================================================
    "@
        $summary | Out-File (Join-Path $work '_SUMMARY.txt')
        Write-Host $summary
    }
    
    # ============================================================
    # 12. Package everything
    # ============================================================
    Stop-Transcript | Out-Null
    
    Write-Step 'Packaging everything...'
    Compress-Archive -Path "$work\*" -DestinationPath $zipFile -Force
    Remove-Item $work -Recurse -Force
    
    Write-Host ''
    Write-Host "Done! Diagnostics package: $zipFile" -ForegroundColor Green