Friday, 25 July 2025

Windows 11 Upgrade with Intune: Prerequisites and Troubleshooting

 As Microsoft ends support for Windows 10 in October 2025, organizations must start preparing to upgrade their Windows 10 devices to Windows 11. Devices that do not meet the hardware requirements for Windows 11 must either be replaced or covered under an Extended Security Update (ESU) program, which will come at an added cost.

This guide will walk you through the upgrade readiness, hardware prerequisites, known compatibility issues, and how to troubleshoot feature upgrade deployments using Microsoft Intune.


⚙️ Upgrade Options

Organizations have three primary choices moving forward:

  1. Upgrade to Windows 11 – For supported hardware.
  2. Replace hardware – Devices that do not meet Windows 11 requirements.
  3. Purchase ESU (Extended Security Updates) – For legacy systems that must remain on Windows 10.

Windows 11 Hardware Requirements

To ensure a smooth upgrade to Windows 11, devices must meet the following minimum system requirements:

  • RAM: 4 GB or more
  • Storage: 64 GB or more
  • Firmware: UEFI capable with Secure Boot enabled
  • TPM: Trusted Platform Module (TPM) version 2.0
  • CPU: 8th Gen Intel or newer (Note: Devices purchased before 2017 are likely unsupported)

💡 Tip: Use Intune’s Windows 11 readiness report under:

Reports → Endpoint Analytics → Work from anywhere → Windows 11 readiness

This will help you quickly identify unsupported devices.


⚠️ Application Compatibility and Known Issues

1. Credential Guard Impact on MSCHAPv2-Based Wi-Fi

  • Issue: Breaks traditional MSCHAPv2 authentication (common in enterprise WPA2).
  • Workaround: Migrate to EAP-TLS using Intune to deploy PKCS or SCEP-based certificates.

2. Memory Integrity and Driver Incompatibility

  • Issue: Memory Integrity (HVCI) can block old or unsigned drivers, causing blue screen errors (BSOD) or app failures.
  • Solution: Update or replace legacy drivers before enabling Memory Integrity.

📊 Intune Reports to Review Before Upgrading

Before deploying the Windows 11 Feature Upgrade policy, review the following reports in Intune:

  1. Windows feature update device readiness
  2. Windows feature update compatibility risks

If the device does not appear in these reports or is flagged with compatibility risks, upgrading via Intune may fail or remain in an “offering” state.


🧰 Troubleshooting Windows 11 Feature Upgrade Failures with SetupDiag

If an upgrade appears to stall or fail, Microsoft’s SetupDiag tool is your best diagnostic resource.

Use On-Demand Remediation Scripts via Intune

Create a Proactive Remediation script in Intune to automate SetupDiag log collection. Here's a sample PowerShell script you can deploy:

🔧 Remediation Script Sample – Collect SetupDiag Logs

# Remediation Script to run SetupDiag and collect logs

$setupDiagUrl = "https://aka.ms/SetupDiag"

$destination = "$env:ProgramData\SetupDiag"

 

# Create directory if not exists

if (!(Test-Path -Path $destination)) {

    New-Item -ItemType Directory -Path $destination -Force

}

 

# Download SetupDiag.exe

Invoke-WebRequest -Uri $setupDiagUrl -OutFile "$destination\SetupDiag.exe"

 

# Run SetupDiag and save logs

Start-Process -FilePath "$destination\SetupDiag.exe" -ArgumentList "/Output:$destination\SetupDiagResults.xml" -Wait

 

# Optional: Copy logs to network share (example path)

# Copy-Item -Path "$destination\SetupDiagResults.xml" -Destination "\\yourfileserver\logs\$env:COMPUTERNAME.xml"

Detection Script Sample – Check if SetupDiag Log Exists


$logPath = "$env:ProgramData\SetupDiag\SetupDiagResults.xml"

 

if (Test-Path -Path $logPath) {

    Write-Output "SetupDiag log exists."

    exit 0

} else {

    Write-Output "SetupDiag log missing."

    exit 1

}

How to Deploy in Intune:

  1. Go to Endpoint Security → Proactive Remediations.
  2. Create a new script package.
  3. Upload the detection and remediation scripts.
  4. Assign it to the target device group.
  5. Review the execution status in Intune > Reports.

Once logs are collected, open the .xml file and review the blockers or compatibility errors (e.g., drivers, apps, or TPM issues) that caused upgrade failures.


🚀 Force Windows 11 24H2 Upgrade via PowerShell

