Case of the SCVMM 2012 Console Install Fail on Windows 8

In my quest for testing software on the Windows Developer Preview x64 release (a.k.a Windows 8) I had to test Microsoft’s System Centre Virtual Machine Manager 2012 Beta console. So I had the product downloaded from MSDN and was ready to use the Windows 8 “Mount ISO” feature. However it had disappeared from Explorer.

image

Turns out when any program takes over the default action on ISO files you loose the ability to mount them. Hopefully in beta we can see that addressed. Simply changing the default program back to Explorer will fix the issue

image

image

This now gave me the mount options…

image

This however threw an error “Virtual Machine Manager server is not supported on this operating system. For more information, see ‘Supported Operating Systems for VMM’ in Virtual Machine Manager Setup Help.

image

OK as the product worked on Windows 7 the first thing was to enable Windows 7 compatibility mode by right clicking .exe and selecting Properties. However because my local account is not a member of local administrators, and the install I am running under another account I need to ensure I make this change for All Users

image

So I set it to Windows 7…

image

OK sweet, this got me past the first error…

image

Then *boom* another version check, this time it failed…

image

Using Process Explorer (http://live.sysinternals.com/ProcExp.exe) I found that it was actually extracting into the temp folder and running from there.

image

The .EXE in the temp folder did not have compatibility mode selected

image

So I copied this temp folder into another temp folder and set it to Windows 7 compatibility mode. I then quit the current installation. (which deleted the temp files in old location)

The from an Administrative command prompt I then ran my setupvm.exe with appropriate cmd line

SetupVM.exe  /spawned /SetupLocation  “F:\amd64\1033\LaunchScreen.DLL\..\..\\” /runui /server

image

However this still failed…

So I launched the app with Process Monitor http://live.sysinternals.com/ProcMon.exe filtering on Process Name is SetupVM.exe

Using ProcMon I found a log file was being written out to disk…

image

<Result StatusCode=”2″>
    <Id>505A6D8E-53CA-4512-AD58-ADED6FC57176</Id>
    <Status>Failed</Status>
    <Check>Operating System Version Check</Check>
    <Components>
      <Component>UI</Component>
    </Components>
    <Description>The system check was not passed.
The VMM 2012 console cannot be installed on a computer running an operating system that is earlier than Windows Vista, Windows 7, Windows Server 2008 x64, or Windows Server 2008 R2 x64.</Description>
    <Resolution>Upgrade the operating system on this computer, or install the VMM 2012 console on a computer that runs an operating system that meets the system requirements.</Resolution>
    <LogInformation>&lt;![CDATA[CheckPrerequisites:                 ProductType was not a match.  Looking for: ServerNT Found: WinNTCheckPrerequisites:         Logic Type:or    OSVersion-w2k8-Fail: 2CheckPrerequisites:                 ProductType was not a match.  Looking for: LanmanNT Found: WinNTCheckPrerequisites:         Logic Type:or    OSVersion-w2k8DC-Fail: 2CheckPrerequisites:                 ProductType was not a match.  Looking for: ServerNT Found: WinNTCheckPrerequisites:         Logic Type:or    OSVersion-w2k8R2-Fail: 2CheckPrerequisites:                 ProductType was not a match.  Looking for: LanmanNT Found: WinNTCheckPrerequisites:         Logic Type:or    OSVersion-w2k8R2DC-Fail: 2CheckPrerequisites:                 The value 6.2.8102.0 was not within the range 6.0.6000.0 to 6.0.9999.CheckPrerequisites:         Logic Type:or    OSVersion-Vista-Fail: 2CheckPrerequisites:                 The value 6.2.8102.0 was not within the range 6.1.7600.0 to 6.1.9999.9999.CheckPrerequisites:         Logic Type:or    OSVersion-win7-Fail: 2]]&gt;</LogInformation>
  </Result>

I also tried applying a Windows 7 Version Lie SHIM via Microsoft Application Compatibility Toolkit 6.0, still failing.

In ProcMon I did a filter on Details contains “6.2” but found no results. (i.e. a reg query) Another way I thought it might be trying version detection is via checking version of a Windows DLL, but I couldn’t identify this clearly from the ProcMon tracing.

So I resorted to .NET Reflector, as the SetupVM.exe was a .NET executable (Process Explorer identified this) .NET reflector allows you to de-compile .NET code very close to original source code (if program is not obfuscated) In addition it allows you to step through a .NET application in Visual Studio 2010, even without original source code. It is available for 30-day trial then it must be purchased. If you do any .NET debugging it’s a must-have tool. You can download from http://www.reflector.net

image

So we can see how the OS check has been performed here:

public static bool IsWindowsVista()
{
    ReturnInformation information = RequiredOperatingSystem("6.0.6000.18000,6.0.6001.65537,Win32NT,WinNT,2", string.Empty);
    return (0 == information.StatusCode);
}

Clicking RequiredOperatingSystem gave me the function being called

public static ReturnInformation RequiredOperatingSystem(string arguments, string formatValue)
{
    Version version;
    Version version2;
    string str;
    string str2;
    ReturnInformation information = new ReturnInformation();
    if (string.IsNullOrEmpty(arguments))
    {
        information.LogInformation.Append("RequiredOperatingSystem: arguments is null.  This is not valid.");
        Trc.Log(LogLevel.Error, "RequiredOperatingSystem: arguments is null.  This is not valid.");
        throw new ArgumentNullException("arguments");
    }
    string[] strArray = arguments.Split(new char[] { ',' });
    if (strArray.Length == 5)
    {
        version = new Version(strArray[0]);
        version2 = new Version(strArray[1]);
        str = strArray[2];
        str2 = strArray[3];
        information.StatusCode = Convert.ToInt32(strArray[4], CultureInfo.InvariantCulture);
    }
    else
    {
        information.LogInformation.Append("RequiredOperatingSystem: invalid number or arguments.");
        Trc.Log(LogLevel.Error, "RequiredOperatingSystem: invalid number or arguments.");
        throw new ArgumentException(arguments);
    }
    if (!string.IsNullOrEmpty(str2))
    {
        string str3 = (string) Registry.GetValue(@"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ProductOptions", "ProductType", null);
        if (str3 == null)
        {
            information.LogInformation.AppendLine("CheckPrerequisites: \t\t\t\tCould not open ProductType key.");
            Trc.Log(LogLevel.Debug, "CheckPrerequisites: \t\t\t\tCould not open ProductType key.");
            return information;
        }
        if (!str3.Equals(str2, StringComparison.OrdinalIgnoreCase))
        {
            information.LogInformation.AppendFormat("CheckPrerequisites: \t\t\t\tProductType was not a match.  Looking for: {0} Found: {1}", str2, str3);
            Trc.Log(LogLevel.Debug, "CheckPrerequisites: \t\t\t\tProductType was not a match.  Looking for: {0} Found: {1}", str2, str3);
            return information;
        }
    }
    if (string.Equals(Environment.OSVersion.Platform.ToString(), str))
    {
        if ((0 <= Environment.OSVersion.Version.CompareTo(version)) && (0 > Environment.OSVersion.Version.CompareTo(version2)))
        {
            information.StatusCode = 0;
            return information;
        }
        information.LogInformation.AppendFormat("CheckPrerequisites: \t\t\t\tThe value {0} was not within the range {1} to {2}.", Environment.OSVersion.Version.ToString(), version.ToString(), version2.ToString());
        Trc.Log(LogLevel.Debug, "CheckPrerequisites: \t\t\t\tThe value {0} was not within the range {1} to {2}.", Environment.OSVersion.Version.ToString(), version.ToString(), version2.ToString());
        return information;
    }
    information.LogInformation.AppendFormat("CheckPrerequisites: \t\t\t\tThe platform value of {0} was not equal to {1}.", Environment.OSVersion.Platform.ToString(), str);
    Trc.Log(LogLevel.Debug, "CheckPrerequisites: \t\t\t\tThe platform value of {0} was not equal to {1}.", Environment.OSVersion.Platform.ToString(), str);
    return information;
}

So we could see the code was essentially using .NET library Environment.OSVersion.Version.ToString());

