Thanks to PowerShells universal “Provider” concept, you can navigate the Windows Registry just as you would the file system. In this chapter, you will learn how to read and write Registry keys and Registry values.
- Using Providers
- Available Providers
- Creating Drives
- Searching for Keys
- Reading One Registry Value
- Reading Multiple Registry Values
- Reading Multiple Keys and Values
- Creating Registry Keys
- Deleting Registry Keys
- Creating Values
- Securing Registry Keys
- Taking Ownership
- Setting New Access Permissions
- Removing an Access Rule
- Controlling Access to Sub-Keys
- Revealing Inheritance
- Controlling Your Own Inheritance
The Registry stores many crucial Windows settings. That’s why it’s so cool to read and sometimes change information in the Windows Registry: you can manage a lot of configuration settings and sometimes tweak Windows in ways that are not available via the user interface.
However, if you mess things up – change the wrong values or deleting important settings – you may well permanently damage your installation. So, be very careful, and don’t change anything that you do not know well.
Using Providers
To access the Windows Registry, there are no special cmdlets. Instead, PowerShell ships with a so-called provider named “Registry”. A provider enables a special set of cmdlets to access data stores. You probably know these cmdlets already: they are used to manage content on drives and all have the keyword “item” in their noun part:
PS> Get-Command -Noun Item* CommandType Name ModuleName Definition ----------- ---- ---------- ---------- Cmdlet Clear-Item Microsoft.PowerSh... ... Cmdlet Clear-ItemProperty Microsoft.PowerSh... ... Cmdlet Copy-Item Microsoft.PowerSh... ... Cmdlet Copy-ItemProperty Microsoft.PowerSh... ... Cmdlet Get-Item Microsoft.PowerSh... ... Cmdlet Get-ItemProperty Microsoft.PowerSh... ... Cmdlet Invoke-Item Microsoft.PowerSh... ... Cmdlet Move-Item Microsoft.PowerSh... ... Cmdlet Move-ItemProperty Microsoft.PowerSh... ... Cmdlet New-Item Microsoft.PowerSh... ... Cmdlet New-ItemProperty Microsoft.PowerSh... ... Cmdlet Remove-Item Microsoft.PowerSh... ... Cmdlet Remove-ItemProperty Microsoft.PowerSh... ... Cmdlet Rename-Item Microsoft.PowerSh... ... Cmdlet Rename-ItemProperty Microsoft.PowerSh... ... Cmdlet Set-Item Microsoft.PowerSh... ... Cmdlet Set-ItemProperty Microsoft.PowerSh... ...
Many of these cmdlets have historic aliases, and when you look at those, the cmdlets probably become a lot more familiar:
PS> Get-Alias -Definition *-Item* CommandType Name ModuleName Definition ----------- ---- ---------- ---------- Alias cli Clear-Item Alias clp Clear-ItemProperty Alias copy Copy-Item Alias cp Copy-Item Alias cpi Copy-Item Alias cpp Copy-ItemProperty Alias del Remove-Item Alias erase Remove-Item Alias gi Get-Item Alias gp Get-ItemProperty Alias ii Invoke-Item Alias mi Move-Item Alias move Move-Item Alias mp Move-ItemProperty Alias mv Move-Item Alias ni New-Item Alias rd Remove-Item Alias ren Rename-Item Alias ri Remove-Item Alias rm Remove-Item Alias rmdir Remove-Item Alias rni Rename-Item Alias rnp Rename-ItemProperty Alias rp Remove-ItemProperty Alias si Set-Item Alias sp Set-ItemProperty
Thanks to the “Registry” provider, all of these cmdlets (and their aliases) can also work with the Registry. So if you wanted to list the keys of HKEY_LOCAL_MACHINESoftware, this is how you’d do it:
Dir HKLM:Software
Available Providers
Get-PSProvider gets a list of all available providers. Your list can easily be longer than in the following example. Many PowerShell extensions add additional providers. For example, the ActiveDirectory module that ships with Windows Server 2008 R2 (and the RSAT tools for Windows 7) adds a provider for the Active Directory. Microsoft SQL Server (starting with 2007) comes with an SQLServer provider.
Get-PSProvider Name Capabilities Drives ---- ------------ ------ Alias ShouldProcess {Alias} Environment ShouldProcess {Env} FileSystem filter, ShouldProcess {C, E, S, D} function ShouldProcess {function} Registry ShouldProcess {HKLM, HKCU} Variable ShouldProcess {Variable} Certificate ShouldProcess {cert}
What’s interesting here is the “Drives” column, which lists the drives that are managed by a respective provider. As you see, the registry provider manages the drives HKLM: (for the registry root HKEY_LOCAL_MACHINE) and HKCU: (for the registry root HKEY_CURRENT_USER). These drives work just like traditional file system drives. Check this out:
Cd HKCU: Dir Hive: Microsoft.PowerShell.CoreRegistry::HKEY_CURRENT_USER SKC VC Name Property --- -- ---- -------- 2 0 AppEvents {} 7 1 Console {CurrentPage} 15 0 Control Panel {} 0 2 Environment {TEMP, TMP} 4 0 EUDC {} 1 6 Identities {Identity Ordinal, Migrated7, Last ... 3 0 Keyboard Layout {} 0 0 Network {} 4 0 Printers {} 38 1 Software {(default)} 2 0 System {} 0 1 SessionInformation {ProgramCount} 1 8 Volatile Environment {LOGONSERVER, USERDOMAIN, USERNAME,...
You can navigate like in the file system and dive deeper into subfolders (which here really are registry keys).
Provider | Description | Example |
Alias | Manages aliases, which enable you to address a command under another name. You’ll learn more about aliases in Chapter 2. | Dir Alias: $alias:Dir |
Environment | Provides access to the environment variables of the system. More in Chapter 3. | Dir env: $env:windir |
Function | Lists all defined functions. Functions operate much like macros and can combine several commands under one name. Functions can also be an alternative to aliases and will be described in detail in Chapter 9. | Dir function: $function:tabexpansion |
FileSystem | Provides access to drives, directories and files. | Dir c: $(c:autoexec.bat) |
Registry | Provides access to branches of the Windows registry. | Dir HKCU: Dir HKLM: |
Variable | Manages all the variables that are defined in the PowerShell console. Variables are covered in Chapter 3. | Dir variable: $variable:pshome |
Certificate | Provides access to the certificate store with all its digital certificates. These are examined in detail in Chapter 10. | Dir cert: Dir cert: -recurse |
Creating Drives
PowerShell comes with two drives built-in that point to locations in the Windows Registry: HKLM: and HKCU:.
Get-PSDrive -PSProvider Registry Name Provider Root CurrentLocation ---- -------- ---- --------------- HKCU Registry HKEY_CURRENT_USER HKLM Registry HKEY_LOCAL_MACHINE
That’s a bit strange because when you open the Registry Editor regedit.exe, you’ll see that there are more than just two root hives. If you wanted to access another hive, let’s say HKEY_USERS, you’d have to add a new drive like this:
New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS Dir HKU:
You may not have access to all keys due to security settings, but your new drive HKU: works fine. Using New-PSDrive, you now can access all parts of the Windows Registry. To remove the drive, use Remove-PSDrive (which only works if HKU: is not the current drive in your PowerShell console):
Remove-PSDrive HKU
You can of course create additional drives that point to specific registry keys that you may need to access often.
New-PSDrive InstalledSoftware registry 'HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstall' Dir InstalledSoftware:
Note that PowerShell drives are only visible inside the session you defined them. Once you close PowerShell, they will automatically get removed again. To keep additional drives permanently, add the New-PSDrive statements to your profile script so they get automatically created once you launch PowerShell.
Using Provider Names Directly
Actually, you do not need PowerShell drives at all to access the Registry. In many scenarios, it can be much easier to work with original Registry paths. To make this work, prepend the paths with the provider names like in the example below:
Dir HKLM:Software Dir Registry::HKEY_LOCAL_MACHINESoftware Dir Registry::HKEY_USERS Dir Registry::HKEY_CLASSES_ROOT.ps1
With this technique, you can even list all the Registry hives:
Dir Registry::
Searching for Keys
Get-ChildItem can list all subkeys of a key, and it can of course use recursion to search the entire Registry for keys with specific keywords.
The registry provider doesn’t support filters, though, so you cannot use the parameter -Filter when you search the registry. Instead, use -Include and -Exclude. For example, if you wanted to find all Registry keys that include the word “PowerShell”, you could search using:
PS> Get-ChildItem HKCU:, HKLM: -Recurse -Include *PowerShell* -ErrorAction SilentlyContinue | >> Select-Object -ExpandProperty Name >> HKEY_CURRENT_USERConsole%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe HKEY_CURRENT_USERSoftwareMicrosoftPowerShell HKEY_CURRENT_USERSoftwareMicrosoftPowerShell1ShellIdsMicrosoft.PowerShell
Note that this example searches both HKCU: and HKLM:. The error action is set to SilentlyContinue because in the Registry, you will run into keys that are access-protected and would raise ugly “Access Denied” errors. All errors are suppressed that way.
Searching for Values
Since Registry values are not interpreted as separate items but rather are added to keys as so-called ItemProperties, you cannot use Get-ChildItem to search for Registry values. You can search for values indirectly, though. Here is some code that finds all Registry keys that have at least one value with the keyword “PowerShell”:
PS> Get-ChildItem HKCU:, HKLM: -Recurse -ea 0 | Where-Object { $_.GetValueNames() | >> Where-Object { $_ -like '*PowerShell*' } }
If you want to find all keys that have a value with the keyword in its data, try this:
PS> Get-ChildItem HKCU:, HKLM: -Recurse -ea 0 | Where-Object { $key = $_ $_.GetValueNames() | >> ForEach-Object { $key.GetValue($_) } | Where-Object { $_ -like '*PowerShell*' } }
Reading One Registry Value
If you need to read a specific Registry value in a Registry key, use Get-ItemProperty. This example reads the registered owner:
PS> Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion' -Name RegisteredOwner RegisteredOwner : Tim Telbert PSPath : Registry::HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersion PSParentPath : Registry::HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NT PSChildName : CurrentVersion PSDrive : HKLM PSProvider : Registry
Unfortunately, the Registry provider adds a number of additional properties so you don’t get back the value alone. Add another Select-Object to really get back only the content of the value you are after:
PS> Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion' -Name RegisteredOwner | >> Select-Object -ExpandProperty RegisteredOwner Tim Telbert
Reading Multiple Registry Values
Maybe you’d like to read more than one Registry value. Registry keys can hold an unlimited number of values. The code is not much different from before. Simply replace the single Registry value name with a comma-separated list, and again use Select-Object to focus only on those. Since this time you are reading multiple properties, use -Property instead of –ExpandProperty parameter.
PS> Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion' ` >> -Name ProductName, EditionID, CSDVersion, RegisteredOwner | >> Select-Object -Property ProductName, EditionID, CSDVersion, RegisteredOwner >> ProductName EditionID CSDVersion RegisteredOwner ----------- --------- ---------- --------------- Windows 7 Ultimate Ultimate Service Pack 1 Tim Telbert
Or, a little simpler:
PS> Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion' | >> Select-Object -Property ProductName, EditionID, CSDVersion, RegisteredOwner >> ProductName EditionID CSDVersion RegisteredOwner ----------- --------- ---------- --------------- Windows 7 Ultimate Ultimate Service Pack 1 Tim Telbert
Reading Multiple Keys and Values
Yet maybe you want to read values not just from one Registry key but rather a whole bunch of them. In HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstall, you find a lot of keys, one for each installed software product. If you wanted to get a list of all software installed on your machine, you could read all of these keys and display some values from them.
That again is just a minor adjustment to the previous code because Get-ItemProperty supports wildcards. Have a look:
PS> Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindowsCurrentVersionUninstall*' | >> Select-Object -Property DisplayName, DisplayVersion, UninstallString DisplayName DisplayVersion UninstallString ----------- -------------- --------------- 0.8.2.232 Microsoft IntelliPoint 8.1 8.15.406.0 msiexec.exe /I {3ED4AD... Microsoft Security Esse... 2.1.1116.0 C:Program FilesMicro... NVIDIA Drivers 1.9 C:Windowssystem32nv... WinImage "C:Program FilesWinI... Microsoft Antimalware 3.0.8402.2 MsiExec.exe /X{05BFB06... Windows XP Mode 1.3.7600.16422 MsiExec.exe /X{1374CC6... Windows Home Server-Con... 6.0.3436.0 MsiExec.exe /I{21E4979... Idera PowerShellPlus Pr... 4.0.2703.2 MsiExec.exe /I{7a71c8a... Intel(R) PROSet/Wireles... 13.01.1000 (...)
Voilá, you get a list of installed software. Some of the lines are empty, though. This occurs when a key does not have the value you are looking for.
To remove empty entries, simply add Where-Object like this:
PS> Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindowsCurrentVersionUninstall*' | >> Select-Object -Property DisplayName, DisplayVersion, UninstallString | >> Where-Object { $_.DisplayName -ne $null }
Creating Registry Keys
Since Registry keys are treated like files or folders in the file system, you can create and delete them accordingly. To create new keys, either use historic aliases like md or mkdir, or use the underlying cmdlet directly:
PS> New-Item HKCU:SoftwareNewKey1 Hive: Registry::HKEY_CURRENT_USERSoftware Name Property ---- -------- NewKey1 PS> md HKCU:SoftwareNewKey2 Hive: Registry::HKEY_CURRENT_USERSoftware Name Property ---- -------- NewKey2
If a key name includes blank characters, enclose the path in quotation marks. The parent key has to exist.
To create a new key with a default value, use New-Item and specify the value and its data type:
PS> New-Item HKCU:SoftwareNewKey3 -Value 'Default Value Text' -Type String Hive: Registry::HKEY_CURRENT_USERSoftware Name Property ---- -------- NewKey3 (default) : Default Value Text
Deleting Registry Keys
To delete a key, use the historic aliases from the file system that you would use to delete a folder, or use the underlying cmdlet Remove-Item directly:
PS> Remove-Item HKCU:SoftwareTest1 Del HKCU:SoftwareTest2 Del HKCU:SoftwareTest3
This process needs to be manually confirmed if the key you are about to remove contains other keys:
Del HKCU:SoftwareKeyWithSubKeys Confirm The item at "HKCU:SoftwareKeyWithSubKeys" has children and the Recurse parameter was not specified. if you continue, all children will be removed with the item. Are you sure you want to continue? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
Use the –Recurse parameter to delete such keys without manual confirmation:
Del "HKCU:SoftwareFirst key" -Recurse
Creating Values
Each Registry key can have an unlimited number of values. Earlier in this chapter, you learned how to read these values. Values are called “ItemProperties”, so they belong to an “Item”, the Registry key.
To add new values to a Registry key, either use New-ItemProperty or Set-ItemProperty. New-ItemProperty cannot overwrite an existing value and returns the newly created value in its object form. Set-ItemProperty is more easy going. If the value does not yet exist, it will be created, else changed. Set-ItemProperty does not return any object.
Here are some lines of code that first create a Registry key and then add a number of values with different data types:
PS> New-Item HKCU:SoftwareTestKey4 PS> Set-ItemProperty HKCU:SoftwareTestKey4 -Name Name -Value 'Smith' PS> Set-ItemProperty HKCU:SoftwareTestKey4 -Name ID -Value 12 -Type DWORD PS> Set-ItemProperty HKCU:SoftwareTestKey4 -Name Path -Value '%WINDIR%' -Type ExpandString PS> Set-ItemProperty HKCU:SoftwareTestKey4 -Name Notes -Value 'First Note','Second Note' ` >> -Type MultiString >> PS> Set-ItemProperty HKCU:SoftwareTestKey4 -Name DigitalInfo -Value 4,8,12,200,90 -Type Binary PS> Get-ItemProperty HKCU:SoftwareTestKey4 Name : Smith ID : 12 Path : C:Windows Notes : {First Note, Second Note} DigitalInfo : {4, 8, 12, 200...} PSPath : Registry::HKEY_CURRENT_USERSoftwareTestKey4 PSParentPath : Registry::HKEY_CURRENT_USERSoftware PSChildName : TestKey4 PSDrive : HKCU PSProvider : Registry
If you wanted to set the keys’ default value, use ‘(default)’ as value name.
ItemType | Description | DataType |
String | A string | REG_SZ |
ExpandString | A string with environment variables that are resolved when invoked | REG_EXPAND_SZ |
Binary | Binary values | REG_BINARY |
DWord | Numeric values | REG_DWORD |
MultiString | Text of several lines | REG_MULTI_SZ |
QWord | 64-bit numeric values | REG_QWORD |
Use Remove-ItemProperty to remove a value. This line deletes the value Name value that you created in the previous example:
Remove-ItemProperty HKCU:SoftwareTestkey4 Name
Clear-ItemProperty clears the content of a value, but not the value itself.
Be sure to delete your test key once you are done playing:
Remove-Item HKCU:SoftwareTestkey4 -Recurse
Securing Registry Keys
Registry keys (and its values) can be secured with Access Control Lists (ACLs) in pretty much the same way the NTFS file system manages access permissions to files and folders. Likewise, you can use Get-Acl to show current permissions of a key:
md HKCU:SoftwareTestkey4 Get-Acl HKCU:SoftwareTestkey Path Owner Access ---- ----- ------ Microsoft.PowerShell.CoreRegistr... TobiasWeltne-PCTobias Weltner TobiasWeltne-PCTobias Weltner A...
To apply new security settings to a key, you need to know the different access rights that can be assigned to a key. Here is how you get a list of these rights:
PS> [System.Enum]::GetNames([System.Security.AccessControl.RegistryRights]) QueryValues SetValue CreateSubKey EnumerateSubKeys Notify CreateLink Delete ReadPermissions WriteKey ExecuteKey ReadKey ChangePermissions TakeOwnership FullControl
Taking Ownership
Always make sure that you are the “owner” of the key before modifying Registry key access permissions. Only owners can recover from lock-out situations, so if you set permissions wrong, you may not be able to undo the changes unless you are the owner of the key.
This is how to take ownership of a Registry key (provided your current access permissions allow you to take ownership. You may want to run these examples in a PowerShell console with full privileges):
$acl = Get-Acl HKCU:SoftwareTestkey $acl.Owner scriptinternalsTobiasWeltner $me = [System.Security.Principal.NTAccount]"$env:userdomain$env:username" $acl.SetOwner($me)
Setting New Access Permissions
The next step is to assign new permissions to the key. Let’s exclude the group “Everyone” from making changes to this key:
$acl = Get-Acl HKCU:SoftwareTestkey $person = [System.Security.Principal.NTAccount]"Everyone" $access = [System.Security.AccessControl.RegistryRights]"WriteKey" $inheritance = [System.Security.AccessControl.InheritanceFlags]"None" $propagation = [System.Security.AccessControl.PropagationFlags]"None" $type = [System.Security.AccessControl.AccessControlType]"Deny" $rule = New-Object System.Security.AccessControl.RegistryAccessRule(` $person,$access,$inheritance,$propagation,$type) $acl.AddAccessRule($rule) Set-Acl HKCU:SoftwareTestkey $acl
The modifications immediately take effect.Try creating new subkeys in the Registry editor or from within PowerShell, and you’ll get an error message:
md HKCU:SoftwareTestkeysubkey New-Item : Requested Registry access is not allowed. At line:1 char:34 + param([string[]]$paths) New-Item <<<< -type directory -path $paths
Why does the restriction applies to you as an administrator? Aren’t you supposed to have full access? No, restrictions always have priority over permissions, and because everyone is a member of the Everyone group, the restriction applies to you as well. This illustrates that you should be extremely careful applying restrictions. A better approach is to assign permissions only.
Removing an Access Rule
The new rule for Everyone was a complete waste of time after all because it applied to everyone, effectively excluding everyone from the key. So, how do you go about removing a rule? You can use RemoveAccessRule() to remove a particular rule, and RemoveAccessRuleAll() to remove all rules of the same type (permission or restriction) for the user named in the specified rule. ModifyAccessRule() changes an existing rule, and PurgeAccessRules() removes all rules for a certain user.
To remove the rule that was just inserted, proceed as follows:
$acl = Get-Acl HKCU:SoftwareTestkey $person = [System.Security.Principal.NTAccount]"Everyone" $access = [System.Security.AccessControl.RegistryRights]"WriteKey" $inheritance = [System.Security.AccessControl.InheritanceFlags]"None" $propagation = [System.Security.AccessControl.PropagationFlags]"None" $type = [System.Security.AccessControl.AccessControlType]"Deny" $rule = New-Object System.Security.AccessControl.RegistryAccessRule(` $person,$access,$inheritance,$propagation,$type) $acl.RemoveAccessRule($rule) Set-Acl HKCU:SoftwareTestkey $acl -Force
However, removing your access rule may not be as straightforward because you have effectively locked yourself out. Since you no longer have modification rights to the key, you are no longer allowed to modify the keys’ security settings as well.
You can overrule this only if you take ownership of the key: Open the Registry editor, navigate to the key, and by right-clicking and then selecting Permissions open the security dialog box and manually remove the entry for Everyone.
You’ve just seen how relatively easy it is to lock yourself out. Be careful with restriction rules.
Controlling Access to Sub-Keys
In the next example, you use permission rules rather than restriction rules. The task: create a key where only administrators can make changes. Everyone else should just be allowed to read the key.
md HKCU:SoftwareTestkey2 $acl = Get-Acl HKCU:SoftwareTestkey2 # Admins may do everything: $person = [System.Security.Principal.NTAccount]”Administrators” $access = [System.Security.AccessControl.RegistryRights]"FullControl" $inheritance = [System.Security.AccessControl.InheritanceFlags]"None" $propagation = [System.Security.AccessControl.PropagationFlags]"None" $type = [System.Security.AccessControl.AccessControlType]"Allow" $rule = New-Object System.Security.AccessControl.RegistryAccessRule(` $person,$access,$inheritance,$propagation,$type) $acl.ResetAccessRule($rule) # Everyone may only read and create subkeys: $person = [System.Security.Principal.NTAccount]"Everyone" $access = [System.Security.AccessControl.RegistryRights]"ReadKey" $inheritance = [System.Security.AccessControl.InheritanceFlags]"None" $propagation = [System.Security.AccessControl.PropagationFlags]"None" $type = [System.Security.AccessControl.AccessControlType]"Allow" $rule = New-Object System.Security.AccessControl.RegistryAccessRule(` $person,$access,$inheritance,$propagation,$type) $acl.ResetAccessRule($rule) Set-Acl HKCU:SoftwareTestkey2 $acl
Note that in this case the new rules were not entered by using AddAccessRule() but by ResetAccessRule(). This results in removal of all existing permissions for respective users. Still, the result isn’t right because regular users could still create subkeys and write values:
md hkcu:softwareTestkey2Subkey Hive: Microsoft.PowerShell.CoreRegistry::HKEY_CURRENT_USERsoftwareTestkey2 SKC VC Name Property --- -- ---- -------- 0 0 Subkey {} Set-ItemProperty HKCU:SoftwareTestkey2 Value1 "Here is text"
Revealing Inheritance
Look at the current permissions of the key to figure out why your permissions did not work the way you planned:
(Get-Acl HKCU:SoftwareTestkey2).Access | Format-Table -Wrap RegistryRights AccessControlType IdentityReference IsInherited InheritanceFlags PropagationFlags -------------- ----------------- ----------------- ----------- ---------------- ---------------- ReadKey Allow Everyone False None None FullControl Allow BUILT-inAdmi False None None nistrators FullControl Allow TobiasWeltne-PCT True ContainerInherit, None obias Weltner ObjectInherit FullControl Allow NT AUTHORITYSYST True ContainerInherit, None EM ObjectInherit FullControl Allow BUILT-inAdmi True ContainerInherit, None nistrators ObjectInherit ReadKey Allow NT AUTHORITYREST True ContainerInherit, None RICTED ACCESS ObjectInherit
The key includes more permissions than what you assigned to it. It gets these additional permissions by inheritance from parent keys. If you want to turn off inheritance, use SetAccessRuleProtection():
$acl = Get-Acl HKCU:SoftwareTestkey2 $acl.SetAccessRuleProtection($true, $false) Set-Acl HKCU:SoftwareTestkey2 $acl
Now, when you look at the permissions again, the key now contains only the permissions you explicitly set. It no longer inherits any permissions from parent keys:
RegistryRights AccessControlType IdentityReference IsInherited InheritanceFlags PropagationFlags -------------- ----------------- ----------------- ----------- ---------------- ---------------- ReadKey Allow Everyone False None None FullControl Allow BUILT-inAdmistrators False None None
Controlling Your Own Inheritance
Inheritance is a sword that cuts both ways. You have just turned off the inheritance of permissions from parent keys, but will your own newly set permissions be propagated to subkeys? Not by default. If you want to pass on your permissions to subdirectories, change the setting for propagation, too. Here are all steps required to secure the key:
del HKCU:SoftwareTestkey2 md HKCU:SoftwareTestkey2 $acl = Get-Acl HKCU:SoftwareTestkey2 # Admins may do anything: $person = [System.Security.Principal.NTAccount]”Administrators” $access = [System.Security.AccessControl.RegistryRights]"FullControl" $inheritance = [System.Security.AccessControl.InheritanceFlags]"ObjectInherit,ContainerInherit" $propagation = [System.Security.AccessControl.PropagationFlags]"None" $type = [System.Security.AccessControl.AccessControlType]"Allow" $rule = New-Object System.Security.AccessControl.RegistryAccessRule(` $person,$access,$inheritance,$propagation,$type) $acl.ResetAccessRule($rule) # Everyone may only read and create subkeys: $person = [System.Security.Principal.NTAccount]"Everyone" $access = [System.Security.AccessControl.RegistryRights]"ReadKey" $inheritance = [System.Security.AccessControl.InheritanceFlags]"ObjectInherit,ContainerInherit" $propagation = [System.Security.AccessControl.PropagationFlags]"None" $type = [System.Security.AccessControl.AccessControlType]"Allow" $rule = New-Object System.Security.AccessControl.RegistryAccessRule(` $person,$access,$inheritance,$propagation,$type) $acl.ResetAccessRule($rule) Set-Acl HKCU:SoftwareTestkey2 $acl