How to refer to HKEY_CLASSES_ROOT in PowerShell? - powershell

New-Item -Path "HKCR:\Directory\Background\shell\customname" -Force
I've been doing the same thing for HKCU and KHLM but when I try HKCR I get errors in PowerShell. how am I supposed to do it for HKEY_CLASSES_ROOT?
I searched for a solution but couldn't find any.

Okay I figured out on my own,
checked Get-PSDrive
and saw the only registry aliases available by default on Windows/PowerShell are
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
so, what I did, following this, was to add a new alias for HKEY_CLASSES_ROOT that is called HKCR
New-PSDrive -Name "HKCR" -PSProvider Registry -Root "HKEY_CLASSES_ROOT"

Defining a custom drive whose root is HKEY_CLASSES_ROOT, as shown in your own answer, is definitely an option, especially for repeated use.
Ad hoc, you can alternatively use the Registry:: provider prefix directly with native registry paths:
New-Item -Path 'Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\customname' -Force
Note:
The Registry part of the prefix is the provider name, as shown in Get-PSProvider's output.
Hypothetically, multiple providers with the same name could be registered, in which case you can prefix the name with the implementing module name for disambiguation; in the case of the registry provider, this module-qualified prefix is Microsoft.PowerShell.Core\Registry::[1] However, it's fair to assume that no third-party providers will choose a name that conflicts with the providers that ship with PowerShell, so Registry:: (or registry::, case doesn't matter), should do.
Note that the module-qualified provider name does show up in the prefix of the .PSPath property that provider items, such as reported by Get-Item and Get-ChildItem, are decorated with, e.g.:
PS> (Get-Item HKCU:\Console).PSPath
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Console
[1] Note that the Core part of the name does not refer to the PowerShell (Core) edition; it simply denotes a module that is at the core of either edition.

Related

Alternative to test-path, using credential, to hosts on a different domain, with wildcard in folder path

I'm trying to copy a file to a specific folder on one of n hosts (hostA, hostB etc.), but i don't know the full path of the folder.
If I don't use a credential (which I have to do) I can e.g.
test-path -path \\hostA\d$\*\targetFolder ...and hit D:\blah\targetFolder
I could use the credential with new-psdrive, but then I can't map to a wildcarded path. I could also invoke-command, but then I'd have to work out a way to get the file from the sourceHost...
This is for a TFS/AzureDevops pipe.
Using New-PSDrive, map a (non-persistent, PS-only) drive to the admin share \\hostA\d$ itself, and then use that drive for wildcard-based path testing:
# Define a PS-only RemoteD: drive that maps to \\hostA\d$,
# using the specified credentials.
New-PSDrive RemoteD FileSystem \\hostA\d$ -Credential (Get-Credential)
# Use paths based on RemoteD: for wildcard-based testing.
Test-Path RemoteD:\*\targetFolder

How do I access another user's registry hive using Powershell?

How can I use Powershell to load and alter another user's registry hive, without having to shell out to another Powershell process run as the target user?
You would need to load their registry.
reg load HKU\<username> C:\Users\<username>\ntuser.dat
You can find more detailed information on this here though:
https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/manipulating-registry-user-hive
While the accepted answer helped me solve my issue, I've since learned how to do this with pure PowerShell using the Registry provider:
# Mount the HKEY_USERS hive
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
# Change location to the user's registry (organized by SID)
cd HKU:/$userSid
This works by mounting the HKEY_USERS hive as a new PSDrive named HKU, which other user hives are accessible under a sub-key named after the target user's SID. You can determine the SID in one of two ways (assuming you don't already know the SID ahead of time):
Local account:
$userSid = ( Get-LocalUser NAME ).SID.Value
Domain Account[1]:
$userSid = ( Get-ADUser NAME ).SID.Value
[1] Get-ADUser is available with the RSAT Tools AD cmdlets, which must be installed as a prerequisite for this command to work.

How to check the existence of registry key in HKEY_CURRENT_CONFIG

How to check the presence of registry key named "Mon12345678" under HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\VIDEO\ {CD73268F-4662-42EC-80F6-182E03DE7017}\0000 regsitry hive? We can validate till HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\VIDEO directly and then run random check under "Video" until we get the sub registry key called "Mon12345678"?
I tried the below code snippet
Test-Path -Path "HKCC:\System\CurrentControlSet\Control\VIDEO\ *\Mon12345678" -ErrorAction SilentlyContinue
But the result shows false even though the sub registry hive is found. How to tackle the problem?
The HKEY_CURRENT_CONFIG registry hive is not predefined as a PowerShell drive name HKCC:, so unless you defined such a drive yourself with New-PSDrive, it won't exist.
(Get-PSDrive -psProvider Registry).Name shows you which registry-based drives are defined; by default, it is only HKLM: (HKEY_LOCAL_MACHINE) and HKCU: (HKEY_CURRENT_CONFIG).
Short of defining your own HKCC: drive, you can prefix a registry hive name with registry:: (the provider name) in order to target a hive; e.g.:
# Test the existence of a key known to exist in the HKEY_CURRENT_CONFIG registry hive,
# using provider prefix 'registry::'
PS> Test-Path -Path 'registry::HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control'
True
Therefore, to test the existence of a subkey named Mon12345678 across all subkeys (*) of key HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\VIDEO, use the following:
$keyPath = 'registry::HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\VIDEO'
Test-Path -Path "$keyPath\*\Mon12345678"
If, by contrast, you want to test the existence of a value (a property of a registry key) named Mon12345678, you cannot use a single Test-Path call, because Test-Path can only operate on key paths, not paths ending in value names.
See this answer for background information.
$keyPath = 'registry::HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\VIDEO'
[bool] (Get-ItemProperty -EA ignore "$keyPath\*" 'Mon12345678')
Did you try?
To search part of the registry, use the following syntax:
REG Query HKxx\subkey [/D|/K|/V] /F "search_pattern" /S [/E] [/C]
To search an entire registry hive, just omit the subkey:
REG Query HKxx [/D|/K|/V] /F "search_pattern" /S [/E] [/C]
Source of the solution and full post can be found here

