How to detect Windows 10 S?

Viewed 2081

Windows 10 S is a special Windows edition which is streamlined for security and superior performance. Basically you can only install apps from Microsoft Store.

You can deliver normal desktop apps through desktop bridge to the Store so that itself is not a big problem. However Windows 10 S imposes additional limitations on Store apps, which might cause them to crash during startup.

I have received this feedback from Store Application Review Results.

App Policies: 10.1.2.1 Inaccurate Functionality: Windows 10S

Notes To Developer:

Your app doesn't work on Windows 10 S and the application terminates without notice to the user. Apps that don’t work on Windows 10 S must support graceful shutdown.

Steps to reproduce: 1. Launch the app on Windows 10S. 2. Notice that your app doesn't work on Windows 10 S and the application terminates without notice to the user.

Please be sure to test your app for Windows 10 S: https://docs.microsoft.com/windows/uwp/porting/desktop-to-uwp-test-windows-s Tested Devices: Windows 10 Desktop

So basically what I need to do is to detect Windows 10 S and notify the user that it's not supported.

4 Answers

Use GetProductInfo Win32 API call and check for return value PRODUCT_CLOUD (0x000000B2) and PRODUCT_CLOUDN (0x000000B3). That 2 values are the SKU detection codes for Windows 10 S.

Inspired by magicandre1981's solution of checking the SKU I implemented it as a concrete solution. It contains a workaround to GetVersionEx() being deprecated in Windows 10 and it contains a check for Windows 10 S Dev Mode in order allow proper testing.

One disclaimer is that this check works as intended in my environment (both real 10 S and Dev Mode). But an end-user has reported that the check is not reliable, I have not been able to validate if the end-user actually run 10 S or just think he does. It passed the review process at Microsoft though.

Example console application in C++ that runs the checks:

// Windows10SCheck.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>
#include <Windows.h>

// Function to get the OS version number
//
// Uses RtlGetVersion() is available, otherwise falls back to GetVersionEx()
//
// Returns false if the check fails, true if success
bool GetOSVersion(OSVERSIONINFOEX* osversion) {
    NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEX);
    *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");

    if (RtlGetVersion != NULL)
    {
        // RtlGetVersion uses 0 (STATUS_SUCCESS)
        // as return value when succeeding
        return RtlGetVersion(osversion) == 0;
    }
    else {
        // GetVersionEx was deprecated in Windows 10
        // Only use it as fallback
#pragma warning(suppress : 4996)
        return GetVersionEx((LPOSVERSIONINFO)osversion);
    }
}

// Function to check if the product type is Windows 10 S
//
// The product type values are from: https://stackoverflow.com/a/47368738/959140
//
// Output parameter bool iswin10s indicates if running 10 S or not
//
// Returns false if the check fails, true if success
bool IsWindows10S(bool *iswin10s) {
    OSVERSIONINFOEX osinfo;
    osinfo.dwOSVersionInfoSize = sizeof(osinfo);
    osinfo.szCSDVersion[0] = L'\0';

    if (!GetOSVersion(&osinfo)) {
        return false;
    }

    DWORD dwReturnedProductType = 0;

    if (!GetProductInfo(osinfo.dwMajorVersion, osinfo.dwMinorVersion, 0, 0, &dwReturnedProductType)) {
        return false;
    }

    *iswin10s = dwReturnedProductType == PRODUCT_CLOUD || dwReturnedProductType == PRODUCT_CLOUDN;

    return true;
}

bool IsWindows10SDevMode() {
    // Checks for the policy file mentioned in the docs:
    // https://docs.microsoft.com/en-us/windows/uwp/porting/desktop-to-uwp-test-windows-s
    struct stat buffer;

    // x64 applications
    std::string filePathName64 = "C:\\Windows\\system32\\CodeIntegrity\\SIPolicy.P7B";
    if (stat(filePathName64.c_str(), &buffer) == 0) {
        return true;
    }

    // x86 applications
    std::string filePathName86 = "C:\\Windows\\sysnative\\CodeIntegrity\\SIPolicy.P7B";
    if (stat(filePathName86.c_str(), &buffer) == 0) {
        return true;
    }


    return false;
}

int main() {
    bool is10s = false;
    if (!IsWindows10S(&is10s)) {
        std::cout << "Windows 10 S check failed";
    }

    std::cout << "\nIs 10 S: " << (is10s ? "true" : "false");
    std::cout << "\nIs 10 S Dev Mode: " << (IsWindows10SDevMode() ? "true" : "false");
}

If Windows 10 1803 or newer, check for the following DWORD registry value:

  • Registry Key (Path): HKLM\System\CurrentControlSet\Control\CI\Policy
  • Registry Value Name: SkuPolicyRequired
  • Registry Value (DWORD): 1

(source: https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-codeintegrity-skupolicyrequired)

On versions of Windows 10 prior to 1803, Windows 10 S (and Windows 10 S N) were their own SKUs. To check this, query the following with WMI: Win32_OperatingSystem -> OperatingSystemSKU and look for an integer value of 178 (Windows 10 S) or 179 (Windows 10 S N).

Regardless of which version of Windows 10 is running, querying for S Mode / Windows 10 S / Windows 10 S N is tricky because common tools like cmd, powershell, regedit, reg, wmic, and wbemtest are going to be blocked. To enable these tools, the device needs to be put into Manufacturing Mode by placing a registry key in place (offline using WinPE), then booting up the computer. For reference, see: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-10-s-manufacturing-mode

Assuming the device is in Manufacturing Mode and you have access to the command prompt, here are a couple ways to query for S Mode / Windows 10 S / Windows 10 S N:

For Windows 10 1803 and newer, an easy way to query for S Mode is to type the following at the command prompt:

reg query HKLM\SYSTEM\CurrentControlSet\Control\CI\Policy /v SkuPolicyRequired

(if you receive a message that the system was unable to find the specified registry key or value, or if you receive a result of a REG_DWORD other than 0x1, then S Mode is not enabled)

For Windows 10 versions prior to 1803, an easy way to query this at the command prompt is to type:

wmic os get operatingsystemsku

Related