> ## Documentation Index
> Fetch the complete documentation index at: https://help.gorelo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Windows 11 compatible assets list

> Use Gorelo custom asset fields and tags to build a live list of Windows 11 compatible and incompatible assets so you can plan and target your upgrade work.

Here’s a way you can create a list of assets that are Windows 11 compatible or not.

<Steps>
  <Step title="Create the custom asset field.">
    1. Navigate to **Settings** > **Assets** > **[Custom Fields](https://app.gorelo.io/Admin/admin-settings#asset#assetcustomfields).**
    2. Add custom field with the following details:
       * **Name**: Windows 11 Compatibility
       * **Variable**: Windows11Compatibility

    <Frame>
      <img src="https://mintcdn.com/gorelo/l3kfLaTp3Zy4uEi2/images/image-123.png?fit=max&auto=format&n=l3kfLaTp3Zy4uEi2&q=85&s=ae2d0033969e351462bc447d983ecded" alt="Image" width="786" height="602" data-path="images/image-123.png" />
    </Frame>
  </Step>

  <Step title="Create the tag.">
    1. Navigate to **Settings** > **[Tags](https://app.gorelo.io/Admin/admin-settings#tagmanagementsettings).**
    2. Select **Asset Policy Tags** from the top.
    3. Click **Create an Assets Tag** down the bottom-left:
       * **Tag**: Win11Compatible
       * **Property**: Registry Key
       * **Condition**: Equals
       * **Path**: HKEY\_LOCAL\_MACHINE\SOFTWARE\Windows11Compatibility\Status
       * **Value**: Compatible
    4. Click **Save**.
    5. Click **Create an Assets Tag** down the bottom-left:
       * **Tag**: Win11NotCompatible
       * **Property**: Registry Key
       * **Condition**: Equals
       * **Path**: HKEY\_LOCAL\_MACHINE\SOFTWARE\Windows11Compatibility\Status
       * **Value**: NotCompatible
    6. Click **Save**.
    7. Click **Create an Assets Tag** down the bottom-left:
       * **Tag**: Win11CheckFailed
       * **Property**: Registry Key
       * **Condition**: Equals
       * **Path**: HKEY\_LOCAL\_MACHINE\SOFTWARE\Windows11Compatibility\Status
       * **Value**: CheckFailed
    8. Click **Save**.
  </Step>

  <Step title="Write the script">
    1. Navigate to **[Scripts](https://app.gorelo.io/Asset/script-list).**
    2. Create a script with the following details:
       * **Name**: Windows 11 Compatibility
       * **Content**:

    ```powershell theme={null}
    # Windows 11 Compatibility Check
    # Adapted from Microsoft's HardwareReadiness.ps1

    # Registry path and name
    $RegistryPath = "HKLM:\SOFTWARE\Windows11Compatibility"
    $RegistryName = "Status"

    # Function to write to registry
    function Write-Win11Registry {
        param(
            [string]$Status
        )
        
        try {
            # Create registry path if it doesn't exist
            if (!(Test-Path $RegistryPath)) {
                New-Item -Path $RegistryPath -Force | Out-Null
            }
            
            # Write the value
            New-ItemProperty -Path $RegistryPath -Name $RegistryName -Value $Status -PropertyType String -Force | Out-Null
        }
        catch {
            Write-Output "Failed to write to registry: $($_.Exception.Message)"
        }
    }

    $Source = @"
    using Microsoft.Win32;
    using System;
    using System.Runtime.InteropServices;

        public class CpuFamilyResult
        {
            public bool IsValid { get; set; }
            public string Message { get; set; }
        }

        public class CpuFamily
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct SYSTEM_INFO
            {
                public ushort ProcessorArchitecture;
                ushort Reserved;
                public uint PageSize;
                public IntPtr MinimumApplicationAddress;
                public IntPtr MaximumApplicationAddress;
                public IntPtr ActiveProcessorMask;
                public uint NumberOfProcessors;
                public uint ProcessorType;
                public uint AllocationGranularity;
                public ushort ProcessorLevel;
                public ushort ProcessorRevision;
            }

            [DllImport("kernel32.dll")]
            internal static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);

            public enum ProcessorFeature : uint
            {
                ARM_SUPPORTED_INSTRUCTIONS = 34
            }

            [DllImport("kernel32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool IsProcessorFeaturePresent(ProcessorFeature processorFeature);

            private const ushort PROCESSOR_ARCHITECTURE_X86 = 0;
            private const ushort PROCESSOR_ARCHITECTURE_ARM64 = 12;
            private const ushort PROCESSOR_ARCHITECTURE_X64 = 9;

            private const string INTEL_MANUFACTURER = "GenuineIntel";
            private const string AMD_MANUFACTURER = "AuthenticAMD";
            private const string QUALCOMM_MANUFACTURER = "Qualcomm Technologies Inc";

            public static CpuFamilyResult Validate(string manufacturer, ushort processorArchitecture)
            {
                CpuFamilyResult cpuFamilyResult = new CpuFamilyResult();

                if (string.IsNullOrWhiteSpace(manufacturer))
                {
                    cpuFamilyResult.IsValid = false;
                    cpuFamilyResult.Message = "Manufacturer is null or empty";
                    return cpuFamilyResult;
                }

                string registryPath = "HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0";
                SYSTEM_INFO sysInfo = new SYSTEM_INFO();
                GetNativeSystemInfo(ref sysInfo);

                switch (processorArchitecture)
                {
                    case PROCESSOR_ARCHITECTURE_ARM64:
                        if (manufacturer.Equals(QUALCOMM_MANUFACTURER, StringComparison.OrdinalIgnoreCase))
                        {
                            bool isArmv81Supported = IsProcessorFeaturePresent(ProcessorFeature.ARM_SUPPORTED_INSTRUCTIONS);

                            if (!isArmv81Supported)
                            {
                                string registryName = "CP 4030";
                                long registryValue = (long)Registry.GetValue(registryPath, registryName, -1);
                                long atomicResult = (registryValue >> 20) & 0xF;

                                if (atomicResult >= 2)
                                {
                                    isArmv81Supported = true;
                                }
                            }

                            cpuFamilyResult.IsValid = isArmv81Supported;
                            cpuFamilyResult.Message = isArmv81Supported ? "" : "Processor does not implement ARM v8.1 atomic instruction";
                        }
                        else
                        {
                            cpuFamilyResult.IsValid = false;
                            cpuFamilyResult.Message = "The processor isn't currently supported for Windows 11";
                        }
                        break;

                    case PROCESSOR_ARCHITECTURE_X64:
                    case PROCESSOR_ARCHITECTURE_X86:
                        int cpuFamily = sysInfo.ProcessorLevel;
                        int cpuModel = (sysInfo.ProcessorRevision >> 8) & 0xFF;
                        int cpuStepping = sysInfo.ProcessorRevision & 0xFF;

                        if (manufacturer.Equals(INTEL_MANUFACTURER, StringComparison.OrdinalIgnoreCase))
                        {
                            try
                            {
                                cpuFamilyResult.IsValid = true;
                                cpuFamilyResult.Message = "";

                                if (cpuFamily >= 6 && cpuModel <= 95 && !(cpuFamily == 6 && cpuModel == 85))
                                {
                                    cpuFamilyResult.IsValid = false;
                                    cpuFamilyResult.Message = "";
                                }
                                else if (cpuFamily == 6 && (cpuModel == 142 || cpuModel == 158) && cpuStepping == 9)
                                {
                                    string registryName = "Platform Specific Field 1";
                                    int registryValue = (int)Registry.GetValue(registryPath, registryName, -1);

                                    if ((cpuModel == 142 && registryValue != 16) || (cpuModel == 158 && registryValue != 8))
                                    {
                                        cpuFamilyResult.IsValid = false;
                                    }
                                    cpuFamilyResult.Message = "PlatformId " + registryValue;
                                }
                            }
                            catch (Exception ex)
                            {
                                cpuFamilyResult.IsValid = false;
                                cpuFamilyResult.Message = "Exception:" + ex.GetType().Name;
                            }
                        }
                        else if (manufacturer.Equals(AMD_MANUFACTURER, StringComparison.OrdinalIgnoreCase))
                        {
                            cpuFamilyResult.IsValid = true;
                            cpuFamilyResult.Message = "";

                            if (cpuFamily < 23 || (cpuFamily == 23 && (cpuModel == 1 || cpuModel == 17)))
                            {
                                cpuFamilyResult.IsValid = false;
                            }
                        }
                        else
                        {
                            cpuFamilyResult.IsValid = false;
                            cpuFamilyResult.Message = "Unsupported Manufacturer: " + manufacturer + ", Architecture: " + processorArchitecture + ", CPUFamily: " + sysInfo.ProcessorLevel + ", ProcessorRevision: " + sysInfo.ProcessorRevision;
                        }
                        break;

                    default:
                        cpuFamilyResult.IsValid = false;
                        cpuFamilyResult.Message = "Unsupported CPU category. Manufacturer: " + manufacturer + ", Architecture: " + processorArchitecture + ", CPUFamily: " + sysInfo.ProcessorLevel + ", ProcessorRevision: " + sysInfo.ProcessorRevision;
                        break;
                }
                return cpuFamilyResult;
            }
        }
    "@
    try {
        $exitCode = 0

        [int]$MinOSDiskSizeGB = 64
        [int]$MinMemoryGB = 4
        [Uint32]$MinClockSpeedMHz = 1000
        [Uint32]$MinLogicalCores = 2
        [Uint16]$RequiredAddressWidth = 64

        # Initialize result object
        $outObject = @{ 
            returnCode = -2
            returnResult = "FAILED TO RUN"
            returnReason = ""
            logging = "" 
        }

        # Check Storage
        $osDrive = Get-WmiObject -Class Win32_OperatingSystem | Select-Object -Property SystemDrive
        $osDriveSize = Get-WmiObject -Class Win32_LogicalDisk -filter "DeviceID='$($osDrive.SystemDrive)'" | Select-Object @{Name = "SizeGB"; Expression = { $_.Size / 1GB -as [int] } }  
        
        if ($osDriveSize.SizeGB -lt $MinOSDiskSizeGB) {
            $outObject.returnReason += "Storage, "
        }

        # Check Memory
        $memory = Get-WmiObject Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum | Select-Object @{Name = "SizeGB"; Expression = { $_.Sum / 1GB -as [int] } }
        
        if ($memory.SizeGB -lt $MinMemoryGB) {
            $outObject.returnReason += "Memory, "
        }

        # Check TPM
        $tpm = Get-Tpm
        if (!$tpm.TpmPresent) {
            $outObject.returnReason += "TPM, "
        }
        else {
            $tpmVersion = Get-WmiObject -Class Win32_Tpm -Namespace root\CIMV2\Security\MicrosoftTpm | Select-Object -Property SpecVersion
            if ($tpmVersion.SpecVersion) {
                $majorVersion = $tpmVersion.SpecVersion.Split(",")[0] -as [int]
                if ($majorVersion -lt 2) {
                    $outObject.returnReason += "TPM Version, "
                }
            }
        }

        # Check CPU and add CPU Family check
        Add-Type -TypeDefinition $Source
        $cpuDetails = @(Get-WmiObject -Class Win32_Processor)[0]
        
        if ($null -eq $cpuDetails) {
            $outObject.returnReason += "Processor (Not Found), "
        }
        else {
            $processorCheckFailed = $false

            # AddressWidth
            if ($null -eq $cpuDetails.AddressWidth -or $cpuDetails.AddressWidth -ne $RequiredAddressWidth) {
                $processorCheckFailed = $true
            }

            # ClockSpeed is in MHz
            if ($null -eq $cpuDetails.MaxClockSpeed -or $cpuDetails.MaxClockSpeed -le $MinClockSpeedMHz) {
                $processorCheckFailed = $true
            }

            # Number of Logical Cores
            if ($null -eq $cpuDetails.NumberOfLogicalProcessors -or $cpuDetails.NumberOfLogicalProcessors -lt $MinLogicalCores) {
                $processorCheckFailed = $true
            }

            # CPU Family
            $cpuFamilyResult = [CpuFamily]::Validate([String]$cpuDetails.Manufacturer, [uint16]$cpuDetails.Architecture)
            if (!$cpuFamilyResult.IsValid) {
                $processorCheckFailed = $true
            }

            if ($processorCheckFailed) {
                $outObject.returnReason += "Processor, "
            }
        }

        # Check SecureBoot
        try {
            $null = Confirm-SecureBootUEFI
        }
        catch {
            $outObject.returnReason += "SecureBoot, "
        }

        # Check for i7-7820hq exception
        try {
            $supportedDevices = @('surface studio 2', 'precision 5520')
            $systemInfo = @(Get-WmiObject -Class Win32_ComputerSystem)[0]

            if ($cpuDetails.Name -match 'i7-7820hq cpu @ 2.90ghz') {
                $modelOrSKUCheckLog = $systemInfo.Model.Trim()
                if ($supportedDevices -contains $modelOrSKUCheckLog) {
                    $outObject.returnReason = ""  # Clear any CPU-related failures
                }
            }
        }
        catch {
            # Ignore i7 exception check failures
        }

        # Set final result
        $WIN11COMPATIBLE = $outObject.returnReason.Length -eq 0
        
        # Output result to object
        $outputObject = [pscustomobject]@{
            WIN11COMPATIBLE = $WIN11COMPATIBLE
            IncompatibleItems = $outObject.returnReason.TrimEnd(", ")
        }

        # Write to Gorelo custom field
        $result = if ($WIN11COMPATIBLE) { "Compatible" } else { "Not Compatible: $($outObject.returnReason.TrimEnd(', '))" }
        GoreloAction -SetCustomField -Name 'asset.Windows11Compatibility' -Value $result

        # Write to Registry
        if ($WIN11COMPATIBLE) {
            Write-Win11Registry -Status "Compatible"
        }
        else {
            Write-Win11Registry -Status "NotCompatible"
        }

        # Return the output object
        $outputObject
    }
    catch {
        # Create error output object
        $outputObject = [pscustomobject]@{
            WIN11COMPATIBLE = $false
            IncompatibleItems = "Error running compatibility check: $($_.Exception.Message)"
        }

        # Write error to Gorelo custom field
        GoreloAction -SetCustomField -Name 'asset.Windows11Compatibility' -Value "Error running check: $($_.Exception.Message)"

        # Write error to Registry
        Write-Win11Registry -Status "CheckFailed"

        # Return the error output object
        $outputObject
    }
    ```
  </Step>

  <Step title="Deploy the script via a policy.">
    1. Navigate to **[Policies](https://app.gorelo.io/Asset/policy-management).**
    2. Edit an existing policy that covers the assets you want to check Windows 11 compatibility for.
    3. Add the **Windows 11 Compatibility** script and set to repeat daily at your preferred time.
    4. **Save** and **Distribute** the policy.
  </Step>

  <Step title="Create the View on the Assets list.">
    1. Navigate to **[Assets](https://app.gorelo.io/asset/asset-list).**
    2. Click **Create view** down the bottom left and use the following details:
       * **Title**: Win11 Compatible
       * **Tags**: Win11Compatible
    3. Click **Save**.
    4. Do the same for **Win11 NotCompatible** and **Win11 CheckFailed.**
  </Step>
</Steps>