So we then again examine with .NET reflector the .NET library code to get OS version

public static OperatingSystem OSVersion
{
    [SecuritySafeCritical]
    get
    {
        if (m_os == null)
        {
            PlatformID winCE;
            bool flag;
            Win32Native.OSVERSIONINFO osVer = new Win32Native.OSVERSIONINFO();
            if (!GetVersion(osVer))
            {
                throw new InvalidOperationException(GetResourceString("InvalidOperation_GetVersion"));
            }
            switch (osVer.PlatformId)
            {
                case 2:
                    winCE = PlatformID.Win32NT;
                    flag = true;
                    break;

                case 3:
                    winCE = PlatformID.WinCE;
                    flag = false;
                    break;

                case 10:
                    winCE = PlatformID.Unix;
                    flag = false;
                    break;

                case 11:
                    winCE = PlatformID.MacOSX;
                    flag = false;
                    break;

                default:
                    throw new InvalidOperationException(GetResourceString("InvalidOperation_InvalidPlatformID"));
            }
            Win32Native.OSVERSIONINFOEX osversioninfoex = new Win32Native.OSVERSIONINFOEX();
            if (flag && !GetVersionEx(osversioninfoex))
            {
                throw new InvalidOperationException(GetResourceString("InvalidOperation_GetVersion"));
            }
            Version version = new Version(osVer.MajorVersion, osVer.MinorVersion, osVer.BuildNumber, (osversioninfoex.ServicePackMajor << 0x10) | osversioninfoex.ServicePackMinor);
            m_os = new OperatingSystem(winCE, version, osVer.CSDVersion);
        }
        return m_os;
    }
}

