Pierre Arnaud
Pierre Arnaud

Reputation: 10547

Determining if the program is running on Windows Server

I would like to determine if my program is running on a version of Windows Server. Apparently, System.Environment does not contain information about the fact that Windows is a server version (there is no such info in the OS version object).

I know that I can use SystemInformation.TerminalServerSession to check whether my program is running on a Remote Desktop (see also this question), but this will also be true if the user is simply accessing a plain client Windows machine remotely.

So is there a supported way of determining if the code is running on a server or on a client machine? I don't mind using P/Invoke if needed.

Note: I don't want to search for the "Server" string in the product name, since this will probably not work on some systems because of the localization.

Upvotes: 18

Views: 12661

Answers (7)

Yonka2019
Yonka2019

Reputation: 1

@lucas0x7B answer but in C#

private static string GetProductType()
{
    string productType = null;

    try
    {
        ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT ProductType FROM Win32_OperatingSystem");

        foreach (ManagementObject queryObj in searcher.Get())
        {
            productType = queryObj["ProductType"].ToString();
            break;
        }
    }
    catch (ManagementException ex)
    {
        Console.WriteLine($"Error retrieving product type: {ex.Message}");
    }

    return productType;
}

Upvotes: 0

Walter Verhoeven
Walter Verhoeven

Reputation: 4431

I also tried the answer of @ylax; however, it points to a C++ macro and not something you can call from c#.

I have generated this helper method, I hope it helps someone:

