注册表中的Powershell查找和替换?

3

'HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders' 中,我设置了一些路径到一个旧的服务器。例如:

'我的图片' 路径设置为 '\\DeadServer\RedirectedFolders\%UserName%\My Documents\My Pictures'

我想用 "C:\Users" 替换 "\\DeadServer\RedirectedFolders"

如何使用 powershell 实现这一点?


我已经尝试过如下命令

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

但是,我混淆了要更改的条目是 '属性' 而不是 '项',而且我不知道如何像对待项一样迭代属性。


在你问之前,我已经使用组策略进行了更改,但是它并没有起作用。用户在登录时会收到以下消息:

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

这个问题导致了文件夹重定向无法应用。这是我手动强制将更改还原回本地存储的尝试。


你实际上需要查找和替换吗?还是可以直接设置值? - arco444
最终我需要在多台计算机上为多个账户运行此程序。如果我只是随意设置值,那么我需要跟踪当前正在迭代的用户名。我的计划是在HKEY_USERS上运行此程序(请参见我在OP中的尝试),因此用户无需登录即可访问其HKCU。在这种情况下使用%username%变量可能会很棘手。 - Derek
4个回答

6

我想通了。花费了很长时间,但我写了一个相当不雅观的脚本:

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 "================================================================"
            }
        }
    }
}

如果您们中有更快或更优雅的方法,请让我学习一下。


已经有一段时间了,但如果这个回答解决了问题,你仍然可以将其标记为“接受的答案”吗?接受答案仍然是StackExchange网站运作的支柱 =) - Mike 'Pomax' Kamermans
我建议你将自己的答案标记为正确答案。在这个网站刚开始的时候,我经常这样做,结果会导致账号被封禁。我觉得这并不是关键,通常我会忽略它并继续浏览。 - undefined

2

这是一个易于使用的注册表替换函数,可以递归地搜索路径。

# 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!!!" } }
                    }
                }
            }
        }
    }
}

抛出以下错误:在 C:\Install\find-replace-reg.ps1:24 字符:9 + Get-ItemProperty -Path "$PowershellRegPrefix$_" | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Get-ItemProperty], InvalidCastException + FullyQualifiedErrorId : System.InvalidCastException,Microsoft.PowerShell.Commands.GetItemPropertyCommand``` - Thomas

1

我对此并不满意,如果有人能够超越它,我会感到高兴和难过。目前已经进行了大部分测试,以验证其是否定位到了正确的键。

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

使用Psdrive映射HKU,因为它不是PowerShell中的默认驱动器。获取所有具有至少指向"\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"路径的键。通过仅查找具有"S-1-5-21"作为键的部分的那些来省略默认键和任何其他本地化帐户。然后对于每个已定位的键,查找具有与您要查找的路径匹配的数据的每个注册表值。
Set-ItemProperty -Path $key -Name $_.Name -Value ($_.Value -replace $pathToReplace,$newPath) -WhatIf

在这里再引起一点注意。对于所有匹配的值,我们使用简单的-replace替换数据。我在那里加了一个-WhatIf以确保您在测试时发现问题。我建议注释掉该行,并输出$_.Value -replace $pathToReplace,$newPath,以验证它是否按照您的预期执行。 确保更改$pathToReplace$newPath的值,然后测试两次,执行一次。

0
以下是我在为用户帐户重命名配置文件路径后使用的示例:
function get-itemproperty2 {
          # get-childitem skips top level key, use get-item for that
          # set-alias gp2 get-itemproperty2
          param([parameter(ValueFromPipeline)]$key)
          process {
            $key.getvaluenames() | foreach-object {
              $value = $_
              [pscustomobject] @{
                Path = $Key -replace 'HKEY_CURRENT_USER',
                  'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
                Name = $Value
                Value = $Key.GetValue($Value)
                Type = $Key.GetValueKind($Value)
              }
            }
          }
        }

    ls -r hkcu: | get-itemproperty2 | where Value -match "(.*)C:\\Users\\Admin(.*)"  | ForEach-Object { 
        $newkey = $_.Value -replace '(.*)C:\\Users\\Admin(.*)', '$1C:\Users\dennisg$2'; 
        if ($_.Name -eq '') 
        {
            set-itemproperty -Path $_.Path -Name '(Default)' -Value $newkey -Type $_.Type ;
            $outInfo = '****' + $_.Path + " | " + $_.Name  + " | " + $newkey;
        }
        else 
        {
            set-itemproperty -Path $_.Path -Name $_.Name -Value $newkey -Type $_.Type ;
            $outInfo = $_.Path + " | " + $_.Name  + " | " + $newkey;
        }
        echo $outInfo;
    }

这个函数来自于这个 Stack Overflow 的问题 使用 PowerShell 在注册表键和值中搜索字符串


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接