tis-check-windows-eol icon

Check Windows EOL

Silent install package for Check Windows EOL

1-24

tis-check-windows-eol

This package allows you to check whether the version of Windows installed on a workstation (client or server) is still supported by Microsoft or has reached its End Of Life (EOL).

The audit is performed automatically every 7 days to account for potential version upgrades, such as an update from Windows 10 22H2 to 24H2, or a migration from Windows 10 to Windows 11.

The result is recorded in the audit data under the key audit-windows-eol

Three types of results are possible :

  • OK → The system is still supported by Microsoft.
  • ⚠️ WARNING → The system is at the end of support.
  • ERROR → The Windows version could not be correctly identified.

In case of an ERROR status, please contact the Tranquil IT team to adjust or correct the package code.

The package is monitored by our team and will be updated regularly based on new data published by Microsoft.

To benefit from the latest updates, it is recommended to :

  • Clone the package from the Tranquil IT WAPT repository.
  • Or run update_package from the WAPT console.

  • package: tis-check-windows-eol
  • name: Check Windows EOL
  • version: 1-24
  • categories: System,Security
  • maintainer: WAPT Team,Tranquil IT,Flavien SCHELFAUT
  • licence: proprietary_free
  • locale: all
  • target_os: windows
  • architecture: all
  • signature_date:
  • size: 79.92 Ko

package           : tis-check-windows-eol
version           : 1-24
architecture      : all
section           : base
priority          : optional
name              : Check Windows EOL
categories        : System,Security
maintainer        : WAPT Team,Tranquil IT,Flavien SCHELFAUT
description       : Detect whether your Windows version is actively supported or has reached its end-of-life status, including extended support phases
depends           : 
conflicts         : 
maturity          : PROD
locale            : all
target_os         : windows
min_wapt_version  : 2.5
sources           : 
installed_size    : 
impacted_process  : 
description_fr    : Détermine si votre version de Windows est activement prise en charge ou si elle a atteint la fin de sa durée de vie, y compris les phases de prise en charge étendue.
description_pl    : Określa, czy dana wersja systemu Windows jest aktywnie wspierana, czy też osiągnęła koniec okresu eksploatacji, w tym fazy rozszerzonego wsparcia.
description_de    : Bestimmt, ob Ihre Windows-Version aktiv unterstützt wird oder das Ende ihrer Lebensdauer erreicht hat, einschließlich der Phasen der erweiterten Unterstützung.
description_es    : Determina si su versión de Windows recibe soporte activo o si ha llegado al final de su vida útil, incluidas las fases de soporte ampliado.
description_pt    : Determina se a sua versão do Windows tem suporte ativo ou se chegou ao fim da sua vida útil, incluindo as fases de suporte alargado.
description_it    : Determina se la versione di Windows in uso è attivamente supportata o se ha raggiunto la fine del suo ciclo di vita, comprese le fasi di supporto esteso.
description_nl    : Bepaalt of uw versie van Windows actief wordt ondersteund of het einde van zijn levensduur heeft bereikt, inclusief verlengde ondersteuningsfasen.
description_ru    : Определяет, активно ли поддерживается ваша версия Windows или срок ее жизни подошел к концу, включая фазы расширенной поддержки.
audit_schedule    : 7d
editor            : 
keywords          : 
licence           : proprietary_free
homepage          : 
package_uuid      : d8715194-e209-439f-b18a-b3b790252d27
valid_from        : 
valid_until       : 
forced_install_on : 
changelog         : 
min_os_version    : 
max_os_version    : 
icon_sha256sum    : 3975cd47cad6ddc972ff4af8e9bdf7d2293b9c0f0b66db3d5b6ea4b0dcbd1916
signer            : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature_date    : 2025-06-05T18:00:17.000000
signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes
signature         : vgoH9j2TbmoHwx+mowVq7qcuuYXE92iStIv3vfv0sceHc+dn2WR55F4YocVRj5j2G8K187OnTAVHhbIJ8W7f9wJp7D/FAMjDbSj+QWTrV5L6OPOLEkOk7z7FmRM1j0I0VWFX3KUmHUP9S9O66OY1ucJRMznvduPRUr1yZtyos8jS7heajhUqHo/IWMN3o63hGvaCgHsVNvuKPl5cWTMC7AFcEqecWNVlJ+PgA2rwCk4/7j9UyM56/a/aXDF1k4s/GI5+uIaf2SVKTdAms+uP2p5ilbbStKUcZSXf/4r4fyGreF7WtIndx2slryf+W2JjHZLUUYLgNduNOZGdFiFlTg==