If the device is eligible and the upgrade is still not applying, you can use the following script to force the 24H2 Windows 11 upgrade:

🔗 GitHub: Force Windows 11 24H2 Update Script

This script is ideal for:

  • Remote remediation
  • One-time on-demand upgrade
  • Skipping upgrade delays in Windows Update for Business (WUfB)

📝 Summary Table

Area

Details

Deadline

Windows 10 EOL: October 2025

Upgrade Options

Windows 11, New Hardware, or ESU Licensing

Pre-checks

Use Intune readiness and compatibility reports

Known Issues

Credential Guard Wi-Fi issues, Memory Integrity blocking old drivers

Troubleshooting Tool

SetupDiag + Intune remediation

Force Upgrade Script

GitHub: Windows 11 24H2 Upgrade Script


📌 Final Recommendations

  • Start auditing today with Intune readiness reports.
  • Replace or repurpose unsupported devices ahead of Q3 2025.
  • Pilot Windows 11 upgrades in phases using Feature Update Rings in Intune.
  • Use SetupDiag automation for ongoing upgrade issue visibility.
  • Communicate the upgrade strategy across the organization early.

Wednesday, 9 July 2025

SCCM SQL Query to Report Application Deployment Status Per Device

 

SCCM SQL Query to Report Application Deployment Status Per Device

In enterprise environments, monitoring application deployment results is crucial for ensuring successful software rollouts and troubleshooting failed installations. System Center Configuration Manager (SCCM) provides a rich set of SQL views that allow administrators to extract detailed deployment information.

This blog post walks through a powerful SQL query that retrieves comprehensive deployment status details for applications assigned to specific devices or users.


🔍 Purpose of the Query

The purpose of this query is to generate a detailed report that includes:

  • Device and user information
  • Operating System details
  • Assigned application and collection name
  • Deployment status (e.g., Success, In Progress, Error)
  • Last enforcement and compliance message timestamps

This helps administrators quickly determine the current state of application deployments across targeted machines.


📄 The SQL Query

SELECT DISTINCT

    vrs.Name0 AS [Computer Name],

    vgos.Caption0 AS [OS],

    vrs.User_Name0 AS [User Name],

    vrs.Ad_site_name0 AS [AD Site Name],

    lac.DisplayName AS [Application Name],

    CollectionName,

    IIF(

        vAppDeploymentResultsPerClient.EnforcementState = 1001, 'Installation Success',

        IIF(

            vAppDeploymentResultsPerClient.EnforcementState >= 1000 AND vAppDeploymentResultsPerClient.EnforcementState < 2000 AND vAppDeploymentResultsPerClient.EnforcementState <> 1001, 'Installation Success',

            IIF(

                vAppDeploymentResultsPerClient.EnforcementState >= 2000 AND vAppDeploymentResultsPerClient.EnforcementState < 3000, 'In Progress',

                IIF(

                    vAppDeploymentResultsPerClient.EnforcementState >= 3000 AND vAppDeploymentResultsPerClient.EnforcementState < 4000, 'Requirements Not Met',

                    IIF(

                        vAppDeploymentResultsPerClient.EnforcementState >= 4000 AND vAppDeploymentResultsPerClient.EnforcementState < 5000, 'Unknown',

                        IIF(

                            vAppDeploymentResultsPerClient.EnforcementState >= 5000 AND vAppDeploymentResultsPerClient.EnforcementState < 6000, 'Error',

                            'Unknown'

                        )

                    )

                )

            )

        )

    ) AS [Status],

    LastEnforcementMessageTime AS [LastEnfMessageTime],

    LastComplianceMessageTime AS [LastComMessageTime]

FROM dbo.v_R_System AS vrs

LEFT JOIN (dbo.vAppDeploymentResultsPerClient

    LEFT JOIN v_CIAssignment ON dbo.vAppDeploymentResultsPerClient.AssignmentID = v_CIAssignment.AssignmentID)

    ON vrs.ResourceID = dbo.vAppDeploymentResultsPerClient.ResourceID

LEFT JOIN dbo.fn_ListApplicationCIs(1033) lac ON lac.CI_ID = dbo.vAppDeploymentResultsPerClient.CI_ID

LEFT JOIN dbo.v_GS_WORKSTATION_STATUS AS vgws ON vgws.ResourceID = vrs.ResourceID

LEFT JOIN v_FullCollectionMembership coll ON coll.ResourceID = vrs.ResourceID

