Как изменить реестр для всех пользователей с помощью power shell

 Windows OS Hub / PowerShell / PowerShell: Get, Modify, Create, and Remove Registry Keys or Parameters

Navigate the Windows Registry Like a File System with PowerShell

Working with the registry in PowerShell is similar to working with common files on a local disk. The main difference is that in this concept the registry keys are analogous to files, and the registry parameters are the properties of these files.

Display the list of available drives on your computer:

get-psdrive

cd HKLM:\
Dir -ErrorAction SilentlyContinue

browse windows registry with powershell

Those, you can access the registry key and their parameters using the same PowerShell cmdlets that you use to manage files and folders.

To refer to registry keys, use cmdlets with xxx-Item:

  • Get-Item – get a registry key
  • New-Item — create a new registry key
  • Remove-Item – delete a registry key

Registry parameters should be considered as properties of the registry key (similar to file/folder properties). The xxx-ItemProperty cmdlets are used to manage registry parameters:

  • Get-ItemProperty – get the value of a registry parameter
  • Set-ItemProperty – change the value of a registry parameter
  • New-ItemProperty – create registry parameter
  • Rename-ItemProperty – rename parameter
  • Remove-ItemProperty — remove the registry parameter

You can navigate to the specific registry key (for example, to the one responsible for the settings of automatic driver updates) using one of two commands:

cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching
or
Set-Location -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching

Get a Registry Parameter Value via PowerShell

Please note that the parameters stored in the registry key are not nested objects, but a property of a specific registry key. Those any registry key can have any number of parameters.

List the contents of the current registry key using the command:

The command has displayed information about the nested registry keys and their properties. But didn’t display information about the SearchOrderConfig parameter, which is a property of the current key.

Use the Get-Item cmdlet to get the parameters of the registry key:

Get-Item .
Or
Get-Item –Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching

As you can see, the DriverSearching key has only one parameter – SearchOrderConfig with a value of 1.

getting registry key properties powershell

To get the value of a registry key parameter, use the Get-ItemProperty cmdlet.

$DriverUpdate = Get-ItemProperty –Path ‘HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching’
$DriverUpdate.SearchOrderConfig

Get-ItemProperty

We got that the value of the SearchOrderConfig parameter is 1.

Changing Registry Value with PowerShell

To change the value of the SearchOrderConfig reg parameter, use the Set-ItemProperty cmdlet:

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching' -Name SearchOrderConfig -Value 0

Make sure that the parameter value has changed:

Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching' -Name SearchOrderConfig

Set-ItemProperty

How to Create a New Register Key or Parameter with PowerShell?

To create a new registry key, use the New-Item command. Let’s create a new key with the name NewKey:

$HKCU_Desktop= "HKCU:\Control Panel\Desktop"
New-Item –Path $HKCU_Desktop –Name NewKey

Now let’s create a new parameter in a new registry key. Suppose we need to create a new string parameter of type REG_SZ named SuperParamString and value filetmp1.txt:

New-ItemProperty -Path $HKCU_Desktop\NewKey -Name "SuperParamString" -Value ”filetmp1.txt”  -PropertyType "String"

  • String (REG_SZ)
  • ExpandString (REG_EXPAND_SZ)
  • MultiString (REG_MULTI_SZ)
  • Binary (REG_BINARY)
  • DWord (REG_DWORD)
  • Qword (REG_QWORD)
  • Unknown (unsupported registry data type)

Make sure that the new key and parameter have appeared in the registry.

powershell create registry parameter

How to check if a registry key exists?

If you need to check if a specific registry key exists, use the Test-Path cmdlet:

Test-Path 'HKCU:\Control Panel\Desktop\NewKey'

Using the Copy-Item cmdlet, you can copy entries from one registry key to another:

:/>  Как запустить командную строку с правами администратора

$source='HKLM:\SOFTWARE\7-zip\'
$dest = 'HKLM:\SOFTWARE\backup'
Copy-Item -Path $source -Destination $dest -Recurse

If you want to copy everything, including subkeys, add the –Recurse switch.

Deleting a Registry Key or Parameter

The Remove-ItemProperty command is used to remove a parameter in the registry key. Let’s remove the parameter SuperParamString created earlier:

$HKCU_Desktop= "HKCU:\Control Panel\Desktop"
Remove-ItemProperty –Path $HKCU_Desktop\NewKey –Name "SuperParamString"

You can delete the entire registry key with all its contents:

Remove-Item –Path $HKCU_Desktop\NewKey –Recurse

Note. –Recurse switch indicates that all subkeys have to be removed recursively.

To remove all items in the reg key (but not the key itself):

