Daniil Romme
Daniil Romme

Reputation: 69

RegistryValueKind NONE

How can I set a none data type.[Microsoft.Win32.RegistryValueKind]::None in Powershell 2.0? Powershell 2.0 has types "Unknown, String, ExpandString, Binary, DWord, MultiString, QWord".
learn.microsoft.com

Upvotes: 1

Views: 766

Answers (2)

mklement0
mklement0

Reputation: 437708

(As implied in your question), [Microsoft.Win32.RegistryValueKind]::None (which translates to a REG_NONE registry value) requires at least .NET Framework 4, whereas Windows PowerShell v2 is built on .NET Framework 2. (Only Windows PowerShell v3 and above are built on .NET Framework 4 and above).

Unlike C#, PowerShell does not allow you to pass the numerical value of an enum-typed parameter if that value doesn't represent an officially defined member of that enumeration (at that time, in the underlying framework), so attempting to pass (-1), the value of [Microsoft.Win32.RegistryValueKind]::None, does not work in Windows PowerShell v2 - neither with New-ItemProperty / Set-ItemProperty's -Type parameter, nor with .NET API calls ([Microsoft.Win32.Registry]::SetValue(...)).

Therefore, in Windows PowerShell v2, calling the Windows API via P/Invoke declarations implemented via Add-Type is probably your only option - see the RegSetKeyValue() WinAPI function (among others).

Building on your own helpful answer, here's a streamlined solution, which:

  • uses Add-Type's -MemberDefinition parameter to simplify creation of types that wrap P/Invoke calls.

  • Exposes a static [WinApiHelper.Registry]::SetNoneValue() method, which:

    • focuses only on creating REG_NONE values

    • also supports creating such values with byte data ([byte[]] arrays)

    • has no return value, but throws a Win32Exception should an error occur.

Add-Type -Namespace WinApiHelper -Name Registry -MemberDefinition @'
    public enum HKEY : uint
    {
        HKEY_CLASSES_ROOT = 0x80000000,
        HKEY_CURRENT_CONFIG = 0x80000005,
        HKEY_CURRENT_USER = 0x80000001,
        HKEY_LOCAL_MACHINE = 0x80000002,
        HKEY_USERS = 0x80000003
    }
    
    [DllImport("advapi32.dll")]
    private static extern int RegSetKeyValue(
      HKEY hkey, 
      string lpSubKey,
      string lpValueName,
      UInt32 type, 
      byte[] data, 
      UInt32 dataLength
    );

    public static void SetNoneValue(HKEY hkey, string subkey, string valuename, byte[] bytes)
    {
      int rc = RegSetKeyValue(hkey, subkey, valuename, 0 /* REG_NONE */, bytes, (UInt32) (bytes == null ? 0 : bytes.Length));
      if (rc != 0) {
        // Access the error code in PowerShell with $Error[0].Exception.InnerException.NativeErrorCode
        throw new System.ComponentModel.Win32Exception(rc);
      }
    }

    // Overload that creates an empty value.
    // Note: .NET 2 doesn't support optional parameters, so an explicit overload is required.
    public static void SetNoneValue(HKEY hkey, string subkey, string valuename) {
      SetNoneValue(hkey, subkey, valuename, null);
    }

'@

Sample calls:

# Create an empty REG_NONE value named 'bar1' in key HKEY_CURRENT_USER\foo.
[WinApiHelper.Registry]::SetNoneValue('HKEY_CURRENT_USER', 'foo', 'bar1')

# Create a REG_NONE value named 'bar2' with a byte array.
[WinApiHelper.Registry]::SetNoneValue('HKEY_CURRENT_USER', 'foo', 'bar2', [byte[]] (42, 43))

Upvotes: 2

Daniil Romme
Daniil Romme

Reputation: 69

Add-Type -TypeDefinition @"
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles;
    namespace AdvapiSolution
    {
        public class Advapi
        {
            public enum HKEY : uint
            {
                HKEY_CLASSES_ROOT = 0x80000000,
                HKEY_CURRENT_USER = 0x80000001,
                HKEY_LOCAL_MACHINE = 0x80000002,
                HKEY_USERS = 0x80000003,
                HKEY_PERFORMANCE_DATA = 0x80000004,
                HKEY_PERFORMANCE_TEXT = 0x80000050,
                HKEY_PERFORMANCE_NLSTEXT = 0x80000060,
                HKEY_CURRENT_CONFIG = 0x80000005
            }
            
            private enum VALUE_TYPE : uint
            {
                REG_NONE= 0,
                REG_SZ = 1,
                REG_EXPAND_SZ = 2,
                REG_BINARY = 3,
                REG_DWORD = 4,
                REG_DWORD_LITTLE_ENDIAN = 4,
                REG_DWORD_BIG_ENDIAN = 5,
                REG_LINK = 6,
                REG_MULTI_SZ = 7,
                REG_RESOURCE_LIST = 8,
                REG_FULL_RESOURCE_DESCRIPTOR = 9,
                REG_RESOURCE_REQUIREMENTS_LIST = 10,
                REG_QWORD_LITTLE_ENDIAN = 11
            }

            [DllImport("advapi32.dll", CharSet = CharSet.Auto, BestFitMapping = false)]
            private static extern int RegSetKeyValueW  (
            HKEY hkey, 
            string lpSubKey,
            string lpValueName,
            VALUE_TYPE type, 
            byte[] data, 
            uint dataLength);
            public int set_key(HKEY hkey, string subkey, string valuename){
                return RegSetKeyValueW(hkey, subkey, valuename, VALUE_TYPE.REG_NONE, null, 0);
            }
       }
}
"@

In my case data equals null and type is REG_NONE. You can change set_key as you like with object:

$Advapiobject = New-Object 'AdvapiSolution.Advapi'
$Advapiobject.set_key('HKEY_CURRENT_USER',$yoursubkey, $yourvaluename, 'REG_NONE')

Another way is using a static method set_key. Change set_key to public static int set_key:

[AdvapiSolution.Advapi]::set_key('HKEY_CURRENT_USER',$yoursubkey, $yourvaluename, 'REG_NONE').

If it returns 0, it's okay. If the function fails, the return value is a nonzero error code defined in Winerror.h.

System Error Codes

Upvotes: 3

Related Questions