LEFT JOIN dbo.v_GS_OPERATING_SYSTEM AS vgos ON vgos.ResourceID = vrs.ResourceID

LEFT JOIN v_CICurrentComplianceStatus ci2 ON ci2.CI_ID = vAppDeploymentResultsPerClient.CI_ID AND ci2.ResourceID = vrs.ResourceID

WHERE

    vAppDeploymentResultsPerClient.AssignmentID IN ('ID') AND

    vrs.Name0 IN ('User Name') AND

    CollectionName = 'Collection'


🔧 Query Breakdown

  • v_R_System (vrs): Core system view providing details like computer name, user name, and AD site.
  • vAppDeploymentResultsPerClient: Contains application deployment status per client.
  • fn_ListApplicationCIs(1033): Retrieves application names based on configuration item (CI) IDs.
  • v_GS_OPERATING_SYSTEM (vgos): Provides OS information of the client.
  • v_CIAssignment: Stores deployment assignment details.
  • v_CICurrentComplianceStatus: Shows compliance status for the CI.
  • v_FullCollectionMembership: Maps devices to their collections.

📊 Deployment Status Mapping

Enforcement State Range

Status Description

= 1001

Installation Success

1000–1999 (≠1001)

Installation Success

2000–2999

In Progress

3000–3999

Requirements Not Met

4000–4999

Unknown

5000–5999

Error

Other

Unknown


🎯 Use Case Scenario

This query is useful when you want to:

  • Audit application deployment success/failure
  • Troubleshoot issues in a specific device or collection
  • Generate deployment compliance reports
  • Identify pending or in-progress installations

Simply replace the following placeholders in the WHERE clause:

  • 'ID' → Your application deployment AssignmentID
  • 'User Name' → List of device names or users
  • 'Collection' → Target SCCM collection name

📝 Final Notes

  • Ensure that you run this query in the SCCM database context (typically CM_<SiteCode>).
  • Add additional filters or joins (like deployment types or deadlines) based on your reporting needs.
  • You can export this data to Power BI or Excel for further visualization.

Tuesday, 1 July 2025

SQL Script to List SCCM Applications Details



📘 Overview

In SCCM (Microsoft Endpoint Configuration Manager), gaining a clear view of your applications, their deployment types, source content, and install/uninstall behaviors is critical for maintaining a healthy environment. Whether you are auditing your environment, troubleshooting deployment issues, or preparing for a migration, having a detailed application inventory is a must.

In this blog post, we’ll walk through a powerful SQL query that pulls application metadata, deployment information, content size, install/uninstall commands, and more — directly from your SCCM database.


🔍 What This Query Does

This SQL query retrieves:

  • Application name and description
  • Deployment type details
  • Source path and size
  • Status (Active/Retired)
  • Install and uninstall command lines
  • Detection method
  • Admin comments and metadata

All tied together using SCCM’s AppModel and CI relationships.


📋 The SQL Query

DECLARE @LocaleID INT = (SELECT LocaleID FROM vSMSData);

 

WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/SystemCenterConfigurationManager/2009/AppMgmtDigest')

SELECT

    app.DisplayName AS ApplicationName,

    pkg.PackageID,

    CASE

        WHEN dtt.IsExpired LIKE '1' THEN 'Retired'

        ELSE 'Active'

    END AS [Application Status],

    cp.SourceSize AS [Source Size in KB],

    app.Description,

    ad.AdminComments,

    Dtt.DisplayName AS [DeploymentTypeName],

    Dtt.Technology,

    dt.CI_ID,

    dt.SDMPackageDigest.value('(/AppMgmtDigest/DeploymentType/Title)[1]', 'nvarchar(max)') AS [DeploymentTypeName],

    ab.NumberOfDeploymentTypes AS [No of Deployments],

    dt.SDMPackageDigest.value('(/AppMgmtDigest/DeploymentType/Installer/Contents/Content/Location)[1]', 'nvarchar(max)') AS [SourcePath],

    dt.SDMPackageDigest.value('(/AppMgmtDigest/DeploymentType/Installer/InstallAction/Args/Arg)[1]', 'nvarchar(max)') AS [InstallCommandLine],

    dt.SDMPackageDigest.value('(/AppMgmtDigest/DeploymentType/Installer/UninstallAction/Args/Arg)[1]', 'nvarchar(max)') AS [UninstallCommandLine],

    dt.SDMPackageDigest.value('(/AppMgmtDigest/DeploymentType/DetectionMethod/Setting)[1]', 'nvarchar(max)') AS DetectionSetting