Remove-Item –Path $HKCU_Desktop\NewKey\* –Recurse

How to Rename a Registry Key or a Parameter?

You can rename the registry parameter with the command:

Rename-ItemProperty –path ‘HKCU:\Control Panel\Desktop\NewKey’ –name "SuperParamString" –newname “OldParamString”

In the same way, you can rename the registry key:

Rename-Item -path 'HKCU:\Control Panel\Desktop\NewKey' OldKey

Search Registry for Keyword Using PowerShell

To find a registry key with a specific name:

Setting Registry Key Permissions with PowerShell

You can get the current registry key permissions using the Get-ACL cmdlet.

$rights = Get-Acl -Path 'HKCU:\Control Panel\Desktop\NewKey'
$rights.Access.IdentityReference

get registry key permissions with powershell

Get current permissions:

$rights = Get-Acl -Path 'HKCU:\Control Panel\Desktop\NewKey'

Select access level:

Access type (Allow/Deny):

$rule = New-Object System.Security.AccessControl.RegistryAccessRule ($idRef, $regRights, $inhFlags, $prFlags, $acType)

Add a new rule to the current ACL:

Apply new permissions to the registry key:

Make sure the new group appears in the ACL of the registry key.

change registry key permissions with powershell

Getting a Registry Value from a Remote Computer via PowerShell

PowerShell allows you to access the registry of a remote computer. You can connect to a remote computer either using WinRM (Invoke-Command or Enter-PSSession). To get the value of a registry parameter from a remote computer:

Or using a remote registry connection (the RemoteRegistry service must be enabled)

Tip. If you have to create/modify a certain registry parameter on multiple domain computers, it is easier to use GPO features.

So we’ve covered typical examples of using PowerShell to access and manage Windows registry entries. You can use them in your automation scripts.

In the labyrinth of Windows Registry data types, there’s a special one that stands out for its ability to juggle multiple strings in a single act.

It’s the REG_MULTI_SZ registry data type, often referred to as “Multiple Strings” or “Multi-String Values“. This data type is an essential part of the Windows registry, known for its capability to store multiple strings or string values within a single registry entry.

REG_MULTI_SZ is a binary data type in the Windows registry, but it stores data in a specific textual format. It is used to hold an array of null-terminated strings, where each string is separated by a double null character (`\0\0`). This unique structure allows it to store multiple values within a single registry entry.

REG_MULTI_SZ is commonly used to store configuration settings, such as environment variables, service dependencies, or lists of values, where maintaining multiple items in a single registry entry is convenient.

In this article, let us explore how you can manipulate the REG_MULTI_SZ with Advanced Installer and PowerShell.

Working with REG_MULTI_SZ and Advanced Installer

Imagine Advanced Installer as your stage director or managing REG_MULTI_SZ entries. Working with Advanced Installer to manipulate registry entries makes developing your installer package so much easier.

It’s a breeze to navigate to the Registry Page and choose your hive:

  • HKEY_CLASSES_ROOT,
  • HKEY_CURRENT_USER,
  • HKEY_LOCAL_MACHINE,
  • or HKEY_USERS.
:/>  Trojan.Encoder.32886

Creating a new REG_MULTI_SZ value:

1. Go to the desired registry location,

2. Right-click on the right pane and select New Value.

  1. string (REG_SZ or REG_MULTI_SZ),
  2. expandable string (REG_EXPAND_SZ),
  3. integer (REG_DWORD), or binary (REG_BINARY).

4. Enter the strings that make up a REG_MULTI_SZ value, one per line, to define it.

REG_MULTI_SZ registry edit

Ready to take the spotlight in registry management?

Get your hands on Advanced Installer’s 30-day free trial, and start developing your installer packages with confidence.

Working with REG_MULTI_SZ and PowerShell

When working with REG_MULTI_SZ values in PowerShell, you typically read and write them as arrays of strings.

PowerShell makes it easy to manipulate and manage these values using cmdlets like Get-ItemProperty and Set-ItemProperty.

# Reading a REG_MULTI_SZ value $registryPath = 'HKLM:\Software\Example' $multiStringValue = Get-ItemProperty -Path $registryPath | Select-Object -ExpandProperty MultiStringProperty
Get-ItemProperty REG_MULTI_SZ in PowerShell
# Writing a REG_MULTI_SZ value $newMultiStringValue = @('Value1', 'Value2', 'Value3') Set-ItemProperty -Path $registryPath -Name MultiStringProperty -Value $newMultiStringValue -Type MultiString
Set-ItemProperty REG_MULTI_SZ in PowerShell

The Art of REG_MULTI_SZ Maintenance

