You can navigate the Windows registry just as you would the file system because PowerShell treats the file system concept discussed in Chapter 15 as a prototype for all hierarchical information systems.
Topics Covered:
You can navigate the Windows registry just as you would the file system because PowerShell treats the file system concept discussed in Chapter 15 as a prototype for all hierarchical information systems:
Cd HKCU:Dir
SKC VC Name Property
--- -- ---- --------
2 0 AppEvents {}
17 1 Console {CurrentPage}
15 0 Control Panel {}
0 3 Environment {PATH, TEMP, TMP}
4 0 EUDC {}
1 6 Identities {Identity Ordinal, Migrated7, Last Username, Last User ID...}
3 0 Keyboard Layout {}
0 0 Network {}
4 0 Printers {}
55 1 Software {(default)}
2 0 System {}
0 1 SessionInformation {ProgramCount}
1 8 Volatile Environment {LOGONSERVER, USERDOMAIN, USERNAME, USERPROFILE...}
The keys in the registry correspond to directories in the file system. However, key values don't quite behave analogously to files in the file system. Instead, they are managed as properties of keys and are displayed in the Property column. Table 16.1 lists all the commands that you require for access to the registry.
| Command |
Description |
| Dir, Get-ChildItem |
Lists the contents of a key |
| Cd, Set-Location |
Changes current directory (key) |
| HKCU:, HKLM: |
Predefined drives for the two most important roots of the registry |
| Get-ItemProperty |
Reads the value of a key |
| Set-ItemProperty |
Modifies the value of a key |
| New-ItemProperty |
Creates a new value for a key |
| Clear-ItemProperty |
Deletes the value contents of a key |
| Remove-ItemProperty |
Removes the value of a key |
| New-Item, md |
Creates a new key |
| Remove-Item, Del |
Deletes a key |
| Test-Path |
Verifies whether a key exists |
Table 16.1: The most important commands for working with the registry
The registry stores nearly all central Windows settings. That's why it's an important location for reading information and modifying the Windows configuration. Incorrect entries or erroneous deletion and modification represent a serious risk and can damage Windows or make it unbootable.
You'll find the most important settings in the HKEY_LOCAL_MACHINE root key, which Windows protects by requiring administrator rights to make changes there.
"Provider": Locations Outside the File System
PowerShell has a modular structure and uses what are called "providers," Which are responsible for a particular information store. In the last chapter, you used a file system provider so you'll need a registry provider if you want to access the Windows registry instead of the file system. In other respects, everything works the way it did in the last chapter. You use the same commands in the registry that you use in the file system.
Available Providers
Get-PSProvider retrieves a list of all installed providers. Your list could be longer than in the following example, because providers can be added later on. For example, PowerShell doesn't have its own provider for Active Directory.
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 names the drives that are managed by respective providers. As you see, the registry provider mounts 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. Try this out:
Cd HKCU:
Dir
Hive: Microsoft.PowerShell.Core\Registry::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,...
From this location, you could navigate through the "subdirectory" in exactly the same way you did through a genuine file system. The same special characters apply here as well. The symbol for the root directory "~" is unknown in the registry and generates an error.
While the other providers do not have a role in this chapter since we will be focusing on the registry, they are listed in Table 16.2 for reference.
| 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 |
Table 16.2: Default providers
Creating Drives
Registry provider provides access to the registry. You address them through drives. If you would like to see which drives are already used by registry provider, use Get-PSDrive with -PSProvider:
Get-PSDrive -PSProvider Registry
Name Provider Root
---- -------- ----
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Here it might have struck your attention that the registry consists of more roots than just these two.
Figure 16.1: Roots in the registry
The root HKEY_CLASSES_ROOT is actually not an independent root but corresponds to HKEY_LOCAL_MACHINE\SOFTWARE\Classes. That means you could use New-PSDrive to create a new drive that has its starting point there:
New-PSDrive -name HKCR -PSProvider registry -root HKLM:\SOFTWARE\Classes
Dir HKCR:
You already have access to this registry branch. In fact, you could get direct access to any of the roots listed in Figure 16.1.
Remove-PSDrive HKCR
New-PSDrive -name HKCR -PSProvider registry -root HKEY_CLASSES_ROOT
Dir HKCR:
You could create any additional drives you like when you're working extensively in a specific registry area:
New-PSDrive job1 registry `
"HKLM:\Software\Microsoft\Windows NT\CurrentVersion"
Dir job1:
Hive: Microsoft.PowerShell.Core\Registry::
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion
SKC VC Name Property
--- -- ---- --------
1 0 Accessibility {}
1 3 AeDebug {UserDebuggerHotKey, Auto, Debugger}
0 10 APITracing {LogFileDirectory, InstalledManifests,
LogApiNamesOnly, ...
4 1 AppCompatFlags {ApphelpUIExe}
1 0 ASR {}
0 174 Compatibility {_3DPC, _BNOTES, _LNOTES, ACAD...}
0 1 Compatibility32 {winword}
3 0 Console {}
1 2 CorruptedFileRecovery {RunCount, TraceLevel}
0 3 DefaultProductKey {ProductId, DigitalProductId,
DigitalProductId4}
2 1 DiskDiagnostics {DFDCollectorInvokeTimes}
(...)
Searching the Registry
Using Dir, you can search the registry just like you did the file system in Chapter 15. Simply use the new drives that the registry provider uses. The drive HKCU: provides an overview of the contents of the HKEY_CURRENT_USER root key:
Cd HKCU:
Dir
Redirect the result to Format-List if you'd rather list contents below each other:
Dir | Format-List
Dir | Format-List Name
Dir | Format-List *
Recursive Search
The registry provider doesn't support any filters so you may not use the Dir parameter -filter when you search the registry. However, the parameters -recurse, -include, and -exclude are supported; you used them in the last chapter to search the file system recursively. This works in the registry as well. For example, if you wanted to know the location of registry entries that include the word "PowerShell", you could search using:
Dir HKCU:, HKLM: -recurse -include *PowerShell*
This instruction searches the HKEY_CURRENT_USER root first and then the HKEY_LOCAL_MACHINE root. It finds all the keys that contain the word "PowerShell." Because there could be a large number of these, search for registry keys that have the word "PowerShell" in their names without using any wildcard characters. Search operations of this kind usually generate error messages because when you search, segments of the registry are read to which you may have no access authorization. To filter the messages out of the result, use the parameter -ErrorAction and set its value to SilentlyContinue:
Dir HKCU:, HKLM: -recurse -include PowerShell -ErrorAction SilentlyContinue
Hive: Microsoft.PowerShell.Core\Registry::
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell
SKC VC Name Property
--- -- ---- --------
1 1 PowerShell {(default)}
Hive: Microsoft.PowerShell.Core\Registry::
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Drive\shell
SKC VC Name Property
--- -- ---- --------
1 1 PowerShell {(default)}
Hive: Microsoft.PowerShell.Core\Registry::
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
SKC VC Name Property
--- -- ---- --------
1 0 PowerShell {}
Individual Registry Keys
Every element that Dir retrieves corresponds to a registry key (Microsoft.Win32.Registry object) that includes these important properties:
$key = Dir HKCU: | Select-Object -first 1
$key.GetType().FullName
Microsoft.Win32.RegistryKey
$key | Get-Member -memberType *Property
TypeName: Microsoft.Win32.RegistryKey
Name MemberType Definition
---- ---------- ----------
Property NoteProperty System.String[] Property=System.String[]
PSChildName NoteProperty System.String PSChildName=AppEvents
PSDrive NoteProperty System.Management.Automation.PSDriveInfo PSDrive=HKCU
PSIsContainer NoteProperty System.Boolean PSIsContainer=True
PSParentPath NoteProperty System.String PSParentPath=Microsoft.PowerShell.Core\Registry::HKEY_...
PSPath NoteProperty System.String PSPath=Microsoft.PowerShell.Core\Registry::HKEY_CURREN...
PSProvider NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft.Power...
Name Property System.String Name {get;}
SubKeyCount Property System.Int32 SubKeyCount {get;}
ValueCount Property System.Int32 ValueCount {get;}
| Property |
Description |
| Name |
Path of a key as displayed in the registry editor |
| Property |
Array including names of values stored in a key |
| PSChildName |
Name of current key |
| PSDrive |
Registry root for a key |
| PSParentPath |
Parent key |
| PSPath |
PowerShell path of a key. Use Dir to view contents of a key under this path |
| PSProvider |
Name of provider: Registry |
| SubKeyCount (SKC) |
Number of keys stored in a key |
| ValueCount (VC) |
Number of values stored in a key |
| PSIsContainer |
Always True |
Table 16.3: Properties of a Microsoft.Win32.Registry object (registry key)
How PowerShell Addresses Registry Keys
Let's take a closer look at the allocation of individual properties to a real key. In the example, the HKLM:\Software\Microsoft\PowerShell\1 key is used and in Figure 16.2 shown as displayed in the registry editor. This is the registry location where PowerShell stores its internal settings.
Figure 16.2: PowerShell settings in the registry editor
Use Get-Item from within PowerShell to access the key:
$key = Get-Item HKLM:\Software\Microsoft\PowerShell\1
$key.Name
HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell\1
$key | Format-List ps*
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell\1
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell
PSChildName : 1
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
PSIsContainer : True
As expected, the Name property retrieves the complete name of the key. Of greater interest are the properties that begin with "PS" and which PowerShell subsequently adds. They split the path of the registry key into various segments.
Values of Keys
Values of keys are in Figure 16.2 in the right column of the registry editor. There are three values. PowerShell reports just two values:
$key.ValueCount
2
One value seems to be missing. You'll see which values PowerShell records if you look more closely at the Property property:
$key.Property
Install
PID
These names correspond to the names of values in Figure 16.2. The value (Default) is missing, and rightly so, because as you can see in Figure 16.2, the default value is empty. The registry editor, Regedit, reports: (value not set).
If you want to retrieve the contents of values, use Get-ItemProperty and pass the path from the PSPath property:
Get-ItemProperty $key.PSPath
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell\1
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell
PSChildName : 1
PSProvider : Microsoft.PowerShell.Core\Registry
Install : 1
PID : 89383-100-0001260-04309
In this way, all the values of the registry key are automatically retrieved and displayed. As you see, along with usual properties, the value contains other properties added by PowerShell. You should access their corresponding properties if you want to retrieve only some particular values:
$values = Get-ItemProperty $key.PSPath
$values.Install
1
$values.PID
89383-100-0001260-04309
If you want to retrieve all the values of a key, without including the properties added by PowerShell, you could proceed as follows:
$key = Get-Item HKLM:\Software\Microsoft\PowerShell\1
$values = Get-ItemProperty $key.PSPath
foreach ($value in $key.Property) { $value + "=" + $values.$value }
Install=1
PID=89383-100-0001260-04309
Once you have navigated through the registry to the key whose values you want to examine, you can list values using a second method:
Cd HKLM:\Software\Microsoft\PowerShell\1
(Get-ItemProperty .).PID
89383-100-0001260-04309
Here "." was used to pass Get-ItemProperty to the relative path of the registry key. For this to work, you should use Cd first to switch to the key so your current directory must correspond to the registry key that you are interested in:
Get-ItemProperty
You should use Dir if you'd like to output the values of several keys. The result of Dir can be passed along in the pipeline to ForEach-Object. In this way, you could evaluate all the subkeys of a key one after the other and, for example, access the respective values of the key. The next line lists all the subkeys of Uninstall and then reports the values DisplayName and MoreInfoURL. This provides you with a rough list of installed programs:
Dir hklm:\software\microsoft\windows\currentversion\uninstall |
ForEach-Object { Write-Host -ForegroundColor Yellow "Installed Products:" }{
$values = Get-ItemProperty $_.PSPath;
"{0:-30} {1:20}" -f $values.DisplayName, $values.MoreInfoURL
}{Write-Host -ForegroundColor Yellow "Finished!"}
Subkey of a Key
In Figure 16.2, you can see in the left column that this key contains four subkeys. PowerShell also reports four subkeys:
$key.SubKeyCount
4
Dir retrieves the names of subkeys. To accomplish this, pass to Dir the PowerShell path of the key that you find in the PSPath property:
Dir $key.PSPath
Hive: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell\1
SKC VC Name Property
--- -- ---- --------
0 1 1033 {Install}
0 5 PowerShellEngine {ApplicationBase, RuntimeVersion, ConsoleHostAssemblyNam...
1 0 PowerShellSnapIns {}
1 0 ShellIds {}
Creating and Deleting Keys and Values
Use New-item or the md function to create new keys. Keys in the registry behave like directories in the file system.
New-Item -type Directory HKCU:\Software\Test1
Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software
SKC VC Name Property
--- -- ---- --------
0 0 Test1 {}
md HKCU:\Software\Test2
Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software
SKC VC Name Property
--- -- ---- --------
0 0 Test2 {}
But the two statements create a key that is completely empty: its default value is not defined. If you want to define the default value of a key, use New-Item instead of md, and specify one of the values in Table 16.4 as -itemType. Set the value of the default entry using the -value parameter:
New-Item -itemType String HKCU:\Software\Test3 -value "A default value"
Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software
SKC VC Name Property
--- -- ---- --------
0 1 Test3 {(default)}
If you want to delete a key, proceed the way you did in the file system and use Remove-Item or the short Del:
Remove-Item HKCU:\Software\Test1
Del HKCU:\Software\Test2
Del HKCU:\Software\Test3
| 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 |
Table 16.4: Permitted ItemTypes in the registry
Deleting Keys with Contents
If a key name includes blank characters, enclose the path in quotation marks. Unfortunately, you can't create more than one key in one step the way you could in the file system. The parent key has to exist. That's why this statement has caused an error; the parent key, First key, was missing:
md "HKCU:\Software\First key\Second key"
New-Item : The registry key at the specified path does not exist.
At line:1 char:34
+ param([string[]]$paths); New-Item <<<< -type directory -path $paths
You have to split up the statement into several steps:
md "HKCU:\Software\First key" | Out-Null
md "HKCU:\Software\First key\Second key" | Out-Null
If you try to delete the First key now, you'll be queried, like you were in the file system, because the key includes subkeys and isn't empty:
Del "HKCU:\Software\First key"
Confirm
The item at "HKCU:\Software\First key" 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 explicitly delete keys that have contents:
Del "HKCU:\Software\First key" -recurse
Setting, Changing, and Deleting Values of Keys
The registry editor distinguishes between keys and values in a well-structured way: keys are in the left column with values in the right. The keys correspond to directories in the file system, and values correspond to files in the directory. If you want to create a new key, use md as you did above or, even better, New-Item, and then use New-Item and the -itemType and -value parameters to assign a default value to your new key.
New-Item HKCU:\Software\Testkey -itemType String -value "A test value" |
Out-Null
Adding New Values
Unfortunately, the file system analogy won't help you if you want to add additional values to a key, because normally you would use Set-Content to create new files inside a directory. But the registry provider is not the right tool:
Set-Content HKCU:\Software\Testkey\Value1 "Contents"
Set-Content : Cannot use interface. The IcontentCmdletProvider
interface is not implemented by this provider.
At line:1 char:12
+ Set-Content <<<< HKCU:\Software\Testkey\Value1 "Contents"
Instead, use Set-ItemProperty to add new values to a key:
Set-ItemProperty HKCU:\Software\Testkey -name "Entry1" -value "123"
The values that you add in this way are automatically registered as REG_SZ values in the registry, that is, as a string. If you want to use another data type, use New-ItemProperty and the -propertyType parameter. It accepts the types listed in Table 16.4:
if (!(Test-Path HKCU:\Software\Testkey)) { md HKCU:\Software\Testkey }
New-ItemProperty HKCU:\Software\Testkey -name "Entry2" `
-value "123" -propertyType dword
PSPath : Microsoft.PowerShell.Core\Registry::
HKEY_CURRENT_USER\Software\Testkey
PSParentPath : Microsoft.PowerShell.Core\Registry::
HKEY_CURRENT_USER\Software
PSChildName : Testkey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
Entry2 : 123
New-ItemProperty HKCU:\Software\Testkey Entry3 `
-value "Windows is in %windir%" -propertyType string
New-ItemProperty HKCU:\Software\Testkey Entry4 `
-value "Windows is in %windir%" -propertyType expandstring
New-ItemProperty HKCU:\Software\Testkey Entry5 `
-value "One","Two","Three" -propertyType multistring
New-ItemProperty HKCU:\Software\Testkey Entry6 `
-value 1,2,3,4,5 -propertyType binary
New-ItemProperty HKCU:\Software\Testkey Entry7 `
-value 100 -propertyType dword
New-ItemProperty HKCU:\Software\Testkey Entry8 `
-value 100 -propertyType qword
The registry editor shows the result in Figure 16.3.
Figure 16.3: Writing various data types in the registry
If you have the Microsoft.Win32.Registry object of a key available, you can add and read out additional values easily by using the SetValue() and GetValue() methods. When you use md or New-Item to create a new key, this object is what you will get as a result, and all you have to do is to save it so that you can add additional values to it in the next step:
$key = md HKCU:\Software\Test2
$key.SetValue("Entry1", "123")
$key.SetValue("Entry2", "123", "Dword")
$key.SetValue("Entry3", "%windir%", "ExpandString")
$key.GetValue("Entry3")
C:\Windows
The SetValue() method works only for keys that you created again using New-Item or md because PowerShell will open only those keys that have write permissions. Existing keys that you get by using Get-Item will be opened in read-only mode. You can't use SetValue() to change values in this instance. Instead, use Set-ItemProperty(see below).
Reading Values
Reading registry values is the only area in which the rules are not particularly clear. Normally, you would assume that values created using Set-ItemProperty could be read using Get-ItemProperty. Unfortunately, that's only partly true because when you use Get-ItemProperty, PowerShell retrieves not only the value you're looking for but also an object with extraneous PowerShell properties:
Get-ItemProperty HKCU:\Software\Testkey Entry3
PSPath : Microsoft.PowerShell.Core\Registry::
HKEY_CURRENT_USER\Software\Testkey
PSParentPath : Microsoft.PowerShell.Core\Registry::
HKEY_CURRENT_USER\Software
PSChildName : Testkey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
Entry3 : Windows is in %windir%
You'll get the information you want only when you explicitly retrieve the right property from the object that That is, Get-ItemProperty retrieves the name of the value that interests you. An incidental consequence is that the difference between the file types REG_SZ and REG_EXPAND_SZ becomes clear.
(Get-ItemProperty HKCU:\Software\Testkey Entry3).Entry3
Windows is in %windir%
(Get-ItemProperty HKCU:\Software\Testkey Entry4).Entry4
Windows is in C:\Windows
Because Entry3 was stored as a REG_SZ value, you will get the precise string value that was stored there when you read it. Entry4 is of the REG_EXPAND_SZ type. Windows automatically resolves environment variables contained in the string when they are retrieved. That's why the Windows directory was retrieved, instead of the environment variable.
Perhaps you're wondering why in the last examples the name of the value that you want to read out occurred twice:
(Get-ItemProperty HKCU:\Software\Testkey Entry3).Entry3
In this example, Get-ItemProperty retrieves the Entry3 value. However, you've seen that what Get-ItemProperty retrieves is an object that has several properties. You can enclose your invocation in parentheses so that your subexpression will be evaluated first since you're only interested in the Entry3 value.,. Finally, get the property you want from the returned object, Entry3.
The following statement seems to do exactly that or at least it returns the same result:
(Get-ItemProperty HKCU:\Software\Testkey).Entry3
Here, however, you should instruct Get-ItemProperty to get all the values of the key, which will be far more than you'll actually need.
Deleting Values
Use Remove-ItemProperty to remove a value. The next instruction deletes the Entry5 value that you created in the previous example:
Remove-ItemProperty HKCU:\Software\Testkey Entry5
Clear-ItemProperty deletes only the contents of a value, but not the value itself.
Default Entry
The default entry of the key plays a special role. It is always shown in the right column under the name (default). But this entry is actually unnamed: it is the only value of a key that has no name.
The default value of a key doesn't have to be defined. If the value isn't set, the registry editor will display "value not set." Normally, you would set a value when using New-Item and the -value parameter to create new keys. But you can also directly address the value by the name (default):
md HKCU:\Software\Test3
Get-ItemProperty HKCU:\Software\Test3 "(default)"
Get-ItemProperty : Property (default) does not exist
at path HKEY_CURRENT_USER\Software\Test3.
At line:1 char:17
+ Get-ItemProperty <<<< HKCU:\Software\Test3 "(default)"
New-ItemProperty HKCU:\Software\Test3 "(default)" -value "A value"
Get-ItemProperty HKCU:\Software\Test3 "(default)"
PSPath : Microsoft.PowerShell.Core\Registry::
HKEY_CURRENT_USER\Software\Test3
PSParentPath : Microsoft.PowerShell.Core\Registry::
HKEY_CURRENT_USER\Software
PSChildName : Test3
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
(default) : A value
(Get-ItemProperty HKCU:\Software\Test3 "(default)")."(default)"
A value
Clear-ItemProperty HKCU:\Software\Test3 "(default)"
Be sure to delete your test key in the registry asthe registry is no place to leave irrelevant entries behind:
Del HKCU:\Software\Testkey -recurse
Del HKCU:\Software\Test2 -recurse
Del HKCU:\Software\Test3 -recurse
Example: Extending the Context Menu
Entries in the registry can have widely varying consequences. Among others, this is where Windows sets the entries for the Explorer context menu. In the next example, you will, as a test, add three new commands to the context menu for PowerShell scripts: "Execute and Leave Open," "Execute and Close," and "Edit".
Executing and Editing PowerShell Scripts
To do this, you have to know first how to launch PowerShell scripts outside the PowerShell console. It's easy. First, create a little example script:
Cd $home
'"Hello world!"' | Out-File test.ps1
Inside the PowerShell console, invoke the script by typing its relative or absolute path:
.\test.ps1
But how to invoke PowerShell scripts outside the PowerShell console? Start powershell.exe and specify the -NoExit option so that the console will stay open after the script has been processed, allowing you to see and evaluate the results of the script. After the -Command parameter, specify the command line that PowerShell is supposed to execute. Enclose the path in single quotation marks and put the call operator in front of it because you don't know whether the path of the script contains blank characters. Put this command inside double quotation marks:
powershell.exe -NoExit -Command "& '.\test.ps1'"
If you would like to edit a script, the command is much simpler: invoke the editor of your choice and pass the script to it:
notepad.exe ".\test.ps1"
The context menu extension will be entered into the registry next. This requires administrator privileges:
New-PSDrive -Name HKCR -PSProvider registry -root HKEY_CLASSES_ROOT | Out-Null
$keyname = (Get-ItemProperty HKCR:\.ps1)."(default)"
New-Item ("HKCR:\$keyname\shell\execute1") -value `
'Execute and Leave Open' -type String
New-Item ("HKCR:\$keyname\shell\execute1\command") -value `
"powershell.exe -NoExit -Command `"& '%L'`"" -type String
New-Item ("HKCR:\$keyname\shell\execute2") -value `
'Execute and Close' -type String
New-Item ("HKCR:\$keyname\shell\execute2\command") -value `
"powershell.exe -Command `"& '%L'`"" -type String
New-Item ("HKCR:\$keyname\shell\editnotepad") -value `
'Edit with Notepad' -type String
New-Item ("HKCR:\$keyname\shell\editnotepad\command") -value `
'notepad.exe "%L"' -type String
if (Test-Path ("HKCR:\$keyname\DefaultIcon")) {
Del ("HKCR:\$keyname\DefaultIcon") }
$icon = '%windir%\System32\WindowsPowerShell\v1.0\powershell.exe,0'
New-Item ("HKCR:\$keyname\DefaultIcon") -value $icon -type ExpandString
Permissions in the Registry
In Chapter 15, you learned in detail how to control permissions for files and directories. The same mechanisms also work in the registry as you could use Get-Acl to show current permissions of a key:
md HKCU:\Software\Testkey
Get-Acl HKCU:\Software\Testkey
Path Owner Access
---- ----- ------
Microsoft.PowerShell.Core... TobiasWeltne-PC\Tobias Weltner TobiasWeltne-PC\Tobias Weltner A...
Because you manage permissions exactly the way you do in the file system, you should take another look at Chapter 15 and review the basics before assigning new permissions to a registry key.
The .NET classes that are required for permissions in the registry are a little different from the ones in the file system. Instead of a FilesystemAccessRule, you will need a RegistryAccessRule, and the fundamental difference between them is the diverging access rights that can be set in them. In a RegistryAccessRule, permissions do not correpond to the FilesystemRights enumeration, but to RegistryRights:
[System.Enum]::GetNames([System.Security.AccessControl.RegistryRights])
QueryValues
SetValue
CreateSubKey
EnumerateSubKeys
Notify
CreateLink
Delete
ReadPermissions
WriteKey
ExecuteKey
ReadKey
ChangePermissions
TakeOwnership
FullControl
Taking Ownership
Make sure that you are the "owner" of the key before modifying key permissions as a test. Only if you are the owner you will be able to undo possible mistakes. This is how to take ownership of a registry key (to the extent that your permissions allow it):
$acl = Get-Acl HKCU:\Software\Testkey
$acl.Owner
scriptinternals\TobiasWeltner
$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. The group "Everyone" is prohibited from making changes to this key:
$acl = Get-Acl HKCU:\Software\Testkeys
$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:\Software\Testkey $acl
The modifications immediately go into effect.Try creating new subkeys in the registry editor or from within PowerShell to check and you'll get an error message:
md HKCU:\Software\Testkey\subkey
New-Item : Requested registry access is not allowed.
At line:1 char:34
+ param([string[]]$paths); New-Item <<<< -type directory -path $paths
If you're asking yourself why the restriction also applies to you because as administrator you're supposed to have full access: restrictions always have priority over permissions, and because everyone is a member of the Everyone group, the restriction applies to you as well.
Removing an Access Rule
The new rule for Everyone was a complete waste of time and didn't stand the test. 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:\Software\Testkey
$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:\Software\Testkey $acl -force
However, removing your access rule may not work the way you expect because you have now locked yourself out. Because you no longer have the right to modify the key, that also applies to changes to your security settings. You can correct the problem only if you take ownership of the key. If this occurs, 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 easy it is to lock yourself out. Be especially careful when you work with the Everyone group, where, if at all possible, you should employ no restrictions because they often have far greater consequences than you would like.
Controlling Access to Subkeys
In the next example, you can do things better and use rules not on restrictions but on permissions. In the following test key, only administrators are supposed to be able to modify the values of the key. However, all others, may read the key:
md HKCU:\Software\Testkey2
$acl = Get-Acl HKCU:\Software\Testkey2
$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)
$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:\Software\Testkey2 $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. Nevertheless, the result still isn't right because normal users can still create subkeys in the key and write values:
md hkcu:\software\Testkey2\Subkey
Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\software\Testkey2
SKC VC Name Property
--- -- ---- --------
0 0 Subkey {}
Set-ItemProperty HKCU:\Software\Testkey2 Value1 "Here is text"
Revealing Inheritance
Look at the current permissions of the key: to determine why your permissions may not be working the way you planned:
(Get-Acl HKCU:\Software\Testkey2).Access | Format-Table -wrap
Registry Access IdentityReference IsInhe InheritanceFlags Propagat
Rights Control rited ionFlags
Type
-------- ------- ----------------- ------ ----------------- --------
ReadKey Allow Everyone False None None
FullCont Allow BUILT-IN\ False None None
rol Administrators
FullCont Allow TobiasWeltner-PC\ True ContainerInherit, None
rol Tobias Weltner ObjectInherit
FullCont Allow NT AUTHORITY\ True ContainerInherit, None
rol SYSTEM ObjectInherit
FullCont Allow BUILT-IN\ True ContainerInherit, None
rol Administrators ObjectInherit
ReadKey Allow NT AUTHORITY\ True ContainerInherit, None
RESTRICTED ACCESS ObjectInherit
The key includes many more permissions than what you assigned to it so it gets these additional permissions by inheritance from parent keys. If you want to turn off inheritance, use SetAccessRuleProtection():
$acl = Get-Acl HKCU:\Software\Testkey2
$acl.SetAccessRuleProtection($true, $false)
Set-Acl HKCU:\Software\Testkey2 $acl
Now, when you look at the permissions, the key will contain only the permissions that you explicitly set so it no longer inherits any permissions from parent keys:
(Get-Acl HKCU:\Software\Testkey2).Access | Format-Table -wrap
Registry Access IdentityReference IsInhe InheritanceFlags Propagat
Rights Control rited ionFlags
Type
-------- ------- ----------------- ------ ----------------- --------
ReadKey Allow Everyone False None None
FullCont Allow BUILT-IN\ False None None
rol Administrators
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 what about your own inheritance permissions? Launch a PowerShell console with administrator privileges so that you can create additional subkeys for your protected key:
md HKCU:\Software\Testkey2\Subkey1
md HKCU:\Software\Testkey2\Subkey1\Subkey2
Then take a look at the permissions for these new subkeys:
(Get-Acl HKCU:\Software\Testkey2\Subkey1\Subkey2).Access | Format-Table -wrap
Registry Access IdentityReference IsInhe InheritanceFlags Propagat
Rights Control rited ionFlags
Type
-------- ------- ----------------- ------ ----------------- --------
FullCont Allow NT AUTHORITY\ False None None
rol SYSTEM
FullCont Allow BUILT-IN\ False None None
rol Administrators
CreateLi Allow S-1-5-5-0-344927 False None None
nk, Read
Key
The result doesn't correspond to the access permissions that you set. The reason: you specified None as inheritance. If you want to pass on your permissions to subdirectories, change the setting:
del HKCU:\Software\Testkey2
md HKCU:\Software\Testkey2
$acl = Get-Acl HKCU:\Software\Testkey2
$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)
$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:\Software\Testkey2 $acl
Posted
Mar 30 2009, 08:07 AM
by
ps1