Is it possible to create namespaced environment variables in powershell? (like $custom:JSenv)

I was wondering if I can create a PSDrive like Env: for my project specific environment variables, like $custom:JSenv, $custom:root etc. instead of populating the Env: PSDrive.
I tried using New-PSDrive -Name custom -PSProvider Environment. I expexceted to see the custom: drive. However, in the actual output nothing changed.
Is creating aEnvironment PSDrive the right way to achieve the purpose?
The New-PSDrive cmdlet requires a Root parameter. I was unable to replicate your problem:
PS /> $null = New-PSDrive -Name custom -PSProvider Environment -Root ''
PS /> Get-Item -Path custom:
# => environment variables
All this really does, however, is give you a different method of calling the Env: drive since they use the same provider and the provider does not have a concept of scope.
No: To get what you want, you'd have to implement your own PowerShell [drive] provider that also implements the IContentCmdletProvider interface, because $<drive>:<path> (or ${<drive>:<path>}) is syntactic sugar - called namespace notation - for the following command:
Get-Content -Path <drive>:<path>
See the bottom section for more.
As for what you tried:
While it is possible to define a custom drive based on an existing provider, that drive will invariably reflect that provider's items, without any ability to define your own.
In other words:
New-PSDrive -Name custom -PSProvider Environment -Root ''
will simply make drive custom: an alias of the env: drive.
While you could define your custom entries as environment variables, they would show in addition to the preexisting ones.
Implementing a custom PowerShell drive [provider]:
Writing your own [drive] provider requires compiled code, so you cannot implement custom drives in PowerShell itself.
As of Windows PowerShell v5.1 / PowerShell Core 6.1.0, implementing providers is nontrivial, but simplifying that is being considered for a future PowerShell Core version.
However, there are third-party helper modules that greatly simplify the process and do allow you to implement custom drives in PowerShell code.
Note: I haven't verified that your specific use case can be implemented.
Simplex: PS Gallery link - source code and documentation - easy-to-use DSL, but not all features are exposed.
SHiPS: PS Gallery link - source code and documentation - more complex, but more fully-featured.

Differentiate Registry Key from Value paths