FROM v_ConfigurationItems dt

INNER JOIN vSMS_CIRelation rel ON dt.CI_ID = rel.ToCIID

INNER JOIN fn_ListLatestApplicationCIs_List(@LocaleID) app ON app.CI_ID = rel.FromCIID

INNER JOIN v_Package p ON p.SecurityKey = app.ModelName

INNER JOIN vSMS_ContentPackage cp ON cp.PkgID = p.PackageID

INNER JOIN dbo.Fn_Listdeploymenttypecis(1033) AS Dtt ON Dtt.AppModelName = app.ModelName

INNER JOIN fn_ListLatestApplicationCIs(1033) AS ab ON ab.ModelName = app.ModelName

INNER JOIN v_Package pkg ON pkg.SecurityKey = ab.ModelName

INNER JOIN v_Applications ad ON ad.ModelID = app.ModelID

WHERE dt.CIType_ID = 21 -- Deployment Type

  AND dt.IsLatest = 1;  -- Latest version only

 


Tuesday, 24 June 2025

SCCM Co-Management Workload Details and Remediation

 

With modern device management relying heavily on co-management, administrators often need insights into how workloads are being distributed between SCCM and Intune. Whether you're troubleshooting, auditing, or planning transitions, having visibility into co-management state is crucial.

In this post, we’ll explore three effective methods to view co-management workload details:

  1. Using SQL Query in SCCM
  2. Using PowerShell with Microsoft Graph
  3. Using the Intune Admin Console

1️ Method 1: View Co-Management Workloads Using SQL Query in SCCM

If you're using SQL Server Reporting Services (SSRS) or the SQL Management Studio, you can run the following query to fetch device-level co-management details:

sql

CopyEdit

SELECT

    s.Netbios_Name0 AS [Computer Name],

    s.Is_Virtual_Machine0,

    s.Client0,

    s.User_Name0,

    c.MDMEnrolled,

    c.MDMWorkloads,

    c.HybridAADJoined,

    c.MDMProvisioned

FROM

    v_R_System s

JOIN

    v_ClientCoManagementState c ON c.ResourceID = s.ResourceID

FULL JOIN

    v_FullCollectionMembership fcm ON s.ResourceID = fcm.ResourceID

WHERE

    fcm.CollectionID = 'collectionID'

This query returns details such as:

  • Whether the device is enrolled in MDM
  • Hybrid Azure AD Join status
  • Which co-management workloads are offloaded to Intune

📌 Reference Workload Values:
For interpreting the MDMWorkloads values, refer to this SystemCenterDudes reference. Each workload corresponds to a specific bitwise value (e.g., 1 = Compliance Policies, 2 = Resource Access, etc.).


2️ Method 2: View Co-Management Status via PowerShell & Microsoft Graph

You can also use PowerShell with Microsoft Graph API to pull co-management details from Intune directly.

🔧 Prerequisites:

  • Azure AD App registration with Graph permissions
  • Certificate-based authentication

📜 PowerShell Script:

powershell

CopyEdit

# Connect to Microsoft Graph

Connect-MgGraph -ClientId '<Client_ID>' -TenantId '<Tenant_ID>' -CertificateThumbprint '<Cert_Thumbprint>'

 

# Get workload status

$workloadStatus = Invoke-MgGraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/deviceManagement/managedDevices'

 

# Display relevant details

$workloadStatus | Select-Object id, deviceName, operatingSystem, complianceState

This will return:

  • Device name
  • OS version
  • Compliance state
  • Managed status (Hybrid, MDM, etc.)

This is useful when you want real-time data or wish to automate reports via scripts.


3️ Method 3: Use Intune Admin Console – Cloud Attach Detail Report

If you prefer a visual interface, Microsoft Intune provides built-in reporting for co-management.

📍 Steps:

  1. Go to the Intune Admin Center: https://intune.microsoft.com
  2. Navigate to:
    Reports
    ➡️ Cloud Attach ➡️ Cloud Attach Detail Preview
  3. Filter by Co-Managed Workloads

This report gives you a snapshot of which workloads are managed by Intune or ConfigMgr for each device.

SCCM Remediation Script – Fix WMI, Client, and Trigger Workloads

When devices are not reporting co-management workload changes, it's often due to WMI corruption or failed client components. This PowerShell script can be deployed as a SCCM Remediation Script or run manually to fix common issues.

