powershellmatchingdword

How to delete REG_DWORD registry value where registry value like '*String*' using PowerShell?


PowerShell is presenting registry values (and their registry data) as an array in $\_.Property in their parent registry key. How do I select and delete only the registry values where the value is like \*String\* ?

I have tried searching high and low on StackOverflow and on Google trying many combinations that involve Get-Item, Get-ItemProperty, Get-ChildItem, Select-Object (including -ExpandProperty parameter), and Where-Object to select the registry values that I want (prior to moving on to incorporating deletion). I am now at a point where I am entirely clueless and unable to figure out how to simply find registry values like \*Text\* existing at a particular registry key and delete them. Something so simple seems so difficult! I do not know how to work with data in arrays!

Get-Item -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs

Every registry value is being listed as part of an array under $\_.Property for registry key HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs. I was expecting results where I could do something roughly like $\_.RegistryValue -Like '\*Text\*' | Remove-Item to delete the registry values matching \*Text\*.

For clarification to ensure correct technical usage of certain vocabulary, a "registry key" appears as a folder in regedit.exe.

A "registry value" is an entry of any type such as REG\_SZ, REG\_DWORD, REG\_MZ, and so on. A registry value contains "registry data", and depending on the registry type, it may be a string, an 32-bit value (sometimes expressed as either 1, 0, or 0x000000, 0x000001).

We often refer to "registry values" as 'registry keys' (which is incorrect technical usage) and the "registry data" as 'registry values' (also incorrect technical usage), and "registry keys" as folders/location/"this place in the registry".


Solution

  • Removing registry values by value name filter only:

    Update, based on your own simplification:

    # The target registry key's full path.
    $keyPath = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs'
    
    # Pass the value name pattern to Remove-ItemProperty's -Name parameter.
    # Remove `-WhatIf` if the preview suggests that the operation works as intended.
    Remove-ItemProperty -Path $keyPath -Name *Text* -WhatIf
    

    Pitfall: If you want to use a wildcard expression such as *Text* with -Name, you must combine it with -Path rather than -LiteralPath, even if the key path is itself not a wildcard; with
    -LiteralPath, -Name too is then taken literally (verbatim).

    If you do need to use -LiteralPath (e.g., if the literal path contains a * character, such as in HKEY_CLASSES_ROOT\*):

    # The target registry key's full path.
    $keyPath = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs'
    
    # Get an array of all value names that match the name wildcard pattern.
    $valueNames = (Get-Item -LiteralPath $keyPath).Property -like '*Text*'
    
    # Pass the array of value names to Remove-ItemProperty's -Name parameter.
    # Remove `-WhatIf` if the preview suggests that the operation works as intended.
    if ($valueNames) {
      Remove-ItemProperty -LiteralPath $keyPath -Name $valueNames -WhatIf
    }
    

    Note the use of Get-Item rather than Get-ItemProperty.[1]

    Get-Item returns an object representing the entire key that is of type [Microsoft.Win32.RegistryKey], which PowerShell decorates with a .Property note property that contains an array of all the key's value names.

    Important: In the .Property array, PowerShell translates the default value name, which is the empty string ('') at the API level, into name '(default)'.

    Applying operator -like to an array LHS makes it act as a filter that only returns a sub-array of matching items.

    Remove-ItemProperty's -Name parameter directly accepts an array of property (registry value) names to remove from the target key.


    Removing values by value name and/or data filter:

    Note: Due to use of the -PipelineVariable common parameter, this solution requires PSv4+.

    # The target registry key's full path.
    $keyPath = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs'
    
    $pattern = '*Text*'
    
    # Look for $pattern in both the name and the data.
    # Remove `-WhatIf` if the preview suggests that the operation works as intended.
    Get-Item -LiteralPath $keyPath -PipelineVariable key |
      ForEach-Object Property | 
        Where-Object { 
          $valueName = ($_, '')[$_ -eq '(default)'] # translate '(default)' to '' for API
          $valueName -like $pattern -or $key.GetValue($valueName) -like $pattern 
        } |
          Remove-ItemProperty -LiteralPath $keyPath -WhatIf
    

    If you simply want to list matching values and their data, see this answer.


    [1] Get-ItemProperty -Path $keyPath -Name *Text* technically works too, but the output is a single object of type [pscustomobject], whose properties you have to enumerate via reflection, because the property names reflect the matching value names; while doing so via .psobject.properties as shown in this answer works and allows you to filter by data too, the pitfall is that PowerShell's registry provider automatically adds its own properties to the collection of properties, namely PSPath, PsParentPath, PSChildName, PSDrive, PSProvider, which means that a wildcard expression that filters by name can accidentally include them or, worse, if values by the same name happen to exist on the key (even though unlikely), the provider properties overrides them.