Skip to content

Instantly share code, notes, and snippets.

@mcwindy
Last active July 8, 2025 02:43
Show Gist options
  • Save mcwindy/27600ce7e3e9cdbe4ad0b9d5f2b340d1 to your computer and use it in GitHub Desktop.
Save mcwindy/27600ce7e3e9cdbe4ad0b9d5f2b340d1 to your computer and use it in GitHub Desktop.
Fix msvc & windows sdk environment variable in windows

This script is used to update MSVC and Windows SDK environment variables on Windows systems, simplifying the C++ configuration of Visual Studio Code.

It performs the following tasks:

  1. Check for Administrator Privileges: The script first checks if it is running with administrator privileges. If not, it prompts the user to run the script as an administrator and exits.

  2. Get Latest Version Path: It scans the specified base paths to find the latest version of MSVC and Windows SDK installations.

  3. Update Environment Variables:

  • MSVC Environment Variables: Updates the INCLUDE, LIB, and Path environment variables to point to the latest version of the MSVC installation.
  • Windows SDK Environment Variables: Updates the INCLUDE, LIB, and Path environment variables to point to the latest version of the Windows SDK installation.
  1. Modify Registry: Accesses the Windows registry to update the system environment variables and uses the setx command to notify the system of the changes.

  2. User Interaction: Prompts the user to confirm changes before updating each environment variable.

The script ensures that the development environment always points to the latest versions of the compiler and SDK, preventing issues caused by outdated paths.

import ctypes
import os
import re
import subprocess
import winreg
from typing import Optional, Tuple, Union


def is_admin() -> bool:
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False


def get_latest_version_path(base_path: str) -> Union[Tuple[str, str], str]:
    if not os.path.exists(base_path):
        return 'Base path does not exist'

    versions = [d for d in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, d))]
    if not versions:
        return 'No version found'

    latest_version = sorted(versions, reverse=True)[0]
    latest_version_path = os.path.join(base_path, latest_version)

    # if os.path.exists(os.path.join(latest_version_path, 'bin', 'Hostx64', 'x64')):
    return latest_version_path, latest_version
    # else:
    #     return 'No latest version path'


def find_pattern_in_env(reg_key: winreg.HKEYType, var_name: str, pattern: re.Pattern) -> Optional[str]:
    try:
        env_value = winreg.QueryValueEx(reg_key, var_name)[0]
        paths = env_value.split(';')
        for path in paths:
            if pattern.match(path):
                return path
    except OSError as e:
        print(f'Error accessing registry: {e}')
    return None


def modify_env_variable(reg_key: winreg.HKEYType, var_name: str, value_to_remove: str, value_to_add: str) -> str:
    env_value = winreg.QueryValueEx(reg_key, var_name)[0]
    paths = list(filter(lambda x: x, env_value.split(';')))

    if value_to_remove in paths:
        paths.remove(value_to_remove)

    if value_to_add not in paths:
        paths.append(value_to_add)

    return ';'.join(paths)


def set_system_env_variable(reg_key: winreg.HKEYType, var_name: str, new_value: str) -> None:
    try:
        winreg.SetValueEx(reg_key, var_name, 0, winreg.REG_EXPAND_SZ, new_value)
        subprocess.run(['setx', var_name, new_value], shell=True)
    except OSError as e:
        print(f'Error setting system environment variable: {e}')


if __name__ == '__main__':
    if not is_admin():
        print('Please run this script as an administrator.')
        exit(1)

    reg_key = winreg.OpenKey(
        winreg.HKEY_LOCAL_MACHINE,
        r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
        0,
        winreg.KEY_QUERY_VALUE | winreg.KEY_SET_VALUE,
    )

    print('Start updating MSVC environment variables')
    base_path = 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Tools\\MSVC\\'
    suffixs = {'INCLUDE': '\\include\\', 'LIB': '\\lib\\x64\\', 'Path': '\\bin\\Hostx64\\x64\\'}
    tmp = get_latest_version_path(base_path)
    if tmp is str:
        print(tmp)
        print('Unable to find a valid MSVC path')
    else:
        new_msvc_path, new_msvc_version = tmp
        print(f'New MSVC version: {new_msvc_version}')

        for kind in ['INCLUDE', 'LIB', 'Path']:
            old_msvc_path_regex = (base_path + '[\\d.]+' + suffixs[kind]).replace('\\', '\\\\').replace('\\\\d', '\\d')
            old_msvc_path_pattern = re.compile(old_msvc_path_regex)
            old_msvc_path = find_pattern_in_env(reg_key, kind, old_msvc_path_pattern)
            new_msvc_path = f'{base_path}{new_msvc_version}{suffixs[kind]}'
            if os.path.exists(new_msvc_path) and new_msvc_path != old_msvc_path:
                input(f'{kind}: {old_msvc_path} -> {new_msvc_path}')
                new_env_value = modify_env_variable(reg_key, kind, old_msvc_path, new_msvc_path)
                # print(f'Updated {kind} value: {new_env_value}')
                set_system_env_variable(reg_key, kind, new_env_value)
                print(f'{kind} updated')

    print('Start updating Windows SDK environment variables')
    base_path = 'C:\\Program Files (x86)\\Windows Kits\\10\\'
    suffixs = {
        'INCLUDE': ['\\um\\', '\\ucrt\\', '\\shared\\'],
        'LIB': ['\\um\\x64\\', '\\ucrt\\x64\\', '\\shared\\x64\\'],
        'Path': ['\\x64\\'],
    }
    tmp = get_latest_version_path(base_path + 'Include\\')
    if tmp is str:
        print(tmp)
        print('Unable to find a valid Windows SDK path')
    else:
        # Path (only one line)
        # C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\
        # LIB (enum suffixs except for shared)
        # C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\
        # C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64\
        # INCLUDE (enum suffixs)
        # C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um\
        # C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\
        # C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared\
        new_windows_sdk_path, new_windows_sdk_version = tmp
        print(f'New Windows SDK version: {new_windows_sdk_version}')

        infix = {'INCLUDE': 'Include\\', 'LIB': 'Lib\\', 'Path': 'bin\\'}
        for kind in infix:
            for suffix in suffixs[kind]:
                old_windows_sdk_regex = (
                    (base_path + infix[kind] + '[\\d.]+' + suffix)
                    .replace('\\', '\\\\')
                    .replace('(', '\\(')
                    .replace(')', '\\)')
                    .replace('\\\\d', '\\d')
                )
                old_windows_sdk_pattern = re.compile(old_windows_sdk_regex)
                old_windows_sdk_path = find_pattern_in_env(reg_key, kind, old_windows_sdk_pattern)
                new_windows_sdk_path = f'{base_path}{infix[kind]}{new_windows_sdk_version}{suffix}'
                if os.path.exists(new_windows_sdk_path) and new_windows_sdk_path != old_windows_sdk_path:
                    input(f'{kind}: {old_windows_sdk_path} -> {new_windows_sdk_path}')
                    new_env_value = modify_env_variable(reg_key, kind, old_windows_sdk_path, new_windows_sdk_path)
                    # print(f'Updated {kind} value: {new_env_value}')
                    set_system_env_variable(reg_key, kind, new_env_value)
                    print(f'{kind} updated')

    winreg.CloseKey(reg_key)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment