{"id":74211,"date":"2015-02-02T00:01:00","date_gmt":"2015-02-02T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2015\/02\/02\/registry-cmdlets-working-with-the-registry\/"},"modified":"2019-02-18T10:35:38","modified_gmt":"2019-02-18T17:35:38","slug":"registry-cmdlets-working-with-the-registry","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/registry-cmdlets-working-with-the-registry\/","title":{"rendered":"Registry Cmdlets: Working with the Registry"},"content":{"rendered":"<p><b style=\"font-size: 12px\">Summary<\/b><span style=\"font-size: 12px\">: Richard Siddaway investigates how to use CIM to manage the registry.<\/span>\nHonorary Scripting Guy, Richard Siddaway, here filling in for my good friend The Scripting Guy. Today, I&#8217;m starting a series about registry cmdlets by investigating how to work with the registry.\nThe bad news is that there aren\u2019t any cmdlets for working with the registry. There\u2019s a <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh847848.aspx\" target=\"_blank\">Registry provider<\/a>, which means you can use the <b>Item<\/b> and <b>ItemProperty<\/b> cmdlets to manage the local registry\u2014but there aren\u2019t any specific registry cmdlets associated with the provider.\nThe 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 <b>Modules<\/b> 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:<\/p>\n<p style=\"margin-left: 30px\">Get-ChildItem -Path C:WindowsSystem32WindowsPowerShellv1.0Modules -Filter *.CDXML -Recurse<\/p>\n<p>These files are a great resource for figuring out how CDXML should be constructed. Other useful resources include:<\/p>\n<ul>\n<li><a href=\"http:\/\/download.microsoft.com\/download\/D\/4\/5\/D450FBD4-8636-48FB-8788-B9C3514D9377\/Cmdlet%20Definition%20XML%20-%20Whitepaper.docx\" target=\"_blank\">Using cmdlet definition XML to create Windows PowerShell cmdlets<\/a> (whitepaper)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/jj542522(v=vs.85).aspx\" target=\"_blank\">Cmdlet definition XML<\/a> (useful examples on MSDN)<\/li>\n<\/ul>\n<p>By the end of this series, you will have a Registry module that will make working with the registry much easier, and you will have learned how to use CDXML so that you can create other modules based on your favorite CIM classes.\nFirst though, we should have a quick recap of using CIM to work with the registry.<\/p>\n<p style=\"margin-left: 30px\"><b>Note<\/b> Although there is a technical difference between CIM and WMI, I will be using them interchangeably, which seems to be common practice.<\/p>\n<p>The registry is accessed through the <b>StdRegProv<\/b> class. You can examine the class like this:<\/p>\n<p style=\"margin-left: 30px\">Get-CimClass -Namespace rootcimv2 -ClassName StdRegProv<\/p>\n<p style=\"margin-left: 30px\">\u00a0\u00a0NameSpace: ROOT\/cimv2<\/p>\n<p style=\"margin-left: 30px\">CimClassName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 CimClassMethods\u00a0\u00a0 CimClassProperties<\/p>\n<p style=\"margin-left: 30px\">&#8212;&#8212;&#8212;&#8212;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8212;&#8212;&#8212;&#8212;\u00a0\u00a0 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/p>\n<p style=\"margin-left: 30px\">StdRegProv\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {CreateKey, Delet&#8230; {}<\/p>\n<p>The class is also available in the rootdefault namespace. This is the only option if you are running Windows XP or Windows Server 2003. These versions are no longer supported, so we\u2019ll use the rootcimv2 namespace for the remainder of the series. If you want to check if the classes are the same, you can examine the rootdefault version like this:<\/p>\n<p style=\"margin-left: 30px\">Get-CimClass -Namespace rootdefault -ClassName StdRegProv<\/p>\n<p>When you look at the <b>StdRegProv<\/b> class, the first thing you notice is that it has no properties. The class provides methods only. To drill into the methods:<\/p>\n<p style=\"margin-left: 30px\">$class = Get-CimClass -Namespace rootcimv2 -ClassName StdRegProv<\/p>\n<p style=\"margin-left: 30px\">$class.CimClassMethods | select Name<\/p>\n<p style=\"margin-left: 30px\">Name<\/p>\n<p style=\"margin-left: 30px\">&#8212;-<\/p>\n<p style=\"margin-left: 30px\">CreateKey<\/p>\n<p style=\"margin-left: 30px\">DeleteKey<\/p>\n<p style=\"margin-left: 30px\">EnumKey<\/p>\n<p style=\"margin-left: 30px\">EnumValues<\/p>\n<p style=\"margin-left: 30px\">DeleteValue<\/p>\n<p style=\"margin-left: 30px\">SetDWORDValue<\/p>\n<p style=\"margin-left: 30px\">SetQWORDValue<\/p>\n<p style=\"margin-left: 30px\">GetDWORDValue<\/p>\n<p style=\"margin-left: 30px\">GetQWORDValue<\/p>\n<p style=\"margin-left: 30px\">SetStringValue<\/p>\n<p style=\"margin-left: 30px\">GetStringValue<\/p>\n<p style=\"margin-left: 30px\">SetMultiStringValue<\/p>\n<p style=\"margin-left: 30px\">GetMultiStringValue<\/p>\n<p style=\"margin-left: 30px\">SetExpandedStringValue<\/p>\n<p style=\"margin-left: 30px\">GetExpandedStringValue<\/p>\n<p style=\"margin-left: 30px\">SetBinaryValue<\/p>\n<p style=\"margin-left: 30px\">GetBinaryValue<\/p>\n<p style=\"margin-left: 30px\">CheckAccess<\/p>\n<p style=\"margin-left: 30px\">SetSecurityDescriptor<\/p>\n<p style=\"margin-left: 30px\">GetSecurityDescriptor<\/p>\n<p>As shown here, all the methods are static:<\/p>\n<p style=\"margin-left: 30px\">\u00a3&gt; $class.CimClassMethods[&#8220;GetSTRINGvalue&#8221;] | Format-List<\/p>\n<p style=\"margin-left: 30px\">Name\u00a0\u00a0 \u00a0: GetStringValue<\/p>\n<p style=\"margin-left: 30px\">ReturnType : UInt32<\/p>\n<p style=\"margin-left: 30px\">Parameters : {hDefKey, sSubKeyName, sValueName, sValue}<\/p>\n<p style=\"margin-left: 30px\">Qualifiers : {implemented, static}<\/p>\n<p>This means that you don\u2019t need an instance of the class to work with\u2014you can simply use the methods. The parameters for these methods are relatively straightforward:<\/p>\n<p style=\"margin-left: 30px\">\u00a3&gt; $class.CimClassMethods[&#8220;GetSTRINGvalue&#8221;].Parameters<\/p>\n<p style=\"margin-left: 30px\">Name \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 CimType Qualifiers<\/p>\n<p style=\"margin-left: 30px\">&#8212;-\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8212;- &#8212;&#8212;&#8212;-<\/p>\n<p style=\"margin-left: 30px\">hDefKey \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0UInt32 {ID, IN}<\/p>\n<p style=\"margin-left: 30px\">sSubKeyName \u00a0 \u00a0 \u00a0 \u00a0String {ID, IN}<\/p>\n<p style=\"margin-left: 30px\">sValueName \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0String {ID, in}<\/p>\n<p style=\"margin-left: 30px\">sValue \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0String {ID, out}<\/p>\n<p>This is where we meet the first nasty bit. The <b>hdefkey<\/b> parameter defines the registry hive you want to work with. It\u2019s an unsigned integer that can take the following values:<\/p>\n<p style=\"margin-left: 30px\">HKEY_CLASSES_ROOT = 2147483648 (0x80000000)<\/p>\n<p style=\"margin-left: 30px\">HKEY_CURRENT_USER = 2147483649 (0x80000001)<\/p>\n<p style=\"margin-left: 30px\">HKEY_LOCAL_MACHINE = 2147483650 (0x80000002)<\/p>\n<p style=\"margin-left: 30px\">HKEY_USERS = 2147483651 (0x80000003)<\/p>\n<p style=\"margin-left: 30px\">HKEY_CURRENT_CONFIG = 2147483653 (0x80000005)<\/p>\n<p style=\"margin-left: 30px\">HKEY_DYN_DATA = 2147483654 (0x80000006)<\/p>\n<p>This list shows the hive and the related unsigned integer as a decimal and hexadecimal number. I have found that it\u2019s easiest to define these values as variables. For instance, to work with the HKEY_LOCAL_MACHINE hive, use:<\/p>\n<p style=\"margin-left: 30px\">[uint32]$hklm = 2147483650<\/p>\n<p>Let\u2019s look at a little Windows PowerShell history for a moment&#8230;\nWhen Windows PowerShell 1.0 launched, it immediately gave us a way to work with WMI (<b>Get-WmiObject<\/b>). That was a huge step forward from using VBScript. Unfortunately, we couldn\u2019t use the <b>StdRegProv<\/b> class directly because of its static methods. The answer was to use the <b>[wmiclass]<\/b> type accelerator:<\/p>\n<p style=\"margin-left: 30px\">$reg = [wmiclass]&#8221;\\.rootcimv2:StdRegprov&#8221;<\/p>\n<p>Then you can use <b>Get-Member<\/b> like this:<\/p>\n<p style=\"margin-left: 30px\">$reg | Get-Member<\/p>\n<p>Now you&#8217;ll see an object from the System.Management.ManagementClass:<\/p>\n<p style=\"margin-left: 30px\">System.Management.ManagementClass#ROOTcimv2StdRegProv<\/p>\n<p>I tend to use variables for things like registry keys and values because it makes my code reusable. A couple of relatively safe values to use are:<\/p>\n<p style=\"margin-left: 30px\">$subkey = &#8220;SOFTWAREMicrosoftInternet Explorer&#8221;<\/p>\n<p style=\"margin-left: 30px\">$value = &#8220;Version&#8221;<\/p>\n<p>You can then call a method on the class:<\/p>\n<p style=\"margin-left: 30px\">$reg.GetSTRINGvalue($hklm, $subkey, $value)<\/p>\n<p>The important parts of the results are:<\/p>\n<p style=\"margin-left: 30px\">ReturnValue\u00a0\u00a0 : 0<\/p>\n<p style=\"margin-left: 30px\">sValue\u00a0\u00a0\u00a0\u00a0 \u00a0: 9.11.9600.17126<\/p>\n<p><b>ReturnValue<\/b> is the return code. A value of 0 in the <b>ReturnValue<\/b> is good. Anything else is bad, and could be very bad. Finding what the return code means can be difficult, but some information is available if you search WMI return values.\nThe <b>sValue<\/b> property holds the return value you want. You can access it directly by using standard techniques:<\/p>\n<p style=\"margin-left: 30px\">$reg.GetSTRINGvalue($hklm, $subkey, $value) | select -ExpandProperty sValue<\/p>\n<p>\u00a0 \u00a0 \u00a0\u2013or\u2013<\/p>\n<p style=\"margin-left: 30px\">($reg.GetSTRINGvalue($hklm, $subkey, $value)).sValue<\/p>\n<p>This technique is still valid and works with the latest versions of Windows PowerShell. However, working with the registry became much easier in Windows PowerShell\u00a02.0 when <b>Invoke-WmiMethod<\/b> joined the game. Our registry access code became:<\/p>\n<p style=\"margin-left: 30px\">Invoke-WmiMethod -Namespace rootcimv2 -Class StdRegProv -Name GetSTRINGvalue -ArgumentList $hklm, $subkey, $value<\/p>\n<p>However, life is never straightforward&#8230;a bit of a problem dropped into our laps. To explain, I need to create a registry key to work with. I can use the <b>$reg<\/b> object that I created earlier:<\/p>\n<p style=\"margin-left: 30px\">$newkey = &#8220;SOFTWAREHSGtest&#8221;<\/p>\n<p style=\"margin-left: 30px\">$reg.CreateKey($hklm, $newkey)<\/p>\n<p>And let\u2019s add a value:<\/p>\n<p style=\"margin-left: 30px\">$newname = &#8216;Date&#8217;<\/p>\n<p style=\"margin-left: 30px\">$newvalue = &#8216;June 2013&#8217;<\/p>\n<p style=\"margin-left: 30px\">$reg.SetSTRINGvalue($hklm, $newkey, $newname, $newvalue)<\/p>\n<p>And finally, let&#8217;s test that it\u2019s created correctly:<\/p>\n<p style=\"margin-left: 30px\">$reg.GetSTRINGvalue($hklm, $newkey, $newname)<\/p>\n<p>The truncated output shows:<\/p>\n<p style=\"margin-left: 30px\">ReturnValue\u00a0\u00a0\u00a0\u00a0\u00a0 : 0<\/p>\n<p style=\"margin-left: 30px\">sValue\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : June 2013<\/p>\n<p>Oops! This where I realize that I\u2019ve used the wrong data, so now I need to modify the data:<\/p>\n<p style=\"margin-left: 30px\">$newvalue = &#8216;June 2014&#8217;<\/p>\n<p>And for a change, I\u2019ll use <b>Invoke-WmiMethod<\/b>:\nInvoke-WmiMethod -Namespace rootcimv2 -Class StdRegProv -Name SetSTRINGvalue $hklm, $newkey, $newname, $newvalue\nA return code of 0 indicates that it worked. But let\u2019s assume I\u2019m a bit paranoid and I want to check the data:<\/p>\n<p style=\"margin-left: 30px\">$reg.GetSTRINGvalue($hklm, $newkey, $newname)<\/p>\n<p>What I get is:<\/p>\n<p style=\"margin-left: 30px\">ReturnValue\u00a0\u00a0 : 0<\/p>\n<p style=\"margin-left: 30px\">sValue\u00a0\u00a0\u00a0\u00a0 \u00a0: June 2013<\/p>\n<p>In reality, the value hasn\u2019t been changed. This isn\u2019t a Windows PowerShell issue. It&#8217;s related to the underlying .NET classes. It turns out that when you are using <b>Invoke-WmiMethod<\/b>, the order of the arguments matters. The cmdlet expects them in alphabetical order, not the order the documentation shows (which is the order that you\u2019d use if using the <b>[wmiclass]<\/b> approach).\nThis problem will be most noticeable if the arguments are different data types. You get a nice big juicy error message that states you have a type mismatch: code 2147749893. The quick way to check the correct order of arguments is to use <b>Get-CimClass<\/b>:<\/p>\n<p style=\"margin-left: 30px\">$class = Get-CimClass -Namespace rootcimv2 -ClassName StdRegProv<\/p>\n<p style=\"margin-left: 30px\">$class.CimClassMethods[&#8220;SetSTRINGvalue&#8221;].Parameters<\/p>\n<p>Examining the <b>Name<\/b> of the parameters shows this:<\/p>\n<p style=\"margin-left: 30px\">Name<\/p>\n<p style=\"margin-left: 30px\">&#8212;-<\/p>\n<p style=\"margin-left: 30px\">hDefKey<\/p>\n<p style=\"margin-left: 30px\">sSubKeyName<\/p>\n<p style=\"margin-left: 30px\">sValue<\/p>\n<p style=\"margin-left: 30px\">sValueName<\/p>\n<p style=\"margin-left: 30px\">Let\u2019s retry it in that order:<\/p>\n<p style=\"margin-left: 30px\">Invoke-WmiMethod -Namespace rootcimv2 -Class StdRegProv -Name SetSTRINGvalue $hklm, $newkey, $newvalue, $newname<\/p>\n<p style=\"margin-left: 30px\">$reg.GetSTRINGvalue($hklm, $newkey, $newname)<\/p>\n<p>And it works.\nOne way to avoid this confusion is to use the CIM cmdlets, which were introduced in Windows PowerShell\u00a03.0. The problem goes away because you have to give argument name and value pairs:\nTo set data:<\/p>\n<p style=\"margin-left: 30px\">$newvalue = \u2018June 2015\u2019<\/p>\n<p style=\"margin-left: 30px\">Invoke-CimMethod -Namespace rootcimv2 -ClassName StdRegProv -MethodName SetSTRINGvalue -Arguments @{hDefKey=$hklm; sSubKeyName=$newkey; sValueName=$newname; sValue=$newvalue}<\/p>\n<p>And to read data:<\/p>\n<p style=\"margin-left: 30px\">Invoke-CimMethod -Namespace rootcimv2 -ClassName StdRegProv -MethodName GetSTRINGvalue -Arguments @{hDefKey=$hklm; sSubKeyName=$newkey; sValueName=$newname}<\/p>\n<p>This still leaves us with a lot of typing. Wouldn\u2019t it be better if we could do this:<\/p>\n<p style=\"margin-left: 30px\">Set-RegistrySTRING -Hive HKLM -SubKey $newkey -ValueName $newname -Value &#8216;April 2015&#8217;<\/p>\n<p style=\"margin-left: 30px\">Get-RegistrySTRING -Hive HKLM -SubKey $newkey -ValueName $newname<\/p>\n<p>These are cmdlets from the module that I\u2019m going to show you how to create in the next few posts, but for now I need to clean up my registry:<\/p>\n<p style=\"margin-left: 30px\">Remove-RegistryKey -Hive HKLM -SubKey $newkey<\/p>\n<p>Bye for now. Next time, we\u2019ll start digging into how we can use CDXML to create registry cmdlets.<\/p>\n<p style=\"margin-left: 30px\"><strong>Biography<\/strong><\/p>\n<p style=\"margin-left: 30px\">Richard Siddaway is based out of the UK. He spends his time automating anything and everything, for Kelway, Ltd. A 7-year Windows PowerShell MVP, Richard is a prolific blogger, mainly about Windows PowerShell (see <a href=\"http:\/\/msmvps.com\/blogs\/richardsiddaway\/default.aspx\" target=\"_blank\">Richard Siddaway&#8217;s Blog<\/a>). Richard has been a director at PowerShell.org since the inception of that organization, and he is a frequent speaker at Windows PowerShell user groups and conferences. He has written a number of books: PowerShell in Practice, PowerShell and WMI, PowerShell in Depth (co-author), PowerShell Dive (co-editor), and Learn Active Directory Management in a Month of Lunches, which features lots of Windows PowerShell. All of the books are available from <a href=\"http:\/\/www.manning.com\/\" target=\"_blank\">Manning Publications<\/a>.<\/p>\n<p>We invite you to follow The Scripting Guys on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send an email to The Scripting Guys at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. Until then, remember eat your cmdlets every day with a dash of creativity.\n<b>Richard Siddaway, <\/b>Windows PowerShell MVP and Honorary Scripting Guy<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Richard Siddaway investigates how to use CIM to manage the registry. Honorary Scripting Guy, Richard Siddaway, here filling in for my good friend The Scripting Guy. Today, I&#8217;m starting a series about registry cmdlets by investigating how to work with the registry. The bad news is that there aren\u2019t any cmdlets for working with [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[385,26,189,45],"class_list":["post-74211","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-cim","tag-registry","tag-richard-siddaway","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Richard Siddaway investigates how to use CIM to manage the registry. Honorary Scripting Guy, Richard Siddaway, here filling in for my good friend The Scripting Guy. Today, I&#8217;m starting a series about registry cmdlets by investigating how to work with the registry. The bad news is that there aren\u2019t any cmdlets for working with [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/74211","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=74211"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/74211\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=74211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=74211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=74211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}