📜 Full PowerShell Script

<#

Script Name: Remediate - StateMsg WMI Status

Description: Fixes WMI issues, repairs SCCM client, and triggers co-management workload baselines.

#>

 

# Step 1: Validate StateMsg WMI namespace

$wmiObject = Get-WmiObject -Namespace root\ccm\StateMsg -Query "SELECT * FROM CCM_StateMsg WHERE TopicType='401'"

if ($wmiObject) {

    Write-Host " StateMsg is working"

} else {

    try {

        Start-Process -FilePath "C:\windows\ccm\ccmrepair.exe" -Wait

        Write-Host "⚙️ StateMsg not working, ran ccmrepair.exe"

    } catch {

        Write-Host " StateMsg not working, ccmrepair.exe failed"

    }

}

 

# Step 2: Define function to trigger baseline evaluation

function Invoke-CoMgmtBaselineEvaluation {

    param (

        [string]$BaselineName

    )

    Write-Host "🔎 Looking for baseline: $BaselineName"

    $instance = Get-WmiObject -Namespace root\ccm\dcm -Query "SELECT * FROM SMS_DesiredConfiguration WHERE DisplayName = '$BaselineName'"

    if ($instance) {

        Write-Host "🚀 Triggering evaluation for: $BaselineName"

        Invoke-CimMethod -Namespace root\ccm\dcm -ClassName SMS_DesiredConfiguration -MethodName TriggerEvaluation -Arguments @{

            "Name"       = $instance.Name

            "Version"    = $instance.Version

            "PolicyType" = $instance.PolicyType

        }

    } else {

        Write-Warning "⚠️ Baseline '$BaselineName' not found. Ensure it's deployed to this client."

    }

}

 

# Step 3: Trigger standard client actions

$triggerSchedules = @{

    "Machine Policy Retrieval & Evaluation Cycle" = "{00000000-0000-0000-0000-000000000021}"

    "Application Deployment Evaluation Cycle"     = "{00000000-0000-0000-0000-000000000113}"

    "Software Updates Deployment Evaluation"      = "{00000000-0000-0000-0000-000000000114}"

    "Software Update Scan Cycle"                  = "{00000000-0000-0000-0000-000000000026}"

    "State Message Refresh Cycle"                 = "{00000000-0000-0000-0000-000000000121}"

}

foreach ($cycle in $triggerSchedules.GetEnumerator()) {

    Write-Host " Triggering $($cycle.Key)..."

    Invoke-WmiMethod -Namespace root\ccm -Class sms_client -Name TriggerSchedule -ArgumentList $cycle.Value

    Start-Sleep -Seconds 10

}

 

# Step 4: Evaluate co-management workload baselines

$baselineList = @(

    "CoMgmtSettingsPilotWUP",

    "CoMgmtSettingsPilotO365",

    "CoMgmtSettingsPilotCApp",

    "CoMgmtSettingsPilotCP",

    "CoMgmtSettingsPilotDC",

    "CoMgmtSettingsPilotDiskEncryption",

    "CoMgmtSettingsPilotEP",

    "CoMgmtSettingsPilotRAP"

)

 

foreach ($baseline in $baselineList) {

    Invoke-CoMgmtBaselineEvaluation -BaselineName $baseline

}

💡 How to Use:

  • Deploy via SCCM Remediation Script for proactive healing
  • Use as a manual fix tool during support scenarios
  • Schedule it via Configuration Baseline or Task Scheduler on problematic systems

🧠 Final Thoughts

With hybrid environments becoming the norm, keeping your co-managed devices healthy and correctly reporting is more important than ever. Combine visibility (via SQL, Graph, and Console) with proactive remediation (via PowerShell) to stay ahead of issues.

SQL = Detailed backend insight
PowerShell = Scripting/automation flexibility
Intune Console = Simple, visual reporting
Remediation Script = Fixes it all!

Wednesday, 11 June 2025

BitLocker Remediation Script for SCCM & Intune

 

This blog walks you through a PowerShell script that automates BitLocker encryption, validates TPM status, and logs all activity to a file—perfect for automated deployments via SCCM, Intune, or GPO.


Key Features of the Script

  • 🔍 Checks TPM presence and status
  • 🔐 Verifies BitLocker encryption and protection status
  • 🔄 Enables encryption and protection if required
  • ☁️ Backs up BitLocker recovery keys to Azure AD
  • 📃 Logs actions with timestamps and severity levels

