Question

I am using MSBuild Extension Pack 4.0 to do my local development deployment. When using the class MSBuild.ExtensionPack.Computer.Registry to read a registry key (to get an installation directory) it fails saying the path is invalid. I believe this is due to msbuild being a 32-bit process, so it can only see:

HKEY_LOCAL_MACHINE\Software\SysWow6432\*

and not

HKEY_LOCAL_MACHINE\Software\*

Has anyone found a way around this without reverting to developing a custom tool?

My actual script:

<MSBuild.ExtensionPack.Computer.Registry TaskAction="Get" RegistryHive="LocalMachine" Key="SOFTWARE\Microsoft\MSCRM" Value="CRM_Server_InstallDir">
  <Output PropertyName="CrmPath" TaskParameter="Data"/>
</MSBuild.ExtensionPack.Computer.Registry>
Was it helpful?

Solution

If you are using MSBuild 4.0 you can as well iuse the built-in property function GetRegistryValueFromView (documented at https://msdn.microsoft.com/en-us/library/dd633440.aspx#BKMK_GetRegistryValueFromView). This functions allows to specify the 64-bits or 32-bits view (or both)

Your call would look like :

<PropertyGroup>
    <CrmPath>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM', 'CRM_Server_InstallDir', null, RegistryView.Registry64, RegistryView.Registry32))</CrmPath>
</PropertyGroup>

OTHER TIPS

Did you already try MSBuilds builtin support for reading the registry?

<PropertyGroup>
    <CrmPath>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM@CRM_Server_InstallDir</CrmPath>
</PropertyGroup>

Learned this myself from this blog posting.

Furthermore you can run MSBuild in both x86 and x64:

%WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe

and

%WINDIR%\Microsoft.NET\Framework64\v3.5\MSBuild.exe

Edit

Even if you're dealing with a multitarget environment you could solve this with builtin means.

<!-- MSBuild 3.5 x86 / AnyCPU -->
<PropertyGroup Condition=" '$(MSBuildToolsPath)' == '$(windir)\Microsoft.NET\Framework\v3.5' AND '$(Platform)' == 'AnyCPU' ">
    <CrmPath>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\SysWow64\*)</CrmPath>
</PropertyGroup>

<!-- MSBuild 3.5 x64 -->
<PropertyGroup Condition=" '$(MSBuildToolsPath)' == '$(windir)\Microsoft.NET\Framework64\v3.5' AND '$(PLatform)' == 'x64' ">
    <CrmPath>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\*)</CrmPath>
</PropertyGroup>

MSBuild is usually able to tell what environment it is dealing with so you can cater for every possible combination and use the same script on all kinds of machines.

I solved this by looking at the new capabilities of .NET 4.0 (as suggested here: Create 64 bit registry key (non-WOW64) from a 32 bit application)

I can now specify in the lookup if I need a 32-bit or 64-bit value:

<GetWindowsRegistryValue Key="SOFTWARE\Microsoft\MSCRM" Value="CRM_Server_InstallDir" Hive="LocalMachine" View="Registry64">
  <Output PropertyName="CrmPath" TaskParameter="Setting"/>
</GetWindowsRegistryValue>

And the custom (quick and dirty) task:

namespace Utilities.CustomBuildTasks
{
    using System;
    using Microsoft.Build.Framework;
    using Microsoft.Win32;

    /// <summary>
    /// Defines the custom task to retrieve registry values.
    /// </summary>
    public class GetWindowsRegistryValue : ITask
    {
        /// <summary>
        /// Gets or sets the build engine associated with the task.
        /// </summary>
        /// <value></value>
        /// <returns>The build engine associated with the task.</returns>
        public IBuildEngine BuildEngine
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets any host object that is associated with the task.
        /// </summary>
        /// <value></value>
        /// <returns>The host object associated with the task.</returns>
        public ITaskHost HostObject
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        /// <value>The registry key.</value>
        [Required]
        public string Key
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        [Required]
        public string Value
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the hive.
        /// </summary>
        /// <value>The registry hive.</value>
        [Required]
        public string Hive
        {
            get
            {
                return this.hive.ToString();
            }

            set
            {
                this.hive = (RegistryHive)Enum.Parse(typeof(RegistryHive), value);
            }
        }

        /// <summary>
        /// The hive enumeration value.
        /// </summary>
        private RegistryHive hive;

        /// <summary>
        /// Gets or sets the view.
        /// </summary>
        /// <value>The view (64-bit/32-bit).</value>
        [Required]
        public string View
        {
            get
            {
                return this.view.ToString();
            }

            set
            {
                this.view = (RegistryView)Enum.Parse(typeof(RegistryView), value);
            }
        }

        /// <summary>
        /// The view enumeration value.
        /// </summary>
        private RegistryView view;

        /// <summary>
        /// Gets or sets the setting.
        /// </summary>
        /// <value>The setting.</value>
        [Output]
        public string Setting
        {
            get;
            set;
        }

        /// <summary>
        /// Executes a task.
        /// </summary>
        /// <returns>
        /// true if the task executed successfully; otherwise, false.
        /// </returns>
        public bool Execute()
        {
            try
            {
                var baseKey = RegistryKey.OpenBaseKey(this.hive, this.view);

                var subKey = baseKey.OpenSubKey(this.Key);

                if (subKey == null)
                {
                    return false;
                }

                this.Setting = subKey.GetValue(this.Value).ToString();

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}

With MSBuild Extension Pack 4.0 you also can create, modify and delete registry keys and values. But if you only plan to read you may take a look at @Thierry answer first.

For x64 registry node view

<MSBuild.ExtensionPack.Computer.Registry TaskAction="Get" RegistryView="Registry64" RegistryHive="LocalMachine" Key="SOFTWARE\Microsoft\MSCRM" Value="CRM_Server_InstallDir">
    <Output PropertyName="CrmPath" TaskParameter="Data"/>
</MSBuild.ExtensionPack.Computer.Registry>

For x86 registry node view

<MSBuild.ExtensionPack.Computer.Registry TaskAction="Get" RegistryView="Registry32" RegistryHive="LocalMachine" Key="SOFTWARE\Microsoft\MSCRM" Value="CRM_Server_InstallDir">
    <Output PropertyName="CrmPath" TaskParameter="Data"/>
</MSBuild.ExtensionPack.Computer.Registry>

For more information see RegistryView on MSDN.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top