Creating a registry key with path components via PowerShell - windows

For a legacy application, I need to create a registry key with a name in the format c:/foo/bar/baz. (Note: forward slashes, not backslashes.) To be clear: that is a single key's name, with forward slashes, that otherwise looks like a Windows path. Because I need to script this against lots of servers, PowerShell seems like a great option.
The problem is that I cannot figure out how to create a key in that format via PowerShell. New-Item -Path HKLM:\SOFTWARE\Some\Key -Name 'c:/foo/bar/baz' errors out with PowerShell thinking I'm using / as a path separator and failing to find the path HKLM:\Software\Some\Key\c:\foo\bar, which does indeed not exist (and shouldn't). I can't find any other way to (ab)use New-Item to get what I want.
Is there something I'm missing, or should I give up and just generate and load a registry dump the old-fashioned way?

You need to do two things. First you need to get a writable RegistryKey object, otherwise you can't modify anything anyway. Second, use the CreateSubKey method on the RegistryKey object directly.
$writable = $true
$key = (get-item HKLM:\).OpenSubKey("SOFTWARE", $writable).CreateSubKey("C:/test")
$key.SetValue("Item 1", "Value 1")
After you create the key you use the resulting object to add values to it.

Related

How do I find DOMAIN\accountname$ of a remote AD-joined computer?