As a result we find out that the OS version is obtained using the Windows Native API GetVersion http://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx

[MethodImpl(MethodImplOptions.InternalCall), SecurityCritical]
internal static extern bool GetVersion(Win32Native.OSVERSIONINFO osVer);

But doesn’t the Version Lie SHIM GetVersion & GetVersionEx Windows APIs. Yes! But not if they’re running under Managed Code! (.NET) http://blogs.msdn.com/b/cjacks/archive/2007/09/10/version-lie-shims-and-managed-code-on-windows-vista.aspx

You can prove this with following C# code and SHIM away to no affect…

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WhatIsMyOS
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Environment.OSVersion.Version.ToString());
        }
    }
}

And we will do the similar in “native” code using C++

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    OSVERSIONINFO osvi;
    BOOL bIsWindowsXPorLater;

    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    GetVersionEx(&osvi);

    printf(“%d.%d.%d”,osvi.dwMajorVersion,osvi.dwMinorVersion,osvi.dwBuildNumber);
    return 0;
}

Run #1 – No Shims Applied

image

I now create & install Win7RTMVersionLie SHIMs.

image

Run #2 – Win7Version Lie SHIM applied

image

Yes, the C# .NET Managed Code is not affected. But don’t worry – .NET applications are a reverse engineers dream come true, being about a million times easier to patch a .NET binary than a Win32 binary.

I want to run my app!!! Well I’m going for brute force method here! I copied all the installation files to a local “working directory”

image

I’m now going to need the .NET 4.0 Framework SDK (Because this .EXE is .NET 4.0 based)

This is available here http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8442

We decompile the assembly to IL code…ILDasm has many more options, documented here http://msdn.microsoft.com/en-us/library/f7dy01k1

image

We now open up the IL file…I can see the conditional jump if the “IsWindowsVista” check fails…

image

I did try to edit the IL code and re-compile it but didn’t have much success there, (maybe not enough sleep?) But I can see this function is in SetupFramework…I replaced the versions in the binary , the DLL still loaded fine, but still failed on version check.

image

I then finally noticed something in ProcMon trace – Pre-Requisite files. Oops. When I was ‘reflecting’ I didn’t spend enough time to notice about this…

image

The PrerequisiteInputFile*.xml contained the OS version detection logic. Now I guessed just from the type of numbers that they represented language of install. So note to fix install for *every* language you would need to update each XML. As I was just using English I only fixed the file ending in 1033.xml.