# -*- coding: utf-8 -*-
from setuphelpers import *
from setupdevhelpers import *
from datetime import datetime
from typing import Optional
import re


def install():

    # Cleanup old files
    for file in ["windows_client.json", "windows_server.json"]:
        dest_path = makepath(public_persistent_dir, file)
        if isfile(dest_path):
            remove_file(dest_path)
            
    print("Copy file to persistent folder")
    dest_path = makepath(public_persistent_dir, "windows_products.json")
    if isfile(dest_path):
        remove_file(dest_path)
    filecopyto("windows_products.json", dest_path)
        
    
def audit():
    
    if params.get("running_as_luti"):
        return check_all_windows_release()

    windows_eol_checker = WindowsEOLChecker()
    status = windows_eol_checker.run()
    WAPT.write_audit_data_if_changed("audit-windows-eol", "audit-windows-eol", str(status))
    return status

class WindowsEOLChecker:
    def __init__(
        self, debug=False, product_name: str = None, edition_id: str = None, windows_ver_prettyname: str = None, 
        esu_licenses: Optional[list] = None, installation_type: str = None, windows_ver: Version = None, 
        csd_version: str = None, release_id: str = None
        ):
        
        self.debug = debug
        
        self.product_name = product_name
        self.edition_id = edition_id
        self.windows_ver_prettyname = windows_ver_prettyname
        self.esu_licenses = list() if esu_licenses is None else esu_licenses
        self.installation_type = installation_type
        self.windows_version = windows_ver if windows_ver else windows_version()
        self.csd_version = csd_version
        self.release_id = release_id
        
        if not self.debug:
            self.product_name = registry_get(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName")
            self.edition_id = registry_get(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "EditionID")
            
            self.windows_ver_prettyname = registry_get(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DisplayVersion")
            release_id = registry_readstring(HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion', 'ReleaseId')
            
            self.csd_version = registry_get(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CSDVersion")
            self.esu_licenses = self.get_esu_license_info()
                
        if not release_id:
            if Version(self.windows_version, 3) == Version('10.0.10240', 3):
                release_id = "1507"
            if Version(self.windows_version, 3) == Version('10.0.10586', 3):
                release_id = "1511"
        
        if not self.windows_ver_prettyname:
            self.windows_ver_prettyname = release_id
        
        if self.is_windows_client() and self.windows_version >= WindowsVersions.Windows11:
            self.product_name = self.product_name.replace('Windows 10', 'Windows 11')
        
        self.windows_product_filename = 'windows_products.json'
        
    def is_windows_client(self):
        
        installation_type = (
            self.installation_type if self.debug and self.installation_type else 
            registry_readstring(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "InstallationType")
        )
            
        return installation_type == "Client"

    def detect_esu_year(self, product_name):
        match = re.search(r"Year\s?([1-9])", product_name, re.IGNORECASE)
        return f"Extended Security Update Year {match.group(1)}" if match else "Unknown"

    def get_esu_license_info(self):
        
        """
        __Output__
        
        Windows Server 2012 R2
        ------------------------
        Name              : Windows(R), Server-ESU-Year3 add-on for ServerDatacenter,ServerDatacenterCore,ServerDatacenterV,ServerDatacenterVCore,ServerStandard,ServerStandardCore,ServerStandardV,ServerStandardVCore
        PartialProductKey : C4BPT
        LicenseStatus     : 1
        Description       : Windows(R) Operating System, VOLUME_MAK channel
        LicenseFamily     : Windows(R), Server-ESU-Year3 add-on for ServerDatacenter,ServerDatacenterCore,ServerDatacenterV,ServerDatacenterVCore,ServerStandard,ServerStandardCore,ServerStandardV,ServerStandardVCore
        
        Windows 7 SP1
        ------------------------                                                                                                                                                                                                                         
        Name                           Windows(R) 7, Client-ESU-Year3 add-on for Enterprise,EnterpriseE,EnterpriseN,Professional,ProfessionalE,ProfessionalN,Ultimate,UltimateE,UltimateN                                                                                  
        ESUYear                        Windows(R) 7, Client-ESU-Year3 add-on for Enterprise,EnterpriseE,EnterpriseN,Professional,ProfessionalE,ProfessionalN,Ultimate,UltimateE,UltimateN                                                                                  
        PartialProductKey              XRFH7                                                                                                                                                                                                                               
        Description                    Windows Operating System - Windows(R) 7, VOLUME_MAK channel                                                                                                                                                                         
        LicenseStatus                  1    
        """

        try:
            wmi = win32com_ensure_dispatch_patch("WbemScripting.SWbemLocator")
            service = wmi.ConnectServer(".", "root\\cimv2")
        except:
            if os.path.isdir(os.path.join(tempfile.gettempdir(), 'gen_py')):
                remove_tree(os.path.join(tempfile.gettempdir(), 'gen_py'), ignore_errors=True)
                wmi = win32com_ensure_dispatch_patch("WbemScripting.SWbemLocator")
                service = wmi.ConnectServer(".", "root\\cimv2")

        def get_property_value_win32com(product, prop_name):
            for prop in product.Properties_:
                if prop.Name == prop_name:
                    return prop.Value
            return None

        query = (
            "SELECT * FROM SoftwareLicensingProduct "
            "WHERE ApplicationID='55c92734-d682-4d71-983e-d6ec3f16059f' "
            "AND PartialProductKey IS NOT NULL AND LicenseStatus=1"
        )

        licenses = []
        for product in service.ExecQuery(query):
            name = get_property_value_win32com(product, "Name")
            if name and any(x in name for x in ("ESU", "Extended Security")):
                license_info = {
                    "name": name.split('for')[0],
                    "partial_product_key": product.PartialProductKey,
                    "license_status": product.LicenseStatus,
                    "description": product.Description,
                    "esu_year": self.detect_esu_year(name)
                }
                licenses.append(license_info)

        return licenses

    @staticmethod
    def get_highest_esu_licence(esu_licences):
        valid = [lic for lic in esu_licences if lic['esu_year'] != 'Unknown']
        return max(valid, key=lambda x: int(x['esu_year'].split('Year')[-1])) if valid else None

    def is_release_eol(self, product):
        support_policy = product['SupportPolicy']
        datetime_format_str = '%Y/%m/%d'

        if support_policy == 'Modern':
            release_end_date = datetime.strptime(product['ReleaseEndDate'], datetime_format_str)
        elif support_policy == 'Fixed':
            release_end_date = product['ExtendedEndDate'] if any(x in product['Product'] for x in ('LTSB', 'LTSC')) else product['MainstreamDate']
            release_end_date = product['ReleaseEndDate'] if 'Extended Security Update' in product['Release'] else release_end_date
            
            # Windows Server is LTSC/LTSB by default so get ExtendedEndDate
            release_end_date = product['ExtendedEndDate'] if not self.is_windows_client() else release_end_date
            
            release_end_date = datetime.strptime(release_end_date, datetime_format_str)
        else:
            return False, None

        # Return a Tuple : bool, datetime
        return datetime.now() > release_end_date, release_end_date.strftime(datetime_format_str)

    def get_windows_report(self):
        return {
            "product_name": self.product_name,
            "edition_id": self.edition_id,
            "windows_ver_prettyname": self.windows_ver_prettyname, 
            "csd_version": self.csd_version,
            "windows_version": str(self.windows_version),
            "is_windows_client": self.is_windows_client(),
            "esu_licenses": self.esu_licenses,
        }

    def run(self):

        current_product = None
        
        # In debug get the file in the package folder otherwise in public_persistent_dir
        filepath = makepath(public_persistent_dir, self.windows_product_filename) if (not self.debug) or params.get("running_as_luti") else self.windows_product_filename
        all_products = json_load_file(filepath)
        
        # Windows Client
        if self.is_windows_client():
            if 'LTSC' in self.product_name:
                current_product = next((i for i in all_products if self.product_name == i['Product']), None)
            elif 'LTSB' in self.product_name:
                # Doesn't have Edition in Product unlike LTSC ...
                parts = self.product_name.split()
                product_name = " ".join(parts[:2] + parts[3:])
                current_product = next((i for i in all_products if product_name == i['Product']), None)
            else:
                windows_version = " ".join(self.product_name.split()[:2]) # Windows 10 Pro -> Windows 10
                esu_licence = self.get_highest_esu_licence(self.esu_licenses)
                
                filtered = [
                    i for i in all_products if windows_version in i['Product'] and 
                    (
                        # For Windows >= 10 : Release is 20H2/22H2 etc
                        ((self.windows_ver_prettyname and i['Release']) and i['Release'].split()[-1] == self.windows_ver_prettyname)
                     or
                        # For Windows 7 : Release can be 'Service Pack 1' or 'Extended Security Update Year 1'
                        ((self.csd_version and i['Release']) and i['Release'] == (esu_licence['esu_year'] if esu_licence else self.csd_version))
                    )
                ]
                
                # Match Windows Edition: Education/Enterprise/Pro etc
                current_product = next((i for i in filtered if i['Edition'] in self.product_name), None)
            
        # Windows Server
        else:
            filtered = [i for i in all_products if i['Product'] in self.product_name and i['Edition'] in self.product_name]
            esu_licence = self.get_highest_esu_licence(self.esu_licenses)
            
            if esu_licence:
                current_product = next((i for i in filtered if esu_licence['esu_year'] in i['Release']), None)
            else:
                current_product = filtered[0] if filtered else None

        # Check if the product found is EOL
        if current_product:
            eol, release_end_date = self.is_release_eol(current_product)
            
            version_info = ((self.windows_ver_prettyname if self.windows_ver_prettyname else self.csd_version) if self.is_windows_client() else "")
            full_name = f"{self.product_name} - {version_info}".strip()
            
            if not eol:
                print(f"[OK] Your {full_name} is supported until {release_end_date}")
                return "OK"
            else:
                print(f"[WARNING] {full_name} is EOL ! End date is {release_end_date}")
                return "WARNING"
        else:
            print("[ERROR] No matching product found. Please create a support report with the following information:\n")
            print(json.dumps(self.get_windows_report(), indent=2))
            return "ERROR"
            

def check_all_windows_release():
         
    # Windows Server 2019 Standard Evaluation
    checker_ws_2019_standard_eva = WindowsEOLChecker(
        debug=True,
        product_name="Windows Server 2019 Standard Evaluation",
        edition_id="ServerStandardEval",
        windows_ver_prettyname=None,
        installation_type="Server",
        windows_ver=Version('10.0.17763'),
        esu_licenses=None,
        release_id="1809"
    )
    
    # Windows Server 2012 R2 Standard
    checker_ws_2012r2_standard = WindowsEOLChecker(
        debug=True,
        product_name="Windows Server 2012 R2 Standard",
        edition_id="ServerStandard",
        windows_ver_prettyname=None,
        installation_type="Server",
        windows_ver=Version("6.3.9600"),
        esu_licenses=[
            {
                "name": "Windows(R), Server-ESU-Year2 add-on",
                "partial_product_key": "C4BPT",
                "license_status": 1,
                "description": "Windows(R) Operating System, VOLUME_MAK channel",
                "esu_year": "Extended Security Update Year 2"
            },
            {
                "name": "Windows(R), Server-ESU-Year3 add-on",
                "partial_product_key": "C4BPT",
                "license_status": 1,
                "description": "Windows(R) Operating System, VOLUME_MAK channel",
                "esu_year": "Extended Security Update Year 3"
            }
        ]
    )
    
    # Windows 7 SP1 - ESU Year 3
    checker_w7_sp1_pro_esu = WindowsEOLChecker(
        debug=True,
        product_name="Windows 7 Professional",
        edition_id="Professional",
        windows_ver_prettyname=None,
        installation_type="Client",
        csd_version="Service Pack 1",
        windows_ver=Version('6.1.7601'),
        esu_licenses=[
            {
                "name": "Windows(R) 7, Client-ESU-Year3 add-on",
                "partial_product_key": "XRFH7",
                "license_status": 1,
                "description": "Windows Operating System - Windows(R) 7, VOLUME_MAK channel",
                "esu_year": "Extended Security Update Year 3"
            },
            # {   # Not officialy supported
            #     "name": "Windows(R) 7, Client-ESU-Year6 add-on",
            #     "partial_product_key": "XRFH7",
            #     "license_status": 1,
            #     "description": "Windows Operating System - Windows(R) 7, VOLUME_MAK channel",
            #     "esu_year": "Extended Security Update Year 6"
            # }
        ]
    )
    
    # Windows 7 SP1 Pro
    checker_w7_sp1_pro = WindowsEOLChecker(
        debug=True,
        product_name="Windows 7 Professional",
        edition_id="Professional",
        windows_ver_prettyname=None,
        installation_type="Client",
        csd_version="Service Pack 1",
        windows_ver=Version('6.1.7601'),
        esu_licenses=None
    )
    
    # Windows 10 22H2 Pro
    checker_w10_22h2_pro = WindowsEOLChecker(
        debug=True,
        product_name="Windows 10 Pro",
        edition_id="Professional",
        windows_ver_prettyname="22H2",
        installation_type="Client",
        windows_ver=Version('10.0.19045'),
        esu_licenses=None,
        release_id="2009"
    )
    
    # Windows 11 24H2 Pro
    checker_w11_24h2_pro = WindowsEOLChecker(
        debug=True,
        product_name="Windows 11 Pro",
        edition_id="Professional",
        windows_ver_prettyname="24H2",
        installation_type="Client",
        windows_ver=Version('10.0.26100'),
        esu_licenses=None
    )
    
    # Windows 11 24H2 Education
    checker_w11_24h2_edu = WindowsEOLChecker(
        debug=True,
        product_name="Windows 11 Education",
        edition_id="Education",
        windows_ver_prettyname="24H2",
        installation_type="Client",
        windows_ver=Version('10.0.26100'),
        esu_licenses=None,
        release_id="2009"
    )
    
    # Windows 11 23H2 Education
    checker_w11_23h2_pro_edu = WindowsEOLChecker(
        debug=True,
        product_name="Windows 11 Education",
        edition_id="Education",
        windows_ver_prettyname="23H2",
        installation_type="Client",
        windows_ver=Version('10.0.22631'),
        esu_licenses=None,
        release_id="2009"
    )
    
    # Windows 11 24H2 Pro Education
    checker_w11_24h2_pro_edu = WindowsEOLChecker(
        debug=True,
        product_name="Windows 11 Pro Education",
        edition_id="ProfessionalEducation",
        windows_ver_prettyname="24H2",
        installation_type="Client",
        windows_ver=Version('10.0.26100'),
        esu_licenses=None,
        release_id="2009"
    )
    
    # Windows 10 Enterprise 2016 LTSB
    checker_w10_enterprise_ltsb_2016 = WindowsEOLChecker(
        debug=True,
        product_name="Windows 10 Enterprise 2016 LTSB",
        edition_id="EnterpriseS",
        windows_ver_prettyname="1607",
        installation_type="Client",
        windows_ver=Version('10.0.14393'),
        esu_licenses=None,
        release_id=None
    )
    
    # Windows 10 Entreprise LTSC 2019
    checker_w10_enterprise_ltsc_2019 = WindowsEOLChecker(
        debug=True,
        product_name="Windows 10 Enterprise LTSC 2019",
        edition_id="EnterpriseS",
        windows_ver_prettyname=None,
        installation_type="Client",
        windows_ver=Version('10.0.17763'),
        esu_licenses=None,
        release_id="1809"
    )
    
    list_of_checker = [
        checker_ws_2019_standard_eva, checker_ws_2012r2_standard, checker_w7_sp1_pro_esu, checker_w7_sp1_pro,
        checker_w10_22h2_pro, checker_w11_24h2_pro, checker_w11_24h2_edu, checker_w11_23h2_pro_edu, checker_w11_24h2_pro_edu,
        checker_w10_enterprise_ltsb_2016, checker_w10_enterprise_ltsc_2019, WindowsEOLChecker()
    ]
    
    audit_status = "OK"
    for checker in list_of_checker:
        result = checker.run()
        if result != "OK":
            audit_status = result
    return audit_status


if __name__ == '__main__':
    check_all_windows_release()

from setuphelpers import *
from setupdevhelpers import *
import hashlib
from io import BytesIO

current_path = os.path.dirname(os.path.realpath(__file__))
if not current_path in sys.path:
    sys.path.append(current_path)

import pylightxl as xl


def extract_data_from_excel(file_obj):
    
    db = xl.readxl(file_obj)
    ws = db.ws('lifecycle_data')
    
    rows = list(ws.rows)
    field_names = rows[6]
    
    return [dict(zip(field_names, [item.strip(' *') for item in row])) for row in rows[7:]]

def update_package():
    # Declaring local variables
    package_updated = False
    proxies = get_proxies()
    if not proxies:
        proxies = get_proxies_from_wapt_console()
    app_name = control.name
    
    # https://learn.microsoft.com/en-us/lifecycle/products/export/
    # https://learn.microsoft.com/en-us/lifecycle/products/export/guidance
    
    base_url = "https://app-omaha-prod.azurewebsites.net/api/PublishedListings/Export"
    
    windows_product_json = f"windows_products.json"
    windows_product_sha256 = f"windows_products.sha256"
        
    sha256_old = json_load_file(windows_product_sha256) if isfile(windows_product_sha256) else None
    download_url = f"{base_url}(endOfSupportYear=0,endOfSupportMonths=0,family='',group='')"
    with BytesIO(wgets(download_url, proxies=proxies)) as f:
        data = extract_data_from_excel(f)
    sha256_new = hashlib.sha256(json.dumps(data).encode()).hexdigest()
    
    if not sha256_old or sha256_new != sha256_old:
        print(f"[UPDATE] New changes detected for {windows_product_json} !")
        json_write_file(windows_product_json, data)
        json_write_file(windows_product_sha256, sha256_new)
        package_updated = True
    
    if package_updated:
        increment = int(control.version.rsplit('-', 1)[-1]) + 1
        control.version = f"{control.get_software_version()}-{increment}"
        control.save_control_to_wapt()
        print("[SUCCESS] Package updated and version bumped")
    else:
        print("[INFO] No changes detected, package not updated")

    return package_updated

cff6b01fc14c665c122c6ab6c0e69fab3caa6292e6c7df735ca3b6bef71b536a : WAPT/README.md
570dffbbe4b0c08d0d3b5a888c4bf9e4cb20fcee34ba0377001545f5ab53709f : WAPT/README_fr.md
38d056ab130f7bf7c481c12636a4e9959de36561d3dfcbe54c6e3571bc0c1dc3 : WAPT/certificate.crt
8e18a327ad2cde18b80212948d5c18d8469f0021c57fd0d13c9493f2b04366f2 : WAPT/control
3975cd47cad6ddc972ff4af8e9bdf7d2293b9c0f0b66db3d5b6ea4b0dcbd1916 : WAPT/icon.png
271ccd5028399272bd801f7184c1ffc91cf14ef0eaf30732a42edf7f3b74244a : luti.json
dcc79ea10bfe84a27cf76bdd9ee4cc86b17f78d08ca6f311dff71c47f9828451 : pylightxl.py
69e3d0a417827d1a9eb394933c0b6b685ccbadf26c25aaf6edddd75de2c9e91e : setup.py
f6869c0ac76538930c40a970a45167c286380e66fe093a776347ca0f5092dd7f : update_package.py
5d229d287d758f9756850970c23e6ee5433ccd04a5ff7cb9eb96adc94f533714 : windows_products.json
31f2f95e614ac0ab8206369433c479e39302e4eb44fb6f3615fffa0700e7d330 : windows_products.sha256