I want to store a remote computer's account name in a variable in the DOMAIN\Accountname format (preferably DOMAIN\Accountname$. I know the DNS name and samaccountname of the computer, and I want to run the script on a domain-joined computer (not a domain controller).
I cannot find any simple one-line approach to get the account name in that format. I can manually construct the string by concatenating the NETBIOS domain name with computer name (samaccountname), but I was assuming there is an easier and more robust way of doing this.
So is there any built-in approach of getting the computer name in the DOMAIN\Accountname$ format without having to manually constructing the string? I assume that's common task.
You can also look at the environmental variables. For this question, I would do the following...
$strUserAndDomain = ((Get-Content env:userdomain) + "\" + (Get-Content env:username))
Then you can user the value of $strUserAndDomain whenever you want.

How do you find the correct verb names to use with FolderItem.InvokeVerb?

How does one find the exact verbs to be used with the Windows API function FolderItem.InvokeVerb? The documentation says, "It must be one of the values returned by the item's FolderItemVerb.Name property." However, this does not seem to be true.
Using a folder as an example, if you run this on Windows 10 (using PowerShell):
$Shell = New-Object -ComObject 'Shell.Application'
$Shell.NameSpace('C:\Windows').Self.Verbs()
you will get a list that looks like this:
Application Parent Name
----------- ------ ----
&Open
Pin to Quick access
Scan with Microsoft Defender...
... and so on.
Those Names are what you get in an Explorer context menu, but they do not work with InvokeVerb. For some of them, such as &Open, all you have to do is remove the &. For others, such as Pin to Quick access, the actual verb that works is altogether different (pintohome). How can one reliably find these "actual" verbs for an arbitrary item?
I have found that the verbs that do work with InvokeVerb correspond to the sub-keys that you can find in the Registry under HKCR\<class name>\shell. However, even knowing that does not make things simple. I have found some verbs before by searching HKCR for the string returned by FolderItemVerb.Name, but that doesn't work if the string is localized. If you happen to know the name of the class, you could look there directly. (Using the folder example, pintohome is one of the keys under HKCR\Folder\shell.) However, when it is localized, there is nothing there that directly indicates this is the verb you are looking for, so you have to try it to find out. And, if you are inside some special shell folder or namespace extension, you might not know what class name(s) to even go looking for.

How to migrate registry entries with PowerShell with Get-Item : Set-Item and ExportTo-CliXml

I am trying to export selective registry entries, preferences and configurations for various software applications, and them import them on to a new machine.
Get-ChildItem Registry::HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\OneNote -Recurse | Export-Clixml -Depth 3 -Path OneNote.xml
And then reverse this process on another machine at a different time using
Import-CliXml -Path OneNote.xml | Set-Item
This doesn't seem to work but it's not obvious why. Conceptually it feels as though something like this should work.
Ideally the next step would be to be able to get keys, filter them and store them all in one file and then restore them cleanly on another machine.
This can be done with regedit, but I'm curious as to how this is done with PowerShell.
Rather than creating the keys if they don't exist and setting their values the Import-CliXml command creates values under default property names in the keys that correspond to the paths of the key. For example:
On the destination machine, a target key such as:
HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\OneNote\OpenNoteBooks
will now contain a default item which has the value:
"HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\OneNote\OpenNoteBooks"
rather than the expected properties from the source key.
For context, at a basic level, what I wish to do may be accomplished by:
reg export HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\OneNote OneNote.reg
To create a registry file containing the keys an values, then.
reg import OneNote.reg
On the target machine to load them. Obviously this is easy for a simple "dump and restore" operation, however it is less flexible if one wishes to process they keys using some logic first.
There's a couple of reasons why this won't work as expected.
Firstly in the Set-Item documentation notes section it states:
In the Registry drives, HKLM: and HKCU:, Set-Item changes the data in the (Default) value of a registry key. To create and change the names of registry keys, use New-Item and Rename-Item. To change the names and data in registry values, use New-ItemProperty, Set-ItemProperty, and Rename-ItemProperty.
So right off the mark we're destined for this not working as you'd intuitively think.
Secondly if you look at the output from Import-CliXml -Path OneNote.xml, there's no registry value type information provided e.g. DWORD, QWORD etc, therefore any tool using this as input won't know how to construct a key's values properly because there's no type hinting.
You're better off sticking to the good old reg.exe tool. It's well proven and predictable in its behaviour. Also it's not too hard to parse a .reg file if you need to tweak some values along the way.

Is there a list for known CLSIDs of the windows registry?

In the windows registry reside many CLSID values (in HKEY_CLASSES_ROOT\CLSID) such as {16d51579-a30b-4c8b-a276-0ff4dc41e755}, many of which may belong to widely known or even built-in applications or libraries. Is there a list or database that contains a mapping of these?
Some usages would be, to present a more meaningful name in a registry viewer along with the key, or checking whether a particular application is present (or was present and not anymore) but has left some keys in the registry.
You should not rely on this mapping.
If you need to go from ProgID to CLSID or the other way around, you can do it by calling ProgIDFromCLSID or CLSIDFromProgID APIs.
It's in the registry. You could try:
Get-ItemProperty -Path "HKLM:\SOFTWARE\Classes\CLSID\*" `
|select PSChildName,`(default`) |ft -auto *
HKEY_CLASSES_ROOT is an alias for HKEY_LOCAL_MACHINE\SOFTWARE\Classes. There're other words stored in various key values under each CLSID, so you could get cleverer with the PowerShell, but this is a start.

read known file extensions / types from the registry

I want to present the user with a list of known file extensions for him to pick. I know that these are stored in the Registry under HKEY_CLASSES_ROOT usually like this:
.txt -> (default)="txtfile"
where txtfile then contains the information about associated programs etc.
Unfortunately that place in the registry also stores lots of other keys, like the file types (e.g. txtfile) and entries like
CAPICOM.Certificates (whatever that is)
How do I determine which of the entries are file extensions? Or is there a different way to get these extensions like an API function?
(I don't think it matters, but I am using Delphi for the program.)
There is no guarantee that every keys preceded by a dot in HKEY_CLASSES_ROOT is intended for file association, but every file association requires creation of a key preceded by a dot. See MSDN on File Types topic.
AFAIK, the method I describe here conforms with how the Windows Set File Associations feature works to get a list of all known file types. It was based on my former observation when I delved into this subject.
To achieve that, you'll need to do intricate steps as follows:
Enumerating every keys preceded by a dot . , you can use RegQueryInfoKey() and RegEnumKeyEx() for this purpose.
In every keys preceded by a dot, look at the default value data:
a. If the default value is not empty, this is enough indication that the "preceding dot key" is intended for file association in all Windows NT version, then try to open the key name as mentioned by the value data, just says TheKeyNameMentioned.
a1) If there is subkeys shell\open\command under TheKeyNameMentioned, then test the existence of the path pointed by the default value of this key; if the path exists, there is a default application associated with the extension; if the path doesn't exists, the default application is unknown. To get the file extension description, look at the default value of TheKeyNameMentioned. To get the program description, first, test whether the following key contain a value-name equal to the EXE file path, that is HKCR\Local Settings\Software\Microsoft\Windows\Shell\MuiCache. If it is there, then look at the value data to get the file description; if it is not there, use GetFileVersionInfo() directly to get the file description.
a2) If there is no subkeys shell\open\command under TheKeyNameMentioned, then the default application is unknown. To get the file extension description, look at the default value of TheKeyNameMentioned.
b. On Windows Vista and later, when the point [a] fails, you need additional check. If the default value is empty, test whether the key has a subkey named OpenWithProgIDs.
If OpenWithProgIDs subkey exists, use RegEnumValue() to find the first encountered value name that meets the criteria, that is, the name of the value name must point to an existing key (just says TheKeyNameMentioned.) with the same name as the value name. If TheKeyNameMentioned exists, this is enough indication that the "preceding dot key" is intended for file association. Read point a1 and a2 for the next steps.
If OpenWithProgIDs subkey doesn't exist, the default application is unknown. To get the file extension description, look at the default value of TheKeyNameMentioned.
Hope that helps. :-)
For a command-line alternative, the assoc command-line program included in Windows shows registered file extensions.
c:\> assoc
.3g2=VLC.3g2
.3gp=VLC.3gp
.3gp2=VLC.3gp2
.3gpp=VLC.3gpp
...
I'm not sure which verb this looks for. Open perhaps? I'm also not sure which extensions will appear in this list. Perhaps the extensions of files that can open from the command line.
To then find out which executable is mapped to each file type, the ftype command will tell:
c:\> ftype VLC.3g2
VLC.3g2="c:\vlc.exe" --started-from-file "%1"
IMHO - all those registry subkeys starting with the dot (.) - are for file extensions.
For instance in your case .txt stands for the "txt" extension, whereas txtfile doesn't start with the dot.
I don't know the details, but it seems you could use the IQueryAssociations interface.

Resources