Is there an equivalent of [System.IO.DirectoryInfo] and [System.IO.FileInfo] for differentiating Registry Keys from Values? I want to evaluate a path and log for the user what the final target of the path is.
So far, this is what I have, and it's kinda ugly.
$path = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\SomeJunkHereToTestFailure'
try {
if ((Get-Item -path:$path -errorAction:stop).GetType().name -eq 'RegistryKey') {
'Registry Key'
}
} catch {
try {
if ((Get-ItemProperty -path:(Split-Path $path -parent) -name:(Split-Path $path -leaf) -errorAction:stop).GetType().name -eq 'PSCustomObject') {
'Registry Value'
}
} catch {
'What is this?'
}
}
Hoping for something more elegant and also consistently correct.
Ok, so after digging around for awhile, canonically speaking, this:
HKEY_LOCAL_MACHINE\SOFTWARE\Path\To\Something
Is always a path to a key.
Look at reg.exe query. Look at how Get-ItemProperty works. Notice in regedit.exe that you can copy key names, but not a "path" to a specific value. Look at how .reg files are written. Look at Registry.GetValue() and Registry.SetValue(). Or Registry.LocalMachine.OpenSubKey().GetValue(). Microsoft clearly thinks that registry paths always point to keys.
If you have software that's using HKEY_LOCAL_MACHINE\SOFTWARE\Path\To\A\Value to refer to a value in the registry, then they're not using standard registry paths that Windows understands.
That's why you run these the way you do:
reg.exe query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v "ProductName"
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name "ProductName"
[Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion').GetValue('ProductName')
[Microsoft.Win32.Registry]::GetValue('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion','ProductName', $false)
That last one is nice because it doesn't error. If it can't find the value, it returns the third argument. It does, however, require the long hive name at the start as far as I can tell.
So, Test-Path -Container can tell you if it's a key. Microsoft.Win32.Registry.GetValue() can tell you if it's a value... with some manipulation.
Original answer (THIS DOES NOT WORK):
Use Test-Path:
$path = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\SomeJunkHereToTestFailure'
# Is it a Key?
Test-Path -Path $path -PathType Container
# Is it a Value?
Test-Path -Path $path -PathType Leaf
As for...
Is there an equivalent of [System.IO.DirectoryInfo] and [System.IO.FileInfo]
Not that I've ever seen or heard of to date.
However, take a look at the below to see if they can fit your need or you may be ableto tweak them to accomplish your goals.
Powershell Registry Cmdlets utilizing the .Net StdRegProv
This Script is a collection of PowerShell cmdlets that can be run in either x86 or x64 processes to handle common registry operations utilizing alternate registry views. This script is compatible with PowerShell versions 2.0 or later.
Download RegistryCmdlets.ps1
https://gallery.technet.microsoft.com/Powershell-Registry-19689888
Or of course is back to writing your own as you are posting here:
See also as you look at your effor to cultivate your own:
Registry Cmdlets: First Steps with CDXML
In this post, I’ll show you how to get started with CDXML. Before that, though, I’d better explain CDXML...
Cmdlet definition XML (CDXML) is a way to create a Windows PowerShell module from a WMI class by using the cmdlets-over-objects technology that was introduced in Windows PowerShell 3.0. As usual, it’s always easier to show you an example:
https://blogs.technet.microsoft.com/heyscriptingguy/2015/02/03/registry-cmdlets-first-steps-with-cdxml/
Registry Cmdlets: Working with the Registry
The bad news is that there aren’t any cmdlets for working with the registry. There’s a Registry provider, which means you can use the Item and ItemProperty cmdlets to manage the local registry—but there aren’t any specific registry cmdlets associated with the provider.
The good news is that we can adopt the approach that many teams at Microsoft have taken and create our own by using cmdlet definition XML (CDXML). A Common Information Model (CIM) class is wrapped in some fairly simple XML and published as a Windows PowerShell module. If you look in the Modules folder on a computer running Windows 8.1, Windows 8, Windows Server 2012 R2, or Windows Server 2012, you will find many files with a CDXML extension:
https://blogs.technet.microsoft.com/heyscriptingguy/2015/02/02/registry-cmdlets-working-with-the-registry
There's a problem with the premise of your question: Ending a registry path - composed of key names - with a value name is not supported - at least neither with the .NET Framework registry types nor with reg.exe nor with PowerShell's registry drive provider.
For instance, to refer to value WindowSize of registry key
HKEY_CURRENT_USER\Control Panel\Colors, you CANNOT use the following path:
# NOT a valid path, because 'WindowSize' is a *value*, not a *key*.
HKEY_CURRENT_USER\Control Panel\Colors\WindowSize
Even if you yourself decide to support such paths in your functions (and there may be utilities that similarly accept that), note that they are ambiguous, because a given registry key can have both a value and a subkey with a given name.
With that limitation in mind, your own code from your question is probably the best you can do (though it can be streamlined a little).
Is there an equivalent of [System.IO.DirectoryInfo] and [System.IO.FileInfo] for differentiating Registry Keys from Values?
The equivalent of [System.IO.DirectoryInfo] (filesystem directory) is [Microsoft.Win32.RegistryKey] (registry key).
By contrast, [System.IO.FileInfo] (filesystem file) has NO counterpart for registry values:
Registry values are represented as properties of registry items (keys) in the PS registry drive provider rather than items in their own right, and such properties are (awkwardly) represented as non-specific [System.Management.Automation.PSCustomObject] instances.
Similarly, registry values have no type representation in the .NET Framework (you only request their data by name).
Fundamentally, in terms of object models, registry values do not correspond to filesystem files; read on for more.
Optional reading: how the registry object model maps onto PowerShell drive-provider concepts in contrast with the filesystem object model
It comes down to this: in the filesystem, a directory's files are child items, whereas in the registry, a key's values are properties of that key.
Only container-type children are represented as child items in both providers (sub-directories in the case of the filesystem provider, sub-keys in case of the registry provider).
In the context of the FileSystem provider, files and directories are both (sub-types of) items.
Files are represented as [System.IO.FileInfo] instances, and directories as [System.IO.DirectoryInfo].
A leaf item is invariably of subtype file, whereas a container (interior) item is invariably of subtype directory (folder).
Therefore, you can use Test-Path -PathType Leaf to test for a file and Test-Path -PathType Container to test for a directory.
In the context of the Registry provider, it is only keys that are items.
Keys are represented as [Microsoft.Win32.RegistryKey] instances.
Since all keys are (potentially) containers, the registry provider has no concept of a leaf item.
Therefore, use of Test-Path -PathType <type> with a registry path is pointless,
because with -PathType Leaf the result is always $False, and with -PathType Container it is always $True.
By contrast, registry values are represented as properties (the equivalent of what the last-modified date is to a filesystem item, for instance).
Use the *-ItemProperty* cmdlets to read and write registry values.