2

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>
krembanan
  • 1,408
  • 12
  • 28

4 Answers4

2

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>
Thierry Franzetti
  • 1,763
  • 12
  • 12
  • Thanks Thierry, this project is no longer operating, but good to know there are built in ways to access both 64 and 32 bit versions of the registry. I haven't tested this, but changing my accepted solution as this is a much better way to solve it. – krembanan Feb 10 '15 at 06:11
2

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.

Filburt
  • 17,626
  • 12
  • 64
  • 115
  • Thanks. This put me on the right path along with http://stackoverflow.com/questions/2197086/create-64-bit-registry-key-non-wow64-from-a-32-bit-application – krembanan Jul 02 '10 at 10:20
  • @Henrik: You're welcome ... but I think you're overdoing it a little with creating a custom task for this. – Filburt Jul 02 '10 at 11:37
  • I totally agree that this is over-engineered if I had control over the version of msbuild that runs across the developer machines. Unfortunately I don't (yet), so this seemed the quickest and most compatible way to go. – krembanan Jul 05 '10 at 10:48
0

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;
            }
        }
    }
}
Community
  • 1
  • 1
krembanan
  • 1,408
  • 12
  • 28
0

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.

VAV
  • 1,756
  • 1
  • 16
  • 26