static class WindowsOperatingSystemHelper
{
    [DllImport("kernel32.dll", SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
    public static extern bool GetProductInfo(
       int dwOSMajorVersion,
       int dwOSMinorVersion,
       int dwSpMajorVersion,
       int dwSpMinorVersion,
       out int pdwReturnedProductType);

    public enum OperatingSystemSKU
    {
        UNDEFINED = 0,
        ULTIMATE = 1,
        HOME_BASIC = 2,
        HOME_PREMIUM = 3,
        ENTERPRISE = 4,
        HOME_BASIC_N = 5,
        BUSINESS = 6,
        STANDARD_SERVER = 7,
        DATACENTER_SERVER = 8,
        SMALLBUSINESS_SERVER = 9,
        ENTERPRISE_SERVER = 10,
        STARTER = 11,
        DATACENTER_SERVER_CORE = 12,
        STANDARD_SERVER_CORE = 13,
        ENTERPRISE_SERVER_CORE = 14,
        ENTERPRISE_SERVER_IA64 = 15,
        BUSINESS_N = 16,
        WEB_SERVER = 17,
        CLUSTER_SERVER = 18,
        HOME_SERVER = 19,
        STORAGE_EXPRESS_SERVER = 20,
        STORAGE_STANDARD_SERVER = 21,
        STORAGE_WORKGROUP_SERVER = 22,
        STORAGE_ENTERPRISE_SERVER = 23,
        SERVER_FOR_SMALLBUSINESS = 24,
        SMALLBUSINESS_SERVER_PREMIUM = 25,
        HOME_PREMIUM_N = 26,
        ENTERPRISE_N = 27,
        ULTIMATE_N = 28,
        WEB_SERVER_CORE = 29,
        MEDIUMBUSINESS_SERVER_MANAGEMENT = 30,
        MEDIUMBUSINESS_SERVER_SECURITY = 31,
        MEDIUMBUSINESS_SERVER_MESSAGING = 32,
        SERVER_FOUNDATION = 33,
        HOME_PREMIUM_SERVER = 34,
        SERVER_FOR_SMALLBUSINESS_V = 35,
        STANDARD_SERVER_V = 36,
        DATACENTER_SERVER_V = 37,
        ENTERPRISE_SERVER_V = 38,
        DATACENTER_SERVER_CORE_V = 39,
        STANDARD_SERVER_CORE_V = 40,
        ENTERPRISE_SERVER_CORE_V = 41,
        HYPERV = 42,
        STORAGE_EXPRESS_SERVER_CORE = 43,
        STORAGE_STANDARD_SERVER_CORE = 44,
        STORAGE_WORKGROUP_SERVER_CORE = 45,
        STORAGE_ENTERPRISE_SERVER_CORE = 46,
        STARTER_N = 47,
        PROFESSIONAL = 48,
        PROFESSIONAL_N = 49,
        SB_SOLUTION_SERVER = 50,
        SERVER_FOR_SB_SOLUTIONS = 51,
        STANDARD_SERVER_SOLUTIONS = 52,
        STANDARD_SERVER_SOLUTIONS_CORE = 53,
        SB_SOLUTION_SERVER_EM = 54,
        SERVER_FOR_SB_SOLUTIONS_EM = 55,
        SOLUTION_EMBEDDEDSERVER = 56,
        SOLUTION_EMBEDDEDSERVER_CORE = 57,
        PROFESSIONAL_EMBEDDED = 58,
        ESSENTIALBUSINESS_SERVER_MGMT = 59,
        ESSENTIALBUSINESS_SERVER_ADDL = 60,
        ESSENTIALBUSINESS_SERVER_MGMTSVC = 61,
        ESSENTIALBUSINESS_SERVER_ADDLSVC = 62,
        SMALLBUSINESS_SERVER_PREMIUM_CORE = 63,
        CLUSTER_SERVER_V = 64,
        EMBEDDED = 65,
        STARTER_E = 66,
        HOME_BASIC_E = 67,
        HOME_PREMIUM_E = 68,
        PROFESSIONAL_E = 69,
        ENTERPRISE_E = 70,
        ULTIMATE_E = 71,
        ENTERPRISE_EVALUATION = 72,
        MULTIPOINT_STANDARD_SERVER = 76,
        MULTIPOINT_PREMIUM_SERVER = 77,
        STANDARD_EVALUATION_SERVER = 79,
        DATACENTER_EVALUATION_SERVER = 80,
        ENTERPRISE_N_EVALUATION = 84,
        EMBEDDED_AUTOMOTIVE = 85,
        EMBEDDED_INDUSTRY_A = 86,
        THINPC = 87,
        EMBEDDED_A = 88,
        EMBEDDED_INDUSTRY = 89,
        EMBEDDED_E = 90,
        EMBEDDED_INDUSTRY_E = 91,
        EMBEDDED_INDUSTRY_A_E = 92,
        STORAGE_WORKGROUP_EVALUATION_SERVE = 95,
        STORAGE_STANDARD_EVALUATION_SERVER = 96,
        CORE_ARM = 97,
        CORE_N = 98,
        CORE_COUNTRYSPECIFIC = 99,
        CORE_SINGLELANGUAGE = 100,
        CORE = 101,
        PROFESSIONAL_WMC = 103,
        EMBEDDED_INDUSTRY_EVAL = 105,
        EMBEDDED_INDUSTRY_E_EVAL = 106,
        EMBEDDED_EVAL = 107,
        EMBEDDED_E_EVAL = 108,
        NANO_SERVER = 109,
        CLOUD_STORAGE_SERVER = 110,
        CORE_CONNECTED = 111,
        PROFESSIONAL_STUDENT = 112,
        CORE_CONNECTED_N = 113,
        PROFESSIONAL_STUDENT_N = 114,
        CORE_CONNECTED_SINGLELANGUAGE = 115,
        CORE_CONNECTED_COUNTRYSPECIFIC = 116,
        CONNECTED_CAR = 117,
        INDUSTRY_HANDHELD = 118,
        PPI_PRO = 119,
        ARM64_SERVER = 120,
        EDUCATION = 121,
        EDUCATION_N = 122,
        IOTUAP = 123,
        CLOUD_HOST_INFRASTRUCTURE_SERVER = 124,
        ENTERPRISE_S = 125,
        ENTERPRISE_S_N = 126,
        PROFESSIONAL_S = 127,
        PROFESSIONAL_S_N = 128,
        ENTERPRISE_S_EVALUATION = 129,
        ENTERPRISE_S_N_EVALUATION = 130,
        HOLOGRAPHIC = 135,
        PRO_SINGLE_LANGUAGE = 138,
        PRO_CHINA = 139,
        ENTERPRISE_SUBSCRIPTION = 140,
        ENTERPRISE_SUBSCRIPTION_N = 141,
        DATACENTER_NANO_SERVER = 143,
        STANDARD_NANO_SERVER = 144,
        DATACENTER_A_SERVER_CORE = 145,
        STANDARD_A_SERVER_CORE = 146,
        DATACENTER_WS_SERVER_CORE = 147,
        STANDARD_WS_SERVER_CORE = 148,
        UTILITY_VM = 149,
        DATACENTER_EVALUATION_SERVER_CORE = 159,
        STANDARD_EVALUATION_SERVER_CORE = 160,
        PRO_WORKSTATION = 161,
        PRO_WORKSTATION_N = 162,
        PRO_FOR_EDUCATION = 164,
        PRO_FOR_EDUCATION_N = 165,
        AZURE_SERVER_CORE = 168,
        AZURE_NANO_SERVER = 169,
        ENTERPRISEG = 171,
        ENTERPRISEGN = 172,
        SERVERRDSH = 175,
        CLOUD = 178,
        CLOUDN = 179,
        HUBOS = 180,
        ONECOREUPDATEOS = 182,
        CLOUDE = 183,
        ANDROMEDA = 184,
        IOTOS = 185,
        CLOUDEN = 186,
    }


    public static bool TryGetOperatingSystem(this Version version, out OperatingSystemSKU sku)
    {
        sku = OperatingSystemSKU.UNDEFINED;
        if (GetProductInfo(version.Major, version.Minor, 0, 0, out int productType))
        {
            sku = (OperatingSystemSKU)productType;
        }
        return sku != OperatingSystemSKU.UNDEFINED;
    }
    public static bool IsWindowsServer()
    {
        if (TryGetOperatingSystem(Environment.OSVersion.Version, out var osSKU))
        {
            return osSKU.ToString().Contains("SERVER") || osSKU.ToString().Contains("DATA_CENTER") || osSKU == OperatingSystemSKU.CLUSTER_SERVER;
        }
        else
        {
            return false;
        }
    }
}

I got the enum from a Powershel site, I guess one needs to update it every xyz years when Microsoft generates a new OS.

Call it like:

if (WindowsOperatingSystemHelper.IsWindowsServer())
{
... your magic
}

Or if you like to know the OS:

 if (WindowsOperatingSystemHelper.TryGetOperatingSystem(Environment.OSVersion.Version, out var operatingSystem))
 {
    ... your magic
 }

Upvotes: 0

lucas0x7B
lucas0x7B

Reputation: 356

I had the same issue, albeit in scripting.

I have found this value; I am querying it using WMI:

https://msdn.microsoft.com/en-us/library/aa394239(v=vs.85).aspx
Win32_OperatingSystem
ProductType
    Data type: uint32
    Access type: Read-only
    Additional system information.
    Work Station (1)
    Domain Controller (2)
    Server (3)

I tested this for the following operating system versions:

  • Windows XP Professional SP3
  • Windows 7 Enterprise
  • Windows 8.1 Pro
  • Windows 8.1 Enterprise
  • Windows 10 Pro 10.0.16299
  • Windows Server 2003 R2 Standard Edition
  • Windows Server 2003 R2 Standard Edition x64
  • Windows Server 2008 R2 Standard
  • Windows Server 2012 Datacenter
  • Windows Server 2012 R2 Datacenter

Find my example batch file below.

Lucas.

for /f "tokens=2 delims==" %%a in ( 'wmic.exe os get producttype /value' ) do (
    set PRODUCT_TYPE=%%a
)
if %PRODUCT_TYPE%==1 set PRODUCT_TYPE=Workstation
if %PRODUCT_TYPE%==2 set PRODUCT_TYPE=DomainController
if %PRODUCT_TYPE%==3 set PRODUCT_TYPE=Server
echo %COMPUTERNAME%: %PRODUCT_TYPE%

You can easily do this in C#:

using Microsoft.Management.Infrastructure;
...
string Namespace = @"root\cimv2";
string className = "Win32_OperatingSystem";

CimInstance operatingSystem = new CimInstance(className, Namespace);

Upvotes: 1

Paul Hoepping
Paul Hoepping

Reputation: 21

IsWindowsServer is an inline function in VersionHelpers.h.

You can find and read that header file on your computer. It uses the API function VerifyVersionInfoW.

There is no function IswindowsServer in kernel32.dll.

Upvotes: 2

ylax
ylax

Reputation: 386

There's supposed to be a set of of 'Version Helper Functions' defined in the VersionHelpers.h header file of the WinAPI in assembly Kernel32.DLL. The one that, according to the documentation, should work for your case is IsWindowsServer(void). Description is here:

http://msdn.microsoft.com/en-us/library/windows/desktop/dn424963%28v=vs.85%29.aspx

In c#, the code would like this (untested):

using System.Runtime.InteropServices;

public static class MyClass
{
    [DllImport("Kernel32.dll")]
    public static extern Boolean IsWindowsServer();
}

And then the consumption code would simply be:

bool is_it_a_server = MyClass.IsWindowsServer();

I've never used any of these functions so let me know how it works...

Upvotes: -1

Pierre Arnaud
Pierre Arnaud

Reputation: 10547

Thanks to pointers provided by Nick's answer, I've finally found what I was looking for. The function IsOS(OS_ANYSERVER) does exactly what I need. Here is the sample code which should work for any OS version (including pre-Vista, since we import the IsOS function by ordinal from shlwapi.dll):

class OS
{
    public static bool IsWindowsServer()
    {
        return OS.IsOS (OS.OS_ANYSERVER);
    }

    const int OS_ANYSERVER = 29;

    [DllImport("shlwapi.dll", SetLastError=true, EntryPoint="#437")]
    private static extern bool IsOS(int os);
}

Upvotes: 28

nick
nick

Reputation: 3458

You can p/invoke the following Win32 functions:

GetProductInfo for Vista/Windows Server 2008+
GetVersionEx for Windows 2000+

BJ Rollison has a good post and sample code about this on his blog.

Upvotes: 6

Related Questions