Editing REG_MULTI_SZ values is a delicate art. Each string must end with a \0, and the array concludes with a \0\0 encore. Mishandling the null-terminated structure is like missing a step in a tango – it could lead to a data disaster.

Handle REG_MULTI_SZ values with the grace of a ballet dancer to maintain data integrity. A misstep, like removing null characters or introducing formatting faux pas, can turn your data performance into a tragedy.

Conclusion

In summary, REG_MULTI_SZ is a versatile and vital performer in the Windows Registry theatre.

Just remember, with great power comes the responsibility to maintain the integrity of your data show. Bravo!

See author's page

Alex Marin

Application Packaging and SCCM Deployments specialist, solutions finder, Technical Writer at Advanced Installer.

To search by value you’ll have to get all keys/subkeys in your specified path first. Once you get the keys you’ll have to go through each one and get the key values and data. The whole key (and subkeys) well be removed if any of it’s value data contain the specified search term.

$searchRegKeyValue = "*test123*"
$myPath = "REGISTRY::HKCR\"
# $mypath = "REGISTRY::HKLM:\Software\"
$childItems = Get-ChildItem -Path $myPath -Recurse -ErrorAction SilentlyContinue
# go through each key in the reg path specified
foreach ($key in $childItems){ # for each value of the key get it's value and compare against the search term foreach ($name in $key.GetValueNames()){ if ($key.GetValue($name) -like $searchRegKeyValue){ # Get-Item -Path $key.pspath Remove-Item -Path $key.pspath -Recurse -WhatIf } }
}

