- Install Ansible on Windows - Thu, Jul 20 2023
- Use Azure Bastion as a jump host for RDP and SSH - Tue, Apr 18 2023
- Azure Virtual Desktop: Getting started - Fri, Apr 14 2023
As Windows system administrators, we come to know the Windows Registry quite intimately. If you’re like me, pressing the Windows key+R, typing regedit, and pressing ENTER is a second-nature way to open the good ol’ Registry Editor. The good news is that Windows PowerShell has had a built-in Registry provider since day one. The bad news is that accessing Registry data programmatically with PowerShell isn’t particularly intuitive.
The Windows Registry Editor
Viewing Registry key data
As I said, Windows PowerShell exposes the two main Registry subtrees (HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE) via the built-in provider.
PS C:\> Get-PSDrive -PSProvider Registry | Select-Object -Property Name, Root Name Root ---- ---- HKCU HKEY_CURRENT_USER HKLM HKEY_LOCAL_MACHINE
Let’s say we want to view the contents of the Run key on our Windows 8.1 system. Of course, we’re already comfortable checking that path to find troublesome and/or unwanted autostart programs, right?
First, we’ll shift our provider from the default file system to the Registry, navigating to the proper path like this:
Set-Location -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Things get weird when we try to get a “directory” listing on the Run key, though:
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run> Get-ChildItem PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run>
Strange, especially when we consider that I do, in fact, have an entry in that key. For example:
Verifying that we do indeed have data in our Run Registry key
Those of you who have prior experience with PowerShell data providers may be familiar with Get-Item to retrieve object-level data. As far as the Registry provider is concerned, Registry keys are items, and the values are item properties. Try this:
Get-Item . Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion Name Property ---- -------- Run VMware User Process : "C:\Program Files\VMware\VMware Tools\vmtoolsd.exe" -n vmusr
The dot (.) is important because Get-Item uses –Path as a first-position required parameter, and the dot historically represents the current working directory in the Cmd.exe, PowerShell, and Bash shells.
To drill into the Run key’s values, we need Get-ItemProperty:
Get-ItemProperty . VMware User Process : "C:\Program Files\VMware\VMware Tools\vmtoolsd.exe" -nvmusr PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion PSChildName : Run PSDrive : HKLM PSProvider : Microsoft.PowerShell.Core\Registry
By creating a variable that stores a Registry key, we can easily use “dot notation” to access all the values. Check this out:
$desktop = Get-ItemProperty –Path "HKCU:\Control Panel\Desktop"
Now use tab completion with $desktop; you can quickly read any value you need. For example:
$desktop.MenuShowDelay 400
Modifying a Registry value
Before Windows 8 came on the scene, I habitually adjusted the MenuShowDelay value in HKCU\Control Panel\Desktop so the Start menu opened faster. I’m sure we can tweak this value again in Windows 10, but I’ll use this as an example now to teach you how to modify Registry values by using Windows PowerShell.
Let’s say we want to change the MenuShowDelay value from its current value to 50. First, we verify its current value, like this:
Get-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name MenuShowDelay MenuShowDelay : 400
Programmers always talk about getting and setting values in their code. We’ve just done the “get;” now, let’s use Set-ItemProperty to perform the set operation:
Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name MenuShowDelay -Value 50 Get-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name MenuShowDelay MenuShowDelay : 50
Adding and removing Registry keys and values
Now I want to teach you how to add new data to the Registry programmatically with PowerShell. In this example, we’ll create a new key called MyKey and a new DWORD value named MyValue. HKCU\Control Panel\Desktop is a fairly innocuous path, so let’s store that in a variable to get started:
$path = "HKCU:\Control Panel\Desktop"
Now, we’ll create the new key by invoking New-Item:
New-Item –Path $path –Name MyKey Next, it’s time to create the MyValue value: New-ItemProperty -Path $path\MyKey -Name "MyValue" -Value 0 -PropertyType "DWORD"
Our new Registry data
We’ll finish up by removing our new key and value. To do that, we’ll call Remove-ItemProperty into action:
Remove-ItemProperty –Path $path\MyKey –Name "MyValue"
Finally, we’ll delete the MyKey Registry key by using Remove-Item:
Remove-Item –Path $path\MyKey -Recurse
In the previous example, the –Recurse parameter deletes any subkeys that may exist beneath the target key.
That’s all there is to it (at least to start with). I hope you found this article informative.
Best explanation out there!
Thanks, Brian! I’m glad you found this piece helpful. Kindest regards, Tim
in regedit I do control-F.
All those I want deleted.
Any suggestions?
Thanks for posting!
I was unable to get this to work, though I had high hopes. The script runs without error, but no changes appear to have occurred in the registry. Any ideas?
You will need elevated rights in order to make changes in the registry. Start Powershell as an admin
Thanks for the post – very informative.
Is there any way within PowerShell to cause the registry to flush to disk? I found reference to the registry function RegFlushKey but it didn’t look like that was part of the power shell registry provider
Thanks, very useful, exactly what I was looking for!
How in the world do you add a command to check if new values appear in the registry during same execution of current PowerShell script run? I’m checking to see when a new Key value gets created, then it does another task, currently it doesn’t find the new values unless I stop the script and retry, which isn’t want we want done. I’m having troubles finding related articles on this…
Hi John,
My guess is that you are using a variable to check in a if loop statement if the value is Key-Value is true or not. In short maybe is better to outline the difference of assigning by value or by reference. Let me explain with a easier example with an interactive powershell session:
PS:>$date = Get-Date
If you print it $date now you’ll have the exact time right? Sort of…
PS:>$date
Wednesday, 12 September 2018 5:13:00 PM
If you print it after 10 minutes? 1 h? 1 year? Same result
PS:>$date
Wednesday, 12 September 2018 5:13:00 PM
This $date is assigned once and never refreshed. So in your case it looks like you’re not refreshing the variable that you’re checking. An examples of it is that if I run these sequence I get the expected result all the time.
Have the expected result.
Instead if on step 1 you store the result on a Variable and on step 3 you wan to print the value the result will not have the value updated. Does this make sense? Is it your case?
I hope it helps.
how to automate the process? Like reading the key value from the file(maybe 50 key values), check if the registry key exists, if exists then modify with the new value from the file and if not exists then add the new key value pair