Powershell Find-And-Replace on registry values?

15,766

Solution 1

I figured it out. Took me a long time, but I wrote a rather inelegant script:

Get-Item -ErrorAction SilentlyContinue -path  "Microsoft.PowerShell.Core\Registry::HKEY_USERS\*\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" |
foreach {
    Get-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::$_" | 
    foreach {
        $CurrentUserShellFoldersPath = $_.PSPath
        $SID = $CurrentUserShellFoldersPath.Split('\')[2]
        $_.PSObject.Properties |
        foreach {
            if ($_.Value -like "*DeadServer*") {
                write-host "Path:`t`t"$CurrentUserShellFoldersPath
                write-host "SID:`t`t"$SID
                write-host "Name:`t`t"$_.Name
                write-host "Old Value:`t"$_.Value
                $newValue = $_.Value
                $newValue = $newValue -replace '\\\\DeadServer\\RedirectedFolders', "C:\Users"
                $newValue = $newValue -replace "My Documents\\", ""
                $newValue = $newValue -replace "My ", ""
                Write-Host "New Value:`t"$newValue
                Set-ItemProperty -Path $CurrentUserShellFoldersPath -Name $_.Name -Value $newValue

                Write-host "================================================================"
            }
        }
    }
}

I'd love to learn of a faster or more elegant way to do this if any of you have one.

Solution 2

Here's an easy to use registry replace function, which can search a path recursively.

# Replace all registry key values and/or registry key names under a given path.
# Example Usage:
#   RegistryValue-Replace "ExistingValue" "NewValue" 'HKEY_CURRENT_USER\Software\100000_DummyData'
#   RegistryValue-Replace "ExistingValue" "NewValue" 'HKEY_USERS\*\Software\100000_DummyData' -ReplaceKeyNames $true -CaseSensitive $true
#   RegistryValue-Replace 'C:\\Program Files\\Microsoft SQL Server' 'E:\Program Files\Microsoft SQL Server' 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server*' -LoggingOn $true

function RegistryValue-Replace (
  [string]$OldValue = $(throw “OldValue (the current value) required.”),
  [string]$NewValue = $(throw “NewValue (the replacement value) required.”),
  [string]$RegkPath = $(throw “RegkPath (The full registry key path) required.”),
  [bool] $CaseSensitive = $false, # If true, search and replace is case sensitive
  [bool] $WholeWord = $false, # If true, searches for whole word within the value.
  [bool] $ExactMatch = $false,  # If true, the entire value must match OldValue, and partial replacements are NOT performed
  [bool] $ReplaceKeyNames = $false, # If true, replaces registry key names
  [bool] $ReplaceValues = $true,
  [bool] $LoggingOn = $false ) 
{
    $PowershellRegPrefix = 'Microsoft.PowerShell.Core\Registry::'
    $MatchFor = if ($WholeWord -eq $true) {".*\b$OldValue\b.*"} else { ".*$OldValue.*" }
    if ($RegkPath -NotLike "$PowershellRegPrefix*") { $RegkPath = $PowershellRegPrefix + $RegkPath }

    @(Get-Item -ErrorAction SilentlyContinue -path  $RegkPath) +
    @(Get-ChildItem -Recurse $RegkPath -ErrorAction SilentlyContinue) |
    foreach {
        Get-ItemProperty -Path "$PowershellRegPrefix$_" | 
        foreach {
            $CurrentShellFoldersPath = $_.PSPath
            $SID = $CurrentShellFoldersPath.Split('\')[2]
            $_.PSObject.Properties |
            foreach {
                if ($_.Name -cne "PSChildName" -and (($ExactMatch -eq $true -and $_.Value -clike $OldValue) -or ($ExactMatch -eq $false -and
                    (($CaseSensitive -eq $false -and $_.Value -match $MatchFor) -or ($CaseSensitive -eq $true -and $_.Value -cmatch $MatchFor))))) {
                    $Original = $_.Value
                    $Create_NewValue = $_.Value
                    $SubKeyName = $_.Name
                    if ($CaseSensitive -eq $true){ $Create_NewValue = $Create_NewValue -creplace $OldValue, $NewValue }
                    else                         { $Create_NewValue = $Create_NewValue -replace  $OldValue, $NewValue }
                    if ($_.Name -eq "PSPath" -and $_.Value -eq $CurrentShellFoldersPath) {
                        if ($ReplaceKeyNames -eq $true) {
                            Move-Item -Path $CurrentShellFoldersPath -Destination $Create_NewValue
                            if ($LoggingOn -eq $true){ Write-host "Renamed registry key '$CurrentShellFoldersPath' to '$Create_NewValue'" }
                        } else {
                            if ($LoggingOn -eq $true){ Write-host "....Skipping renaming key '$CurrentShellFoldersPath->$SubKeyName' due to input option!!!" } }
                    } else {
                        if ($ReplaceValues -eq $true) {
                            Set-ItemProperty -Path $CurrentShellFoldersPath -Name $_.Name -Value $Create_NewValue
                            if ($LoggingOn -eq $true){ Write-host "Renamed '$Original' to '$Create_NewValue' for registry key '$CurrentShellFoldersPath->$SubKeyName'" }
                        } else {
                            if ($LoggingOn -eq $true){ Write-host "....Skipping renaming value '$CurrentShellFoldersPath->$SubKeyName' due to input option!!!" } }
                    }
                }
            }
        }
    }
}

Solution 3

Not really happy with this so I will be happy and sad if someone puts this to shame. It's been mostly tested as far as verifying that it is locating the correct keys.

If(!(Test-Path HKU:)){New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS}
$registrySearchPath = "HKU:\*\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
$pathToReplace = [regex]::Escape("C:\Users")
$newPath = '%USERPROFILE%'
Get-Item -path $registrySearchPath -ErrorAction SilentlyContinue | 
        Select-Object -ExpandProperty Name | 
        Where-Object{$_ -match "^HKEY_USERS\\S-1-5-21"} |
        ForEach-Object{
    $key = $_ -replace "^HKEY_USERS","HKU:"
    (Get-ItemProperty $key).psobject.Properties | Where-Object{$_.Value -match $pathToReplace} | 
            Select-Object Name,Value | ForEach-Object{
        Set-ItemProperty -Path $key -Name $_.Name -Value ($_.Value -replace $pathToReplace,$newPath) -WhatIf
    }
}

Use a Psdrive to map HKU since its not a default drive in PowerShell. Get all keys back that have at least a path to "\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders". Omit the default keys and any other localesque accounts by only looking for the ones with "S-1-5-21" as part of the key. Then for each of those that is located find every registry value with data that matchs the path you are looking for.

Set-ItemProperty -Path $key -Name $_.Name -Value ($_.Value -replace $pathToReplace,$newPath) -WhatIf

Drawing a little more attention on the last part here. With all the values that matched we replace the data with a simple -replace. I have a -WhatIf on there to be sure you test in case something bad happens. I would suggest commenting out that line and outputing just $_.Value -replace $pathToReplace,$newPath to verify that it is doing what you expect it to.

Make sure that you change the values for $pathToReplace and $newPath then Test twice, execute once.

Share:
15,766

Related videos on Youtube

Derek
Author by

Derek

Updated on June 04, 2022

Comments

  • Derek
    Derek almost 2 years

    In 'HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders' I have some paths set to an old server. e.g.:

    'My Pictures' is set to '\\DeadServer\RedirectedFolders\%UserName%\My Documents\My Pictures'

    I'd like to replace "\\DeadServer\RedirectedFolders" with "C:\Users"

    How can this be done in powershell?


    I got as far as trying

    Get-ItemProperty -path "Microsoft.PowerShell.Core\Registry::HKEY_USERS\*\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" | ? {$_.PSObject.Properties -like "*DeadServer*"} 

    But I think I'm getting confused with how the entry I want to change is a 'Property', and not an 'Item', and I don't know how to iterate through properties like I'd do Items.


    Before you ask, I've already made this change with Group Policy, but it's not taking. Users are getting a message

    The Recycle Bin on \DeadServer\RedirectedFolders\%UserName%\My Documents\My Pictures` is corrupted. Do you want to empty the Recycle Bin for this drive?

    upon login which is keeping Folder Redirection from applying.
    This is my attempt to force the change back to local storage manually.

  • Thomas
    Thomas over 3 years
    trows me the follow error: Get-ItemProperty : Die angegebene Umwandlung ist ungültig. In C:\Install\find-replace-reg.ps1:24 Zeichen:9 + Get-ItemProperty -Path "$PowershellRegPrefix$_" | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Get-ItemProperty], InvalidCastException + FullyQualifiedErrorId : System.InvalidCastException,Microsoft.PowerShell.Commands.Ge‌​tItemPropertyCommand
  • Mike 'Pomax' Kamermans
    Mike 'Pomax' Kamermans about 2 years
    it's been a while, but can you still flag this as accepted answer if this solved the problem? Accepting answers is still the backbone of how stackexchange sites work =)