<LogicDelegates>
      <LogicDelegate LogicType=”or”
                     DelegateId=”OSVersion-w2k8-Fail”
                     DelegateNameSpace=”Microsoft.VirtualManager.SetupFramework.BuiltInDelegates,SetupFramework”
                     DelegateName=”RequiredOperatingSystem”>
        6.0.6001.0,6.0.7000,Win32NT,ServerNT,2
      </LogicDelegate>
      <LogicDelegate LogicType=”or”
                     DelegateId=”OSVersion-w2k8DC-Fail”
                     DelegateNameSpace=”Microsoft.VirtualManager.SetupFramework.BuiltInDelegates,SetupFramework”
                     DelegateName=”RequiredOperatingSystem”>
        6.0.6001.0,6.0.7000,Win32NT,LanmanNT,2
      </LogicDelegate>
      <LogicDelegate LogicType=”or”
                     DelegateId=”OSVersion-w2k8R2-Fail”
                     DelegateNameSpace=”Microsoft.VirtualManager.SetupFramework.BuiltInDelegates,SetupFramework”
                     DelegateName=”RequiredOperatingSystem”>
        6.1.7600.0,6.1.9999.9999,Win32NT,ServerNT,2
      </LogicDelegate>
      <LogicDelegate LogicType=”or”
                     DelegateId=”OSVersion-w2k8R2DC-Fail”
                     DelegateNameSpace=”Microsoft.VirtualManager.SetupFramework.BuiltInDelegates,SetupFramework”
                     DelegateName=”RequiredOperatingSystem”>
        6.1.7600.0,6.1.9999.9999,Win32NT,LanmanNT,2
      </LogicDelegate>
      <LogicDelegate LogicType=”or”
                     DelegateId=”OSVersion-Vista-Fail”
                     DelegateNameSpace=”Microsoft.VirtualManager.SetupFramework.BuiltInDelegates,SetupFramework”
                     DelegateName=”RequiredOperatingSystem”>
        6.0.6000.0,6.0.9999,Win32NT,WinNT,2
      </LogicDelegate>
      <LogicDelegate LogicType=”or”
                     DelegateId=”OSVersion-win7-Fail”
                     DelegateNameSpace=”Microsoft.VirtualManager.SetupFramework.BuiltInDelegates,SetupFramework”
                     DelegateName=”RequiredOperatingSystem”>
        6.1.7600.0,6.1.9999.9999,Win32NT,WinNT,2
      </LogicDelegate>
    </LogicDelegates>

I simplify modified the Windows 7 detection rule from 6.1.7600.0,6.1.9999.9999 to 6.1.7600.0,9.9.9999.9999

OK we made it past the pre-req check!image

 

image

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in .NET, Application Compatibility, Windows 8 and tagged . Bookmark the permalink.

10 Responses to Case of the SCVMM 2012 Console Install Fail on Windows 8

  1. ashconllc says:

    nice work, man. thanks for posting this.

  2. gil dotan says:

    thanks man ! after changing the compatibility of the main setup.exe, and just before installing the console changing the temp xml file everything was managed to install !! thank you.

  3. Exotic Hadron says:

    Hi, does the trick work on RTM?

  4. Mattias Nygren says:

    Yes I can confirm it works on Windows 8 RTM

    • Exotic Hadron says:

      Hi, Mattias!
      Thank you for your response. I actually meant to say if the trick works for *RTM version of SCVMM* (not the OS)? I changed the XMLs but the wizard keeps saying it won’t install because my OS is incompatible. Possibly something has changed in how the RTM version of SCVMM checks for the target OS version.
      Thank you.

  5. Ashley Rutland says:

    Is there not a simpler way to get round this?

  6. Sebastian says:

    to install SCVMM2012 in Windows 8 RTM, you need to edit the “PrerequisiteInputFile1033” or whatever languaje you use, and replace in the whole file the “6.1.7600.0,6.1.9999.9999” to “6.2.9200.0,6.2.9999.9999” it seems that the build numer changed from this article to the final version.

    • Exotic Hadron says:

      Hi, Sebastian,
      Thank you for your response!
      The article speaks of installing beta version of SCVMM 2012 on beta version of Windows 8.
      It’s understood that you can trick beta version of SCVMM 2012 to install it on RTM version of Windows 8. Can you however trick the RTM version of SCVMM? I’ve tried replacing build numbers of Windows 7 (6.1.7600.x,x.x) with the build number of Windows 8 (6.2.8400.* for Release Preview and 6.2.9200.* for RTM) but that did NOT work for RTM version of SCVMM 2012. It still says that setup cannot continue because of incompatible OS.
      BTW, do I have to install WAIK for Windows 7 to install SCVMM 2012 on Windows 8?

      Thank you.

  7. Gustavo says:

    brilliant! thanks a lot! =)

  8. Nick says:

    great Post Nicely DONE!! I simply modified the .xml files ending with 1033 to the updated version check and changed the setup.exe to win 7 mode and installed without a hitch!!

Leave a comment