krembanan
krembanan

Reputation: 1428

Reading registry key fails with MSBuild Extension Pack 4.0

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>

Upvotes: 2

Views: 1861

Answers (4)

VAV
VAV

Reputation: 1896

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.

Upvotes: 0

Thierry Franzetti
Thierry Franzetti

Reputation: 1863

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>

Upvotes: 2

Filburt
Filburt

Reputation: 18062

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.

Upvotes: 2

krembanan
krembanan

Reputation: 1428

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;
            }
        }
    }
}

Upvotes: 0

Related Questions