🧩 PowerShell Script Breakdown

Below is the complete PowerShell script. You can save this as Enable-BitLocker.ps1 and deploy it as needed.

Function Get-LoggedInUser {

    [CmdletBinding()]

    param(

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]

        [string[]] $ComputerName = $env:COMPUTERNAME,

 

        [Parameter(Mandatory = $false)]

        [Alias("SamAccountName")]

        [string]   $UserName

    )

    PROCESS {

        foreach ($Computer in $ComputerName) {

            try {

                $Computer = $Computer.ToUpper()

                $SessionList = quser /Server:$Computer 2>$null

                if ($SessionList) {

                    $UserInfo = foreach ($Session in ($SessionList | select -Skip 1)) {

                        $Session = $Session.ToString().trim() -replace '\s+', ' ' -replace '>', ''

                        if ($Session.Split(' ')[3] -eq 'Active') {

                            [PSCustomObject]@{

                                ComputerName = $Computer

                                UserName     = $session.Split(' ')[0]

                                SessionName  = $session.Split(' ')[1]

                                SessionID    = $Session.Split(' ')[2]

                                SessionState = $Session.Split(' ')[3]

                                IdleTime     = $Session.Split(' ')[4]

                                LogonTime    = $session.Split(' ')[5, 6, 7] -as [string] -as [datetime]

                            }

                        } else {

                            [PSCustomObject]@{

                                ComputerName = $Computer

                                UserName     = $session.Split(' ')[0]

                                SessionName  = $null

                                SessionID    = $session.Split(' ')[1]

                                SessionState = 'Disconnected'

                                IdleTime     = $Session.Split(' ')[3]

                                LogonTime    = $session.Split(' ')[4, 5, 6] -as [string] -as [datetime]

                            }

                        }

                    }

                    if ($PSBoundParameters.ContainsKey('Username')) {

                        $UserInfo | Where-Object {$_.UserName -eq $UserName}

                    } else {

                        $UserInfo | Sort-Object LogonTime

                    }

                }

            } catch {

                Write-Error $_.Exception.Message

            }

        }

    }

}

 

Function Out-LogFile {

    Param(

        [Parameter(Mandatory = $false)] $Text,

        $Mode,

        [Parameter(Mandatory = $false)][ValidateSet(1, 2, 3, 'Information', 'Warning', 'Error')]$Severity = 1

    )

 

    switch ($Severity) {

        'Information' {$Severity = 1}

        'Warning' {$Severity = 2}

        'Error' {$Severity = 3}

    }

 

    $clientpath = 'C:\Windows'

    $Logfile = "$clientpath\temp\BitlockerAzure.log"

 

    foreach ($item in $text) {

        $item = '<![LOG[' + $item + ']LOG]!>'

        $time = 'time="' + (Get-Date -Format HH:mm:ss.fff) + '+000"'

        $date = 'date="' + (Get-Date -Format MM-dd-yyyy) + '"'

        $component = 'component="BitlockerScript"'

        $context = 'context=""'

        $type = 'type="' + $Severity + '"'

        $thread = 'thread="' + $PID + '"'

        $file = 'file=""'

        $logblock = ($time, $date, $component, $context, $type, $thread, $file) -join ' '

        $logblock = '<' + $logblock + '>'

        $item + $logblock | Out-File -Encoding utf8 -Append $logFile

    }

}

 

function Get-TPMStatus {

    try {

        $tpm = Get-WmiObject -Namespace "Root\CIMv2\Security\MicrosoftTpm" -Class Win32_Tpm

        if ($tpm) {

            if ($tpm.IsEnabled -eq $false) {

                return "TPM is turned off"

            } elseif ($tpm.IsPresent -eq $false) {

                return "No TPM present"

            } else {

                return "TPM is enabled"

            }

        } else {

            return "No TPM information available"

        }

    } catch {

        return "Error retrieving TPM status"

    }

}


 

💡 Deployment Tips

  • Run as Administrator – TPM and BitLocker commands require elevated privileges.
  • Log Review – Review C:\Windows\Temp\BitlockerAzure.log for audit and debugging.
  • Use with Intune or Task Scheduler for zero-touch deployments.
  • Test on a VM or staging environment before deploying widely.

Windows 11 Upgrade with Intune: Prerequisites and Troubleshooting

  As Microsoft ends support for Windows 10 in October 2025 , organizations must start preparing to upgrade their Windows 10 devices to Windo...