The above solution works well if there are not a lot of keys/subkeys to go through but can get slow especially if you specify a top level path ("REGISTRY::HKCR\" vs "REGISTRY::HKCR\CLSID").

I found a really interesting solution to speed up registry search in powershell here. So I modified the solution a bit to work with this use case. The speed up using this solution is more noticeable with a larger search set. I saw 50%+ speedup on the larger search set but on smaller it was closer. For my orginal solution it took 293 seconds to search HKCR:\ while using the solution linked it took 101 seconds.
enter image description here

Bellow is from the linked solution modified to remove the keys that have values that match $search. I had to change some things around in the search to account for an empty $subKey to search from root level but it’s mostly the same other than that.

# [email protected]# reference: https://msdn.microsoft.com/de-de/vstudio/ms724875(v=vs.80)
cls
remove-variable * -ea 0
$ErrorActionPreference = "stop"
$signature = @'
[DllImport("advapi32.dll")]
public static extern Int32 RegOpenKeyEx( UInt32 hkey, StringBuilder lpSubKey, int ulOptions, int samDesired, out IntPtr phkResult );
[DllImport("advapi32.dll")]
public static extern Int32 RegQueryInfoKey( IntPtr hKey, StringBuilder lpClass, Int32 lpCls, Int32 spare, out int subkeys, out int skLen, int mcLen, out int values, out int vNLen, out int mvLen, int secDesc, out System.Runtime.InteropServices.ComTypes.FILETIME lpftLastWriteTime
);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern Int32 RegEnumValue( IntPtr hKey, int dwIndex, IntPtr lpValueName, ref IntPtr lpcchValueName, IntPtr lpReserved, out IntPtr lpType, IntPtr lpData, ref int lpcbData
);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern Int32 RegEnumKeyEx( IntPtr hKey, int dwIndex, IntPtr lpName, ref int lpcName, IntPtr lpReserved, IntPtr lpClass, int lpcClass, out System.Runtime.InteropServices.ComTypes.FILETIME lpftLastWriteTime
);
[DllImport("advapi32.dll")]
public static extern Int32 RegCloseKey(IntPtr hkey);
'@
$reg = add-type $signature -Name reg -Using System.Text -PassThru
$marshal = [System.Runtime.InteropServices.Marshal]
function search-RegistryTree($path) { if(($path -ne "") -and !($path.EndsWith("\"))){ $path += "\" } # open the key: [IntPtr]$hkey = 0 $result = $reg::RegOpenKeyEx($global:hive, $path, 0, 25 ,[ref]$hkey) if ($result -eq 0) { # get details of the key: $subKeyCount = 0 $maxSubKeyLen = 0 $valueCount = 0 $maxNameLen = 0 $maxValueLen = 0 $time = $global:time $result = $reg::RegQueryInfoKey($hkey,$null,0,0,[ref]$subKeyCount,[ref]$maxSubKeyLen,0,[ref]$valueCount,[ref]$maxNameLen,[ref]$maxValueLen,0,[ref]$time) if ($result -eq 0) { $maxSubkeyLen += $maxSubkeyLen+1 $maxNameLen += $maxNameLen +1 $maxValueLen += $maxValueLen +1 } # enumerate the values: if ($valueCount -gt 0) { $type = [IntPtr]0 $pName = $marshal::AllocHGlobal($maxNameLen) $pValue = $marshal::AllocHGlobal($maxValueLen) foreach ($index in 0..($valueCount-1)) { $nameLen = $maxNameLen $valueLen = $maxValueLen $result = $reg::RegEnumValue($hkey, $index, $pName, [ref]$nameLen, 0, [ref]$type, $pValue, [ref]$valueLen) if ($result -eq 0) { $name = $marshal::PtrToStringUni($pName) $value = switch ($type) { 1 {$marshal::PtrToStringUni($pValue)} 2 {$marshal::PtrToStringUni($pValue)} 3 {$b = [byte[]]::new($valueLen) $marshal::Copy($pValue,$b,0,$valueLen) if ($b[1] -eq 0 -and $b[-1] -eq 0 -and $b[0] -ne 0) { [System.Text.Encoding]::Unicode.GetString($b) } else { [System.Text.Encoding]::UTF8.GetString($b)} } 4 {$marshal::ReadInt32($pValue)} 7 {$b = [byte[]]::new($valueLen) $marshal::Copy($pValue,$b,0,$valueLen) $msz = [System.Text.Encoding]::Unicode.GetString($b) $msz.TrimEnd(0).split(0)} 11 {$marshal::ReadInt64($pValue)} } # if ($name -match $global:search) { # write-host "$path\$name : $value" # $global:hits++ # } elseif ($value -match $global:search) { # write-host "$path\$name : $value" # $global:hits++ # } # only find keys based on matched value data if ($value -match $global:search) { write-host "$path$name : $value" $item = "$path : $value" $keyList.Add($item) $global:hits++ } } } $marshal::FreeHGlobal($pName) $marshal::FreeHGlobal($pValue) } # enumerate the subkeys: if ($subkeyCount -gt 0) { $subKeyList = @() $pName = $marshal::AllocHGlobal($maxSubkeyLen) $subkeyList = foreach ($index in 0..($subkeyCount-1)) { $nameLen = $maxSubkeyLen $result = $reg::RegEnumKeyEx($hkey, $index, $pName, [ref]$nameLen,0,0,0, [ref]$time) if ($result -eq 0) { $marshal::PtrToStringUni($pName) } } $marshal::FreeHGlobal($pName) } # close: $result = $reg::RegCloseKey($hkey) # get Tree-Size from each subkey: $subKeyValueCount = 0 if ($subkeyCount -gt 0) { foreach ($subkey in $subkeyList) { if (!($subkey.EndsWith("\"))){ $subKeyValueCount += search-RegistryTree "$path$subkey\" } else{ $subKeyValueCount += search-RegistryTree "$path$subkey" } } } return ($valueCount+$subKeyValueCount) }
}
function remove-keys ($keyList){ Write-Output "The following KEYS will be removed: " foreach ($key in $keyList){ $value = $key.split(":")[1] $key = $key.split(":")[0].TrimEnd() Get-Item -Path "$root\$key" } foreach ($key in $keyList){ $value = $key.split(":")[1] $key = $key.split(":")[0].TrimEnd() # Get-Item -Path "$root\$key" Remove-Item -Path "$root\$key" -Recurse -WhatIf }
}
$timer = [System.Diagnostics.Stopwatch]::new()
$timer.Start()
# setting global variables:
$search = "test123"
#needs to change depending on the location you are searching
# $hive = [uint32]"0x80000002" #HKLM
$hive = [uint32]"0x80000000" #HKCR
# $root = "REGISTRY::HKEY_LOCAL_MACHINE"
$root = "REGISTRY::HKEY_CLASSES_ROOT"
# to search from the root level of the hive you selected
$subkey = ""
# $subkey = "CLSID"
$time = New-Object System.Runtime.InteropServices.ComTypes.FILETIME
$hits = 0
$keyList = [System.Collections.Generic.List[string]]::new()
write-host "We start searching for pattern '$search' in Registry-Path '$subkey' ...`n"
$count = search-RegistryTree $subkey
Write-Output $values
$timer.stop()
$sec = [int](100 * $timer.Elapsed.TotalSeconds)/100
write-host "`nWe checked $count reg-values in $sec seconds. Number of hits = $hits."
remove-keys $keyList

In both solutions you’ll need to remove -whatIf when using remove-item to actually remove the item. I just left it here for safety. It’ll remove the key and any subkeys of that key if there is a match. I’d recommend testing with your search term first before removing -whatIf to make sure it